Skip to content

Commit 25a0b94

Browse files
authored
Remove #[ignore] tests and GUEST env var, improve test ergonomics (#1196)
* Make test_drop able to run concurrently Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Rename create_1000_sandboxes to create_200_sandboxes and make concurrent-safe Reduces thread count (20->10) and sandboxes per thread (50->20) so the test can run alongside other tests without exhausting system resources. Removes #[ignore] and the corresponding test-isolated entry in the Justfile. Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Allow execute_on_heap to execute concurrently Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Make test_trace_trace concurrent-safe Use Interest::sometimes() in TracingSubscriber to prevent the global interest cache from permanently caching Interest::never() when another thread's no-op subscriber registers callsites first. Add a warmup call + rebuild_interest_cache() to ensure callsites are properly registered before the real test run. Also removes the now-unused build_metadata_testing module and TestLogger dependency. Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Remove GUEST env var and refactor test helpers Replace the GUEST environment variable approach with explicit helper functions (with_rust_sandbox, with_c_sandbox, with_all_sandboxes, etc.) that make test intent clearer and remove runtime environment coupling. Each test now explicitly declares which guest(s) it needs. Tests that work with both guests use with_all_sandboxes to run against both Rust and C guests in a single test invocation, removing the need for separate test-integration runs per guest language. Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Move max_memory_sandbox test to layout module Move the test from integration tests into the layout module where it belongs, and rewrite it to test SandboxMemoryLayout::get_memory_size directly instead of going through UninitializedSandbox::new. Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> * Add error context to assert!(matches!()) and remove debug println in tests Adds descriptive error messages to pattern-matching assertions so test failures show the actual value. Removes println!("{:?}", res) calls that were only useful for manual debugging. Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --------- Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
1 parent f110930 commit 25a0b94

11 files changed

Lines changed: 884 additions & 902 deletions

File tree

Justfile

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -205,30 +205,27 @@ like-ci config=default-target hypervisor="kvm":
205205
just check-license-headers
206206

207207
# runs all tests
208-
test target=default-target features="": (test-unit target features) (test-isolated target features) (test-integration "rust" target features) (test-integration "c" target features) (test-doc target features)
208+
test target=default-target features="": (test-unit target features) (test-isolated target features) (test-integration target features) (test-doc target features)
209209

