From 8bd56c8c3c68e8e67d0e04f0987f47807128739e Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Tue, 27 Jan 2026 10:57:01 -0800 Subject: [PATCH 1/4] Make test_drop able to run concurrently Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- Justfile | 1 - src/hyperlight_host/src/mem/shared_mem.rs | 69 +++++++++++++---------- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/Justfile b/Justfile index e11c16ec3..f73546548 100644 --- a/Justfile +++ b/Justfile @@ -167,7 +167,6 @@ test-isolated target=default-target features="" : {{ 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 {{ 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 {{ 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 - {{ 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 {{ 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 @# metrics tests {{ 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 diff --git a/src/hyperlight_host/src/mem/shared_mem.rs b/src/hyperlight_host/src/mem/shared_mem.rs index a69394c23..daed0697e 100644 --- a/src/hyperlight_host/src/mem/shared_mem.rs +++ b/src/hyperlight_host/src/mem/shared_mem.rs @@ -1331,50 +1331,61 @@ mod tests { assert_eq!(data, ret_vec); } - /// A test to ensure that, if a `SharedMem` instance is cloned - /// and _all_ clones are dropped, the memory region will no longer - /// be valid. - /// - /// This test is ignored because it is incompatible with other tests as - /// they may be allocating memory at the same time. - /// - /// Marking this test as ignored means that running `cargo test` will not - /// run it. This feature will allow a developer who runs that command - /// from their workstation to be successful without needing to know about - /// test interdependencies. This test will, however, be run explicitly as a - /// part of the CI pipeline. + /// Test that verifies memory is properly unmapped when all SharedMemory + /// references are dropped. #[test] - #[ignore] - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(miri)))] fn test_drop() { - use proc_maps::maps_contain_addr; + use proc_maps::get_process_maps; + + // Use a unique size that no other test uses to avoid false positives + // from concurrent tests allocating at the same address. + // The mprotect calls split the mapping into 3 regions (guard, usable, guard), + // so we check for the usable region which has this exact size. + // + // NOTE: If this test fails intermittently, there may be a race condition + // where another test allocates memory at the same address between our + // drop and the mapping check. Ensure UNIQUE_SIZE is not used by any + // other test in the codebase to avoid this. + const UNIQUE_SIZE: usize = PAGE_SIZE_USIZE * 17; let pid = std::process::id(); - let eshm = ExclusiveSharedMemory::new(PAGE_SIZE_USIZE).unwrap(); + let eshm = ExclusiveSharedMemory::new(UNIQUE_SIZE).unwrap(); let (hshm1, gshm) = eshm.build(); let hshm2 = hshm1.clone(); - let addr = hshm1.raw_ptr() as usize; - // ensure the address is in the process's virtual memory - let maps_before_drop = proc_maps::get_process_maps(pid.try_into().unwrap()).unwrap(); + // Use the usable memory region (not raw), since mprotect splits the mapping + let base_ptr = hshm1.base_ptr() as usize; + let mem_size = hshm1.mem_size(); + + // Helper to check if exact mapping exists (matching both address and size) + let has_exact_mapping = |ptr: usize, size: usize| -> bool { + get_process_maps(pid.try_into().unwrap()) + .unwrap() + .iter() + .any(|m| m.start() == ptr && m.size() == size) + }; + + // Verify mapping exists before drop assert!( - maps_contain_addr(addr, &maps_before_drop), - "shared memory address {:#x} was not found in process map, but should be", - addr, + has_exact_mapping(base_ptr, mem_size), + "shared memory mapping not found at {:#x} with size {}", + base_ptr, + mem_size ); - // drop both shared memory instances, which should result - // in freeing the memory region + + // Drop all references drop(hshm1); drop(hshm2); drop(gshm); - let maps_after_drop = proc_maps::get_process_maps(pid.try_into().unwrap()).unwrap(); - // now, ensure the address is not in the process's virtual memory + // Verify exact mapping is gone assert!( - !maps_contain_addr(addr, &maps_after_drop), - "shared memory address {:#x} was found in the process map, but shouldn't be", - addr + !has_exact_mapping(base_ptr, mem_size), + "shared memory mapping still exists at {:#x} with size {} after drop", + base_ptr, + mem_size ); } From c8e2ce3347441e564ab0992919de92fb02355777 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Tue, 27 Jan 2026 11:03:50 -0800 Subject: [PATCH 2/4] Make create_1000_sandboxes be able to run concurrently Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- Justfile | 1 - .../src/sandbox/initialized_multi_use.rs | 41 +++++++++---------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/Justfile b/Justfile index f73546548..699daee2a 100644 --- a/Justfile +++ b/Justfile @@ -165,7 +165,6 @@ test-unit target=default-target features="": test-isolated target=default-target features="" : {{ 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 {{ 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 - {{ 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 {{ 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 {{ 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 @# metrics tests diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 8673c6e9c..352bd028a 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -1071,41 +1071,38 @@ mod tests { } #[test] - #[ignore] // this test runs by itself because it uses a lot of system resources - fn create_1000_sandboxes() { - let barrier = Arc::new(Barrier::new(21)); + fn create_200_sandboxes() { + const NUM_THREADS: usize = 10; + const SANDBOXES_PER_THREAD: usize = 20; - let mut handles = vec![]; + // barrier to make sure all threads start their work simultaneously + let start_barrier = Arc::new(Barrier::new(NUM_THREADS + 1)); + let mut thread_handles = vec![]; - for _ in 0..20 { - let c = barrier.clone(); + for _ in 0..NUM_THREADS { + let barrier = start_barrier.clone(); let handle = thread::spawn(move || { - c.wait(); - - for _ in 0..50 { - let usbox = UninitializedSandbox::new( - GuestBinary::FilePath( - simple_guest_as_string().expect("Guest Binary Missing"), - ), - None, - ) - .unwrap(); + barrier.wait(); - let mut multi_use_sandbox: MultiUseSandbox = usbox.evolve().unwrap(); + for _ in 0..SANDBOXES_PER_THREAD { + let guest_path = simple_guest_as_string().expect("Guest Binary Missing"); + let uninit = + UninitializedSandbox::new(GuestBinary::FilePath(guest_path), None).unwrap(); - let res: i32 = multi_use_sandbox.call("GetStatic", ()).unwrap(); + let mut sandbox: MultiUseSandbox = uninit.evolve().unwrap(); - assert_eq!(res, 0); + let result: i32 = sandbox.call("GetStatic", ()).unwrap(); + assert_eq!(result, 0); } }); - handles.push(handle); + thread_handles.push(handle); } - barrier.wait(); + start_barrier.wait(); - for handle in handles { + for handle in thread_handles { handle.join().unwrap(); } } From b92b32a856af661c1f9ab00f41ab5115fb1a221e Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Tue, 27 Jan 2026 11:13:51 -0800 Subject: [PATCH 3/4] Allow execute_on_heap to execute concurrently Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- Justfile | 5 ++--- src/hyperlight_host/tests/integration_test.rs | 18 +++++++++--------- src/tests/rust_guests/simpleguest/src/main.rs | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Justfile b/Justfile index 699daee2a..c00a3aeec 100644 --- a/Justfile +++ b/Justfile @@ -171,9 +171,8 @@ test-isolated target=default-target features="" : {{ 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 # runs integration tests. Guest can either be "rust" or "c" test-integration guest target=default-target features="": - @# run execute_on_heap test with feature "executable_heap" on and off - {{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 - {{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 + @# run execute_on_heap test with feature "executable_heap" on (runs with off during normal tests) + {{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} }} @# run the rest of the integration tests @# skip interrupt_random_kill_stress_test and then run it explicitly so we can see the output more diff --git a/src/hyperlight_host/tests/integration_test.rs b/src/hyperlight_host/tests/integration_test.rs index 9a395ee81..26fef12fa 100644 --- a/src/hyperlight_host/tests/integration_test.rs +++ b/src/hyperlight_host/tests/integration_test.rs @@ -705,22 +705,22 @@ fn execute_on_stack() { } #[test] -#[ignore] // ran from Justfile because requires feature "executable_heap" fn execute_on_heap() { let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); let result = sbox1.call::("ExecuteOnHeap", ()); - println!("{:#?}", result); #[cfg(feature = "executable_heap")] - assert!(result.is_ok()); + assert_eq!( + result.unwrap(), + "Executed on heap successfully", + "should execute successfully" + ); #[cfg(not(feature = "executable_heap"))] - { - assert!(result.is_err()); - let err = result.unwrap_err(); - - assert!(err.to_string().contains("PageFault")); - } + assert!( + result.unwrap_err().to_string().contains("PageFault"), + "should get page fault" + ); } // checks that a recursive function with stack allocation eventually fails with stackoverflow diff --git a/src/tests/rust_guests/simpleguest/src/main.rs b/src/tests/rust_guests/simpleguest/src/main.rs index df7de9469..586d1bcb6 100644 --- a/src/tests/rust_guests/simpleguest/src/main.rs +++ b/src/tests/rust_guests/simpleguest/src/main.rs @@ -489,7 +489,7 @@ fn execute_on_heap() -> String { black_box(heap_fn); // avoid optimization when running in release mode } // will only reach this point if heap is executable - String::from("fail") + String::from("Executed on heap successfully") } #[guest_function("TestMalloc")] From bcb8f97d21190f8028da547f7616ea58f7d7f342 Mon Sep 17 00:00:00 2001 From: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> Date: Tue, 27 Jan 2026 11:53:44 -0800 Subject: [PATCH 4/4] Allow test_trace_trace to run concurrently (by removing unused TestLogger) Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com> --- Justfile | 1 - .../src/sandbox/uninitialized.rs | 165 ++++++++---------- src/hyperlight_host/src/testing/log_values.rs | 64 ------- 3 files changed, 70 insertions(+), 160 deletions(-) diff --git a/Justfile b/Justfile index c00a3aeec..2d8b799a0 100644 --- a/Justfile +++ b/Justfile @@ -163,7 +163,6 @@ test-unit target=default-target features="": # runs tests that requires being run separately, for example due to global state test-isolated target=default-target features="" : - {{ 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 {{ 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 {{ 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 {{ 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 diff --git a/src/hyperlight_host/src/sandbox/uninitialized.rs b/src/hyperlight_host/src/sandbox/uninitialized.rs index ea40a7f43..b21cf05db 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized.rs @@ -758,115 +758,90 @@ mod tests { } } + /// Tests that tracing spans and events are properly emitted when a tracing subscriber is set. + /// + /// This test verifies: + /// 1. Spans are created with correct attributes (correlation_id) + /// 2. Nested spans from UninitializedSandbox::new are properly parented + /// 3. Error events are emitted when sandbox creation fails #[test] - // Tests that trace data are emitted when a trace subscriber is set - // this test is ignored because it is incompatible with other tests , specifically those which require a logger for tracing - // marking this test as ignored means that running `cargo test` will not run this test but will allow a developer who runs that command - // from their workstation to be successful without needed to know about test interdependencies - // this test will be run explicitly as a part of the CI pipeline - #[ignore] #[cfg(feature = "build-metadata")] fn test_trace_trace() { - use hyperlight_testing::logger::Logger as TestLogger; - use hyperlight_testing::tracing_subscriber::TracingSubscriber as TestSubscriber; - use serde_json::{Map, Value}; - use tracing::Level as tracing_level; + use hyperlight_testing::tracing_subscriber::TracingSubscriber; + use tracing::Level; use tracing_core::Subscriber; - use tracing_core::callsite::rebuild_interest_cache; use uuid::Uuid; - use crate::testing::log_values::build_metadata_testing::try_to_strings; - use crate::testing::log_values::test_value_as_str; - - TestLogger::initialize_log_tracer(); - rebuild_interest_cache(); - let subscriber = TestSubscriber::new(tracing_level::TRACE); - tracing::subscriber::with_default(subscriber.clone(), || { - let correlation_id = Uuid::new_v4().as_hyphenated().to_string(); - let span = tracing::error_span!("test_trace_logs", correlation_id).entered(); - - // We should be in span 1 - - let current_span = subscriber.current_span(); - assert!(current_span.is_known(), "Current span is unknown"); - let current_span_metadata = current_span.into_inner().unwrap(); - assert_eq!( - current_span_metadata.0.into_u64(), - 1, - "Current span is not span 1" - ); - assert_eq!(current_span_metadata.1.name(), "test_trace_logs"); - - // Get the span data and check the correlation id - - let span_data = subscriber.get_span(1); - let span_attributes: &Map = span_data - .get("span") - .unwrap() - .get("attributes") - .unwrap() - .as_object() - .unwrap(); - - test_value_as_str(span_attributes, "correlation_id", correlation_id.as_str()); - - let mut binary_path = simple_guest_as_string().unwrap(); - binary_path.push_str("does_not_exist"); + /// Helper to extract a string value from nested JSON: obj["span"]["attributes"][key] + fn get_span_attr<'a>(span: &'a serde_json::Value, key: &str) -> Option<&'a str> { + span.get("span")?.get("attributes")?.get(key)?.as_str() + } - let sbox = UninitializedSandbox::new(GuestBinary::FilePath(binary_path), None); - assert!(sbox.is_err()); + /// Helper to extract event field: obj["event"][field] + fn get_event_field<'a>(event: &'a serde_json::Value, field: &str) -> Option<&'a str> { + event.get("event")?.get(field)?.as_str() + } - // Now we should still be in span 1 but span 2 should be created (we created entered and exited span 2 when we called UninitializedSandbox::new) + /// Helper to extract event metadata field: obj["event"]["metadata"][field] + fn get_event_metadata<'a>(event: &'a serde_json::Value, field: &str) -> Option<&'a str> { + event.get("event")?.get("metadata")?.get(field)?.as_str() + } - let current_span = subscriber.current_span(); - assert!(current_span.is_known(), "Current span is unknown"); - let current_span_metadata = current_span.into_inner().unwrap(); - assert_eq!( - current_span_metadata.0.into_u64(), - 1, - "Current span is not span 1" - ); + let subscriber = TracingSubscriber::new(Level::TRACE); - let span_metadata = subscriber.get_span_metadata(2); - assert_eq!(span_metadata.name(), "new"); + tracing::subscriber::with_default(subscriber.clone(), || { + let correlation_id = Uuid::new_v4().to_string(); + let _span = tracing::error_span!("test_trace_logs", %correlation_id).entered(); + + // Verify we're in span 1 with correct name + let (span_id, span_meta) = subscriber + .current_span() + .into_inner() + .expect("Should be inside a span"); + assert_eq!(span_id.into_u64(), 1, "Should be in span 1"); + assert_eq!(span_meta.name(), "test_trace_logs"); + + // Verify correlation_id was recorded + let span_data = subscriber.get_span(1); + let recorded_id = + get_span_attr(&span_data, "correlation_id").expect("correlation_id not found"); + assert_eq!(recorded_id, correlation_id); + + // Try to create a sandbox with a non-existent binary - this should fail + // and emit an error event + let bad_path = simple_guest_as_string().unwrap() + "does_not_exist"; + let result = UninitializedSandbox::new(GuestBinary::FilePath(bad_path), None); + assert!(result.is_err(), "Sandbox creation should fail"); + + // Verify we're still in span 1 (our test span) + let (span_id, _) = subscriber + .current_span() + .into_inner() + .expect("Should still be inside a span"); + assert_eq!(span_id.into_u64(), 1, "Should still be in span 1"); + + // Verify span 2 was created by UninitializedSandbox::new + let inner_span_meta = subscriber.get_span_metadata(2); + assert_eq!(inner_span_meta.name(), "new"); + + // Verify the error event was emitted + let events = subscriber.get_events(); + assert_eq!(events.len(), 1, "Expected exactly one error event"); - // There should be one event for the error that the binary path does not exist plus 14 info events for the logging of the crate info + let event = &events[0]; + let level = get_event_metadata(event, "level").expect("event should have level"); + let error = get_event_field(event, "error").expect("event should have error field"); + let target = get_event_metadata(event, "target").expect("event should have target"); + let module_path = + get_event_metadata(event, "module_path").expect("event should have module_path"); - let events = subscriber.get_events(); - assert_eq!(events.len(), 1); - - let mut count_matching_events = 0; - - for json_value in events { - let event_values = json_value.as_object().unwrap().get("event").unwrap(); - let metadata_values_map = - event_values.get("metadata").unwrap().as_object().unwrap(); - let event_values_map = event_values.as_object().unwrap(); - - let expected_error_start = "Error(\"GuestBinary not found:"; - - let err_vals_res = try_to_strings([ - (metadata_values_map, "level"), - (event_values_map, "error"), - (metadata_values_map, "module_path"), - (metadata_values_map, "target"), - ]); - if let Ok(err_vals) = err_vals_res - && err_vals[0] == "ERROR" - && err_vals[1].starts_with(expected_error_start) - && err_vals[2] == "hyperlight_host::sandbox::uninitialized" - && err_vals[3] == "hyperlight_host::sandbox::uninitialized" - { - count_matching_events += 1; - } - } + assert_eq!(level, "ERROR"); assert!( - count_matching_events == 1, - "Unexpected number of matching events {}", - count_matching_events + error.contains("GuestBinary not found"), + "Error should mention 'GuestBinary not found', got: {error}" ); - span.exit(); - subscriber.clear(); + assert_eq!(target, "hyperlight_host::sandbox::uninitialized"); + assert_eq!(module_path, "hyperlight_host::sandbox::uninitialized"); }); } diff --git a/src/hyperlight_host/src/testing/log_values.rs b/src/hyperlight_host/src/testing/log_values.rs index 049010459..47f40ae0a 100644 --- a/src/hyperlight_host/src/testing/log_values.rs +++ b/src/hyperlight_host/src/testing/log_values.rs @@ -60,67 +60,3 @@ fn try_to_string<'a>(values: &'a Map, key: &'a str) -> Result<&'a Err(new_error!("value for key {} was not found", key)) } } - -#[cfg(feature = "build-metadata")] -pub(crate) mod build_metadata_testing { - use super::*; - - /// A single value in the parameter list for the `try_to_strings` - /// function. - pub(crate) type MapLookup<'a> = (&'a Map, &'a str); - - /// Given a constant-size slice of `MapLookup`s, attempt to look up the - /// string value in each `MapLookup`'s map (the first tuple element) for - /// that `MapLookup`'s key (the second tuple element). If the lookup - /// succeeded, attempt to convert the resulting value to a string. Return - /// `Ok` with all the successfully looked-up string values, or `Err` - /// if any one or more lookups or string conversions failed. - pub(crate) fn try_to_strings<'a, const NUM: usize>( - lookups: [MapLookup<'a>; NUM], - ) -> Result<[&'a str; NUM]> { - // Note (from arschles) about this code: - // - // In theory, there's a way to write this function in the functional - // programming (FP) style -- e.g. with a fold, map, flat_map, or - // something similar -- and without any mutability. - // - // In practice, however, since we're taking in a statically-sized slice, - // and we are expected to return a statically-sized slice of the same - // size, we are more limited in what we can do. There is a way to design - // a fold or flat_map to iterate over the lookups parameter and attempt to - // transform each MapLookup into the string value at that key. - // - // I wrote that code, which I'll called the "FP code" hereafter, and - // noticed two things: - // - // - It required several places where I had to explicitly deal with long - // and complex (in my opinion) types - // - It wasn't much more succinct or shorter than the code herein - // - // The FP code is functionally "pure" and maybe fun to write (if you like - // Rust or you love FP), but not fun to read. In fact, because of all the - // explicit type ceremony, I bet it'd make even the most hardcore Haskell - // programmer blush. - // - // So, I've decided to use a little bit of mutability to implement this - // function in a way I think most programmers would agree is easier to - // reason about and understand quickly. - // - // Final performance note: - // - // It's likely, but not certain, that the FP code is probably not - // significantly more memory efficient than this, since the compiler knows - // the size of both the input and output slices. Plus, this is test code, - // so even if this were 2x slower, I'd still argue the ease of - // understanding is more valuable than the (relatively small) memory - // savings. - let mut ret_slc: [&'a str; NUM] = [""; NUM]; - for (idx, lookup) in lookups.iter().enumerate() { - let map = lookup.0; - let key = lookup.1; - let val = try_to_string(map, key)?; - ret_slc[idx] = val - } - Ok(ret_slc) - } -}