Skip to content

Commit 00c8ae6

Browse files
committed
Fix tests and examples that relied on timing out
Signed-off-by: Ludvig Liljenberg <[email protected]>
1 parent a45c35b commit 00c8ae6

File tree

5 files changed

+122
-50
lines changed

5 files changed

+122
-50
lines changed

src/hyperlight_host/examples/logging/main.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ limitations under the License.
1616
#![allow(clippy::disallowed_macros)]
1717
extern crate hyperlight_host;
1818

19+
use std::sync::{Arc, Barrier};
20+
1921
use hyperlight_host::sandbox::uninitialized::UninitializedSandbox;
2022
use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox;
2123
use hyperlight_host::sandbox_state::transition::Noop;
@@ -82,15 +84,29 @@ fn main() -> Result<()> {
8284
let no_op = Noop::<UninitializedSandbox, MultiUseSandbox>::default();
8385

8486
let mut multiuse_sandbox = usandbox.evolve(no_op)?;
87+
let interrupt_handle = multiuse_sandbox.interrupt_handle();
88+
let barrier = Arc::new(Barrier::new(2));
89+
let barrier2 = barrier.clone();
90+
const NUM_CALLS: i32 = 5;
91+
let thread = std::thread::spawn(move || {
92+
for _ in 0..NUM_CALLS {
93+
barrier2.wait();
94+
// Sleep for a short time to allow the guest function to run.
95+
std::thread::sleep(std::time::Duration::from_millis(500));
96+
// Cancel the host function call.
97+
interrupt_handle.kill();
98+
}
99+
});
85100

86101
// Call a function that gets cancelled by the host function 5 times to generate some log entries.
87102

88-
for _ in 0..5 {
103+
for _ in 0..NUM_CALLS {
89104
let mut ctx = multiuse_sandbox.new_call_context();
90-
105+
barrier.wait();
91106
ctx.call::<()>("Spin", ()).unwrap_err();
92107
multiuse_sandbox = ctx.finish().unwrap();
93108
}
109+
thread.join().unwrap();
94110

95111
Ok(())
96112
}

src/hyperlight_host/examples/metrics/main.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ limitations under the License.
1515
*/
1616
#![allow(clippy::disallowed_macros)]
1717
extern crate hyperlight_host;
18+
use std::sync::{Arc, Barrier};
1819
use std::thread::{spawn, JoinHandle};
1920

2021
use hyperlight_host::sandbox::uninitialized::UninitializedSandbox;
@@ -95,12 +96,27 @@ fn do_hyperlight_stuff() {
9596
let no_op = Noop::<UninitializedSandbox, MultiUseSandbox>::default();
9697

9798
let mut multiuse_sandbox = usandbox.evolve(no_op).expect("Failed to evolve sandbox");
99+
let interrupt_handle = multiuse_sandbox.interrupt_handle();
100+
101+
const NUM_CALLS: i32 = 5;
102+
let barrier = Arc::new(Barrier::new(2));
103+
let barrier2 = barrier.clone();
104+
105+
let thread = std::thread::spawn(move || {
106+
for _ in 0..NUM_CALLS {
107+
barrier2.wait();
108+
// Sleep for a short time to allow the guest function to run after the `wait`.
109+
std::thread::sleep(std::time::Duration::from_millis(500));
110+
// Cancel the host function call.
111+
interrupt_handle.kill();
112+
}
113+
});
98114

99115
// Call a function that gets cancelled by the host function 5 times to generate some metrics.
100116

101-
for _ in 0..5 {
117+
for _ in 0..NUM_CALLS {
102118
let mut ctx = multiuse_sandbox.new_call_context();
103-
119+
barrier.wait();
104120
ctx.call::<()>("Spin", ()).unwrap_err();
105121
multiuse_sandbox = ctx.finish().unwrap();
106122
}
@@ -109,6 +125,7 @@ fn do_hyperlight_stuff() {
109125
let result = join_handle.join();
110126
assert!(result.is_ok());
111127
}
128+
thread.join().unwrap();
112129
}
113130

114131
fn fn_writer(_msg: String) -> Result<i32> {

src/hyperlight_host/examples/tracing-otlp/main.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,15 @@ limitations under the License.
1616
#![allow(clippy::disallowed_macros)]
1717
//use opentelemetry_sdk::resource::ResourceBuilder;
1818
use opentelemetry_sdk::trace::SdkTracerProvider;
19-
use rand::Rng;
2019
use tracing::{span, Level};
2120
use tracing_opentelemetry::OpenTelemetryLayer;
2221
use tracing_subscriber::layer::SubscriberExt;
2322
use tracing_subscriber::util::SubscriberInitExt;
2423
extern crate hyperlight_host;
2524
use std::error::Error;
2625
use std::io::stdin;
27-
use std::sync::{Arc, Mutex};
28-
use std::thread::{self, spawn, JoinHandle};
26+
use std::sync::{Arc, Barrier, Mutex};
27+
use std::thread::{spawn, JoinHandle};
2928

3029
use hyperlight_host::sandbox::uninitialized::UninitializedSandbox;
3130
use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox;
@@ -157,8 +156,23 @@ fn run_example(wait_input: bool) -> HyperlightResult<()> {
157156
}
158157

159158
// Call a function that gets cancelled by the host function 5 times to generate some log entries.
160-
161-
for i in 0..5 {
159+
const NUM_CALLS: i32 = 5;
160+
let barrier = Arc::new(Barrier::new(2));
161+
let barrier2 = barrier.clone();
162+
163+
let interrupt_handle = multiuse_sandbox.interrupt_handle();
164+
165+
let thread = std::thread::spawn(move || {
166+
for _ in 0..NUM_CALLS {
167+
barrier2.wait();
168+
// Sleep for a short time to allow the guest function to run.
169+
std::thread::sleep(std::time::Duration::from_millis(500));
170+
// Cancel the host function call.
171+
interrupt_handle.kill();
172+
}
173+
});
174+
175+
for i in 0..NUM_CALLS {
162176
let id = Uuid::new_v4();
163177
// Construct a new span named "hyperlight tracing call cancellation example thread" with INFO level.
164178
let span = span!(
@@ -169,15 +183,11 @@ fn run_example(wait_input: bool) -> HyperlightResult<()> {
169183
);
170184
let _entered = span.enter();
171185
let mut ctx = multiuse_sandbox.new_call_context();
172-
186+
barrier.wait();
173187
ctx.call::<()>("Spin", ()).unwrap_err();
174188
multiuse_sandbox = ctx.finish().unwrap();
175189
}
176-
let sleep_for = {
177-
let mut rng = rand::rng();
178-
rng.random_range(500..3000)
179-
};
180-
thread::sleep(std::time::Duration::from_millis(sleep_for));
190+
thread.join().expect("Thread panicked");
181191
}
182192
Ok(())
183193
});

src/hyperlight_host/examples/tracing/main.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ limitations under the License.
1616
#![allow(clippy::disallowed_macros)]
1717
use tracing::{span, Level};
1818
extern crate hyperlight_host;
19+
use std::sync::{Arc, Barrier};
1920
use std::thread::{spawn, JoinHandle};
2021

2122
use hyperlight_host::sandbox::uninitialized::UninitializedSandbox;
@@ -110,10 +111,24 @@ fn run_example() -> Result<()> {
110111
let no_op = Noop::<UninitializedSandbox, MultiUseSandbox>::default();
111112

112113
let mut multiuse_sandbox = usandbox.evolve(no_op)?;
114+
let interrupt_handle = multiuse_sandbox.interrupt_handle();
113115

114116
// Call a function that gets cancelled by the host function 5 times to generate some log entries.
115-
116-
for i in 0..5 {
117+
const NUM_CALLS: i32 = 5;
118+
let barrier = Arc::new(Barrier::new(2));
119+
let barrier2 = barrier.clone();
120+
121+
let thread = std::thread::spawn(move || {
122+
for _ in 0..NUM_CALLS {
123+
barrier2.wait();
124+
// Sleep for a short time to allow the guest function to run.
125+
std::thread::sleep(std::time::Duration::from_millis(500));
126+
// Cancel the host function call.
127+
interrupt_handle.kill();
128+
}
129+
});
130+
131+
for i in 0..NUM_CALLS {
117132
let id = Uuid::new_v4();
118133
// Construct a new span named "hyperlight tracing call cancellation example thread" with INFO level.
119134
let span = span!(
@@ -124,7 +139,7 @@ fn run_example() -> Result<()> {
124139
);
125140
let _entered = span.enter();
126141
let mut ctx = multiuse_sandbox.new_call_context();
127-
142+
barrier.wait();
128143
ctx.call::<()>("Spin", ()).unwrap_err();
129144
multiuse_sandbox = ctx.finish().unwrap();
130145
}
@@ -133,6 +148,7 @@ fn run_example() -> Result<()> {
133148
let result = join_handle.join();
134149
assert!(result.is_ok());
135150
}
151+
thread.join().unwrap();
136152

137153
Ok(())
138154
}

src/hyperlight_host/src/metrics/mod.rs

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,11 @@ pub(crate) fn maybe_time_and_emit_host_call<T, F: FnOnce() -> T>(
8585

8686
#[cfg(test)]
8787
mod tests {
88+
use std::thread;
89+
use std::time::Duration;
90+
8891
use hyperlight_testing::simple_guest_as_string;
89-
use metrics::Key;
92+
use metrics::{with_local_recorder, Key};
9093
use metrics_util::CompositeKey;
9194

9295
use super::*;
@@ -95,24 +98,24 @@ mod tests {
9598
use crate::{GuestBinary, UninitializedSandbox};
9699

97100
#[test]
98-
#[ignore = "This test needs to be run separately to avoid having other tests interfere with it"]
99101
fn test_metrics_are_emitted() {
100-
// Set up the recorder and snapshotter
101102
let recorder = metrics_util::debugging::DebuggingRecorder::new();
102103
let snapshotter = recorder.snapshotter();
103-
104-
// we cannot use with_local_recorder, since that won't capture the metrics
105-
// emitted by the hypervisor-thread (which is all of them)
106-
recorder.install().unwrap();
107-
108-
let snapshot = {
104+
let snapshot = with_local_recorder(&recorder, || {
109105
let uninit = UninitializedSandbox::new(
110106
GuestBinary::FilePath(simple_guest_as_string().unwrap()),
111107
None,
112108
)
113109
.unwrap();
114110

115111
let mut multi = uninit.evolve(Noop::default()).unwrap();
112+
let interrupt_handle = multi.interrupt_handle();
113+
114+
// interrupt the guest function call to "Spin" after 1 second
115+
let thread = thread::spawn(move || {
116+
thread::sleep(Duration::from_secs(1));
117+
assert!(interrupt_handle.kill());
118+
});
116119

117120
multi
118121
.call_guest_function_by_name::<i32>("PrintOutput", "Hello".to_string())
@@ -121,9 +124,10 @@ mod tests {
121124
multi
122125
.call_guest_function_by_name::<i32>("Spin", ())
123126
.unwrap_err();
127+
thread.join().unwrap();
124128

125129
snapshotter.snapshot()
126-
};
130+
});
127131

128132
// Convert snapshot into a hashmap for easier lookup
129133
#[expect(clippy::mutable_key_type)]
@@ -132,27 +136,17 @@ mod tests {
132136
cfg_if::cfg_if! {
133137
if #[cfg(feature = "function_call_metrics")] {
134138
use metrics::Label;
135-
// Verify that the histogram metrics are recorded correctly
136-
assert_eq!(snapshot.len(), 4, "Expected two metrics in the snapshot");
137139

138-
// 1. Host print duration
139-
let histogram_key = CompositeKey::new(
140-
metrics_util::MetricKind::Histogram,
141-
Key::from_parts(
142-
METRIC_HOST_FUNC_DURATION,
143-
vec![Label::new("function_name", "HostPrint")],
144-
),
145-
);
146-
let histogram_value = &snapshot.get(&histogram_key).unwrap().2;
147-
assert!(
148-
matches!(
149-
histogram_value,
150-
metrics_util::debugging::DebugValue::Histogram(histogram) if histogram.len() == 1
151-
),
152-
"Histogram metric does not match expected value"
153-
);
140+
let expected_num_metrics = if cfg!(all(feature = "seccomp", target_os = "linux")) {
141+
3 // if seccomp enabled, the host call duration metric is emitted on a separate thread which this local recorder doesn't capture
142+
} else {
143+
4
144+
};
154145

155-
// 2. Guest call duration
146+
// Verify that the histogram metrics are recorded correctly
147+
assert_eq!(snapshot.len(), expected_num_metrics);
148+
149+
// 1. Guest call duration
156150
let histogram_key = CompositeKey::new(
157151
metrics_util::MetricKind::Histogram,
158152
Key::from_parts(
@@ -169,7 +163,7 @@ mod tests {
169163
"Histogram metric does not match expected value"
170164
);
171165

172-
// 3. Guest cancellation
166+
// 2. Guest cancellation
173167
let counter_key = CompositeKey::new(
174168
metrics_util::MetricKind::Counter,
175169
Key::from_name(METRIC_GUEST_CANCELLATION),
@@ -179,7 +173,7 @@ mod tests {
179173
metrics_util::debugging::DebugValue::Counter(1)
180174
);
181175

182-
// 4. Guest call duration
176+
// 3. Guest call duration
183177
let histogram_key = CompositeKey::new(
184178
metrics_util::MetricKind::Histogram,
185179
Key::from_parts(
@@ -195,9 +189,28 @@ mod tests {
195189
),
196190
"Histogram metric does not match expected value"
197191
);
192+
193+
if !cfg!(all(feature = "seccomp", target_os = "linux")) {
194+
// 4. Host call duration
195+
let histogram_key = CompositeKey::new(
196+
metrics_util::MetricKind::Histogram,
197+
Key::from_parts(
198+
METRIC_HOST_FUNC_DURATION,
199+
vec![Label::new("function_name", "HostPrint")],
200+
),
201+
);
202+
let histogram_value = &snapshot.get(&histogram_key).unwrap().2;
203+
assert!(
204+
matches!(
205+
histogram_value,
206+
metrics_util::debugging::DebugValue::Histogram(histogram) if histogram.len() == 1
207+
),
208+
"Histogram metric does not match expected value"
209+
);
210+
}
198211
} else {
199212
// Verify that the counter metrics are recorded correctly
200-
assert_eq!(snapshot.len(), 1, "Expected two metrics in the snapshot");
213+
assert_eq!(snapshot.len(), 1);
201214

202215
let counter_key = CompositeKey::new(
203216
metrics_util::MetricKind::Counter,

0 commit comments

Comments
 (0)