210210
# runs unit tests
211211
test-unit target=default-target features="":
212212
{{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --lib
213213

214214
# runs tests that requires being run separately, for example due to global state
215215
test-isolated target=default-target features="" :
216-
{{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::uninitialized::tests::test_trace_trace --exact --ignored
217216
{{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::uninitialized::tests::test_log_trace --exact --ignored
218-
{{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::initialized_multi_use::tests::create_1000_sandboxes --exact --ignored
219217
{{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- sandbox::outb::tests::test_log_outb_log --exact --ignored
220-
{{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- mem::shared_mem::tests::test_drop --exact --ignored
221218
{{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --test integration_test -- log_message --exact --ignored
222219
@# metrics tests
223220
{{ cargo-cmd }} test {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F function_call_metrics,init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} -p hyperlight-host --lib -- metrics::tests::test_metrics_are_emitted --exact
224-
# runs integration tests. Guest can either be "rust" or "c"
225-
test-integration guest target=default-target features="":
226-
@# run execute_on_heap test with feature "executable_heap" on and off
227-
{{if os() == "windows" { "$env:" } else { "" } }}GUEST="{{guest}}"{{if os() == "windows" { ";" } else { "" } }} {{ cargo-cmd }} test --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --test integration_test execute_on_heap {{ if features =="" {" --features executable_heap"} else {"--features executable_heap," + features} }} -- --ignored
228-
{{if os() == "windows" { "$env:" } else { "" } }}GUEST="{{guest}}"{{if os() == "windows" { ";" } else { "" } }} {{ cargo-cmd }} test --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --test integration_test execute_on_heap {{ if features =="" {""} else {"--features " + features} }} -- --ignored
221+
222+
# runs integration tests
223+
test-integration target=default-target features="":
224+
@# run execute_on_heap test with feature "executable_heap" on (runs with off during normal tests)
225+
{{ cargo-cmd }} test {{ if features =="" {"--features executable_heap"} else if features=="no-default-features" {"--no-default-features --features executable_heap"} else {"--no-default-features -F init-paging,executable_heap," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --test integration_test execute_on_heap
229226

230227
@# run the rest of the integration tests
231-
{{if os() == "windows" { "$env:" } else { "" } }}GUEST="{{guest}}"{{if os() == "windows" { ";" } else { "" } }} {{ cargo-cmd }} test -p hyperlight-host {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --test '*'
228+
{{ cargo-cmd }} test -p hyperlight-host {{ if features =="" {''} else if features=="no-default-features" {"--no-default-features" } else {"--no-default-features -F init-paging," + features } }} --profile={{ if target == "debug" { "dev" } else { target } }} {{ target-triple-flag }} --test '*'
232229

233230
# tests compilation with no default features on different platforms
234231
test-compilation-no-default-features target=default-target:

src/hyperlight_host/src/mem/layout.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,4 +662,13 @@ mod tests {
662662
get_expected_memory_size(&sbox_mem_layout)
663663
);
664664
}
665+
666+
#[test]
667+
fn test_max_memory_sandbox() {
668+
let mut cfg = SandboxConfiguration::default();
669+
cfg.set_input_data_size(0x40000000);
670+
let layout = SandboxMemoryLayout::new(cfg, 4096, 2048, 4096, 4096, None).unwrap();
671+
let result = layout.get_memory_size();
672+
assert!(matches!(result.unwrap_err(), MemoryRequestTooBig(..)));
673+
}
665674
}

src/hyperlight_host/src/mem/shared_mem.rs

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,50 +1333,61 @@ mod tests {
13331333
assert_eq!(data, ret_vec);
13341334
}
13351335

1336-
/// A test to ensure that, if a `SharedMem` instance is cloned
1337-
/// and _all_ clones are dropped, the memory region will no longer
1338-
/// be valid.
1339-
///
1340-
/// This test is ignored because it is incompatible with other tests as
1341-
/// they may be allocating memory at the same time.
1342-
///
1343-
/// Marking this test as ignored means that running `cargo test` will not
1344-
/// run it. This feature will allow a developer who runs that command
1345-
/// from their workstation to be successful without needing to know about
1346-
/// test interdependencies. This test will, however, be run explicitly as a
1347-
/// part of the CI pipeline.
1336+
/// Test that verifies memory is properly unmapped when all SharedMemory
1337+
/// references are dropped.
13481338
#[test]
1349-
#[ignore]
1350-
#[cfg(target_os = "linux")]
1339+
#[cfg(all(target_os = "linux", not(miri)))]
13511340
fn test_drop() {
1352-
use proc_maps::maps_contain_addr;
1341+
use proc_maps::get_process_maps;
1342+
1343+
// Use a unique size that no other test uses to avoid false positives
1344+
// from concurrent tests allocating at the same address.
1345+
// The mprotect calls split the mapping into 3 regions (guard, usable, guard),
1346+
// so we check for the usable region which has this exact size.
1347+
//
1348+
// NOTE: If this test fails intermittently, there may be a race condition
1349+
// where another test allocates memory at the same address between our
1350+
// drop and the mapping check. Ensure UNIQUE_SIZE is not used by any
1351+
// other test in the codebase to avoid this.
1352+
const UNIQUE_SIZE: usize = PAGE_SIZE_USIZE * 17;
13531353

13541354
let pid = std::process::id();
13551355

1356-
let eshm = ExclusiveSharedMemory::new(PAGE_SIZE_USIZE).unwrap();
1356+
let eshm = ExclusiveSharedMemory::new(UNIQUE_SIZE).unwrap();
13571357
let (hshm1, gshm) = eshm.build();
13581358
let hshm2 = hshm1.clone();
1359-
let addr = hshm1.raw_ptr() as usize;
13601359

1361-
// ensure the address is in the process's virtual memory
1362-
let maps_before_drop = proc_maps::get_process_maps(pid.try_into().unwrap()).unwrap();
1360+
// Use the usable memory region (not raw), since mprotect splits the mapping
1361+
let base_ptr = hshm1.base_ptr() as usize;
1362+
let mem_size = hshm1.mem_size();
1363+
1364+
// Helper to check if exact mapping exists (matching both address and size)
1365+
let has_exact_mapping = |ptr: usize, size: usize| -> bool {
1366+
get_process_maps(pid.try_into().unwrap())
1367+
.unwrap()
1368+
.iter()
1369+
.any(|m| m.start() == ptr && m.size() == size)
1370+
};
1371+
1372+
// Verify mapping exists before drop
13631373
assert!(
1364-
maps_contain_addr(addr, &maps_before_drop),
1365-
"shared memory address {:#x} was not found in process map, but should be",
1366-
addr,
1374+
has_exact_mapping(base_ptr, mem_size),
1375+
"shared memory mapping not found at {:#x} with size {}",
1376+
base_ptr,
1377+
mem_size
13671378
);
1368-
// drop both shared memory instances, which should result
1369-
// in freeing the memory region
1379+
1380+
// Drop all references
13701381
drop(hshm1);
13711382
drop(hshm2);
13721383
drop(gshm);
13731384

1374-
let maps_after_drop = proc_maps::get_process_maps(pid.try_into().unwrap()).unwrap();
1375-
// now, ensure the address is not in the process's virtual memory
1385+
// Verify exact mapping is gone
13761386
assert!(
1377-
!maps_contain_addr(addr, &maps_after_drop),
1378-
"shared memory address {:#x} was found in the process map, but shouldn't be",
1379-
addr
1387+
!has_exact_mapping(base_ptr, mem_size),
1388+
"shared memory mapping still exists at {:#x} with size {} after drop",
1389+
base_ptr,
1390+
mem_size
13801391
);
13811392
}
13821393

src/hyperlight_host/src/sandbox/initialized_multi_use.rs

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,41 +1119,38 @@ mod tests {
11191119
}
11201120

11211121
#[test]
1122-
#[ignore] // this test runs by itself because it uses a lot of system resources
1123-
fn create_1000_sandboxes() {
1124-
let barrier = Arc::new(Barrier::new(21));
1122+
fn create_200_sandboxes() {
1123+
const NUM_THREADS: usize = 10;
1124+
const SANDBOXES_PER_THREAD: usize = 20;
11251125

1126-
let mut handles = vec![];
1126+
// barrier to make sure all threads start their work simultaneously
1127+
let start_barrier = Arc::new(Barrier::new(NUM_THREADS + 1));
1128+
let mut thread_handles = vec![];
11271129

1128-
for _ in 0..20 {
1129-
let c = barrier.clone();
1130+
for _ in 0..NUM_THREADS {
1131+
let barrier = start_barrier.clone();
11301132

11311133
let handle = thread::spawn(move || {
1132-
c.wait();
1133-
1134-
for _ in 0..50 {
1135-
let usbox = UninitializedSandbox::new(
1136-
GuestBinary::FilePath(
1137-
simple_guest_as_string().expect("Guest Binary Missing"),
1138-
),
1139-
None,
1140-
)
1141-
.unwrap();
1134+
barrier.wait();
11421135

1143-
let mut multi_use_sandbox: MultiUseSandbox = usbox.evolve().unwrap();
1136+
for _ in 0..SANDBOXES_PER_THREAD {
1137+
let guest_path = simple_guest_as_string().expect("Guest Binary Missing");
1138+
let uninit =
1139+
UninitializedSandbox::new(GuestBinary::FilePath(guest_path), None).unwrap();
11441140

1145-
let res: i32 = multi_use_sandbox.call("GetStatic", ()).unwrap();
1141+
let mut sandbox: MultiUseSandbox = uninit.evolve().unwrap();
11461142

1147-
assert_eq!(res, 0);
1143+
let result: i32 = sandbox.call("GetStatic", ()).unwrap();
1144+
assert_eq!(result, 0);
11481145
}
11491146
});
11501147

1151-
handles.push(handle);
1148+
thread_handles.push(handle);
11521149
}
11531150

1154-
barrier.wait();
1151+
start_barrier.wait();
11551152

1156-
for handle in handles {
1153+
for handle in thread_handles {
11571154
handle.join().unwrap();
11581155
}
11591156
}

0 commit comments

Comments
 (0)