@@ -104,163 +104,163 @@ impl MultiUseGuestCallContext {
104
104
}
105
105
}
106
106
107
- // TODO(danbugs:297): bring back
108
- // #[cfg(test)]
109
- // mod tests {
110
- // use std::sync::mpsc::sync_channel ;
111
- // use std::thread::{self, JoinHandle};
112
- //
113
- // use hyperlight_common::flatbuffer_wrappers::function_types::{
114
- // ParameterValue, ReturnType, ReturnValue,
115
- // } ;
116
- // use hyperlight_testing::simple_guest_as_string;
117
- //
118
- // use crate::sandbox_state::sandbox::EvolvableSandbox;
119
- // use crate::sandbox_state::transition::Noop;
120
- // use crate::{GuestBinary, HyperlightError , MultiUseSandbox, Result, UninitializedSandbox};
121
- //
122
- // fn new_uninit() -> Result<UninitializedSandbox> {
123
- // let path = simple_guest_as_string().map_err(|e| {
124
- // HyperlightError::Error(format!("failed to get simple guest path ({e:?})"))
125
- // })?;
126
- // UninitializedSandbox::new(GuestBinary::FilePath(path), None, None, None )
127
- // }
128
- //
129
- // /// Test to create a `MultiUseSandbox`, then call several guest functions
130
- // /// on it across different threads.
131
- // ///
132
- // /// This test works by passing messages between threads using Rust's
133
- // /// [mpsc crate](https://doc.rust-lang.org/std/sync/mpsc). Details of this
134
- // /// interaction are as follows.
135
- // ///
136
- // /// One thread acts as the receiver (AKA: consumer) and owns the
137
- // /// `MultiUseSandbox`. This receiver fields requests from N senders
138
- // /// (AKA: producers) to make batches of calls.
139
- // ///
140
- // /// Upon receipt of a message to execute a batch, a new
141
- // /// `MultiUseGuestCallContext` is created in the receiver thread from the
142
- // /// existing `MultiUseSandbox`, and the batch is executed.
143
- // ///
144
- // /// After the batch is complete, the `MultiUseGuestCallContext` is done
145
- // /// and it is converted back to the underlying `MultiUseSandbox`
146
- // #[test]
147
- // fn test_multi_call_multi_thread() {
148
- // let (snd, recv) = sync_channel::<Vec<TestFuncCall>>(0);
149
- //
150
- // // create new receiver thread and on it, begin listening for
151
- // // requests to execute batches of calls
152
- // let recv_hdl = thread::spawn(move || {
153
- // let mut sbox: MultiUseSandbox = new_uninit().unwrap().evolve(Noop::default()).unwrap();
154
- // while let Ok(calls) = recv.recv() {
155
- // let mut ctx = sbox.new_call_context();
156
- // for call in calls {
157
- // let res = ctx
158
- // .call(call.func_name.as_str(), call.ret_type, call.params)
159
- // .unwrap();
160
- // assert_eq!(call.expected_ret, res);
161
- // }
162
- // sbox = ctx.finish().unwrap();
163
- // }
164
- // });
165
- //
166
- // // create new sender threads
167
- // let send_handles: Vec<JoinHandle<()>> = (0..10)
168
- // .map(|i| {
169
- // let sender = snd.clone();
170
- // thread::spawn(move || {
171
- // let calls: Vec<TestFuncCall> = vec![
172
- // TestFuncCall {
173
- // func_name: "Echo".to_string(),
174
- // ret_type: ReturnType::String,
175
- // params: Some(vec![ParameterValue::String(
176
- // format!("Hello {}", i).to_string(),
177
- // )]),
178
- // expected_ret: ReturnValue::String(format!("Hello {}", i).to_string()),
179
- // },
180
- // TestFuncCall {
181
- // func_name: "CallMalloc".to_string(),
182
- // ret_type: ReturnType::Int,
183
- // params: Some(vec![ParameterValue::Int(i + 2)]),
184
- // expected_ret: ReturnValue::Int(i + 2),
185
- // },
186
- // ];
187
- // sender.send(calls).unwrap();
188
- // })
189
- // })
190
- // .collect();
191
- //
192
- // for hdl in send_handles {
193
- // hdl.join().unwrap();
194
- // }
195
- // // after all sender threads are done, drop the sender itself
196
- // // so the receiver thread can exit. then, ensure the receiver
197
- // // thread has exited.
198
- // drop(snd);
199
- // recv_hdl.join().unwrap();
200
- // }
201
- //
202
- // pub struct TestSandbox {
203
- // sandbox: MultiUseSandbox,
204
- // }
205
- //
206
- // impl TestSandbox {
207
- // pub fn new() -> Self {
208
- // let sbox: MultiUseSandbox = new_uninit().unwrap().evolve(Noop::default()).unwrap();
209
- // Self { sandbox: sbox }
210
- // }
211
- // pub fn call_add_to_static_multiple_times(mut self, i: i32) -> Result<TestSandbox> {
212
- // let mut ctx = self.sandbox.new_call_context();
213
- // let mut sum: i32 = 0;
214
- // for n in 0..i {
215
- // let result = ctx.call(
216
- // "AddToStatic",
217
- // ReturnType::Int,
218
- // Some(vec![ParameterValue::Int(n)]),
219
- // );
220
- // sum += n;
221
- // println!("{:?}", result);
222
- // let result = result.unwrap();
223
- // assert_eq!(result, ReturnValue::Int(sum));
224
- // }
225
- // let result = ctx.finish();
226
- // assert!(result.is_ok());
227
- // self.sandbox = result.unwrap();
228
- // Ok(self)
229
- // }
230
- //
231
- // pub fn call_add_to_static(mut self, i: i32) -> Result<()> {
232
- // for n in 0..i {
233
- // let result = self.sandbox.call_guest_function_by_name(
234
- // "AddToStatic",
235
- // ReturnType::Int,
236
- // Some(vec![ParameterValue::Int(n)]),
237
- // );
238
- // println!("{:?}", result);
239
- // let result = result.unwrap();
240
- // assert_eq!(result, ReturnValue::Int(n));
241
- // }
242
- // Ok(())
243
- // }
244
- // }
245
- //
246
- // #[test]
247
- // fn ensure_multiusesandbox_multi_calls_dont_reset_state() {
248
- // let sandbox = TestSandbox::new();
249
- // let result = sandbox.call_add_to_static_multiple_times(5);
250
- // assert!(result.is_ok());
251
- // }
252
- //
253
- // #[test]
254
- // fn ensure_multiusesandbox_single_calls_do_reset_state() {
255
- // let sandbox = TestSandbox::new();
256
- // let result = sandbox.call_add_to_static(5);
257
- // assert!(result.is_ok());
258
- // }
259
- //
260
- // struct TestFuncCall {
261
- // func_name: String,
262
- // ret_type: ReturnType,
263
- // params: Option<Vec<ParameterValue>>,
264
- // expected_ret: ReturnValue,
265
- // }
266
- // }
107
+ # [ cfg ( test ) ]
108
+ mod tests {
109
+ use std :: sync :: mpsc :: sync_channel ;
110
+ use std:: thread :: { self , JoinHandle } ;
111
+
112
+ use hyperlight_common :: flatbuffer_wrappers :: function_types :: {
113
+ ParameterValue , ReturnType , ReturnValue ,
114
+ } ;
115
+ use hyperlight_testing :: simple_guest_as_string ;
116
+
117
+ use crate :: sandbox :: sandbox_builder :: SandboxBuilder ;
118
+ use crate :: sandbox_state:: sandbox:: EvolvableSandbox ;
119
+ use crate :: sandbox_state:: transition:: Noop ;
120
+ use crate :: { GuestBinary , MultiUseSandbox , Result , UninitializedSandbox } ;
121
+
122
+ fn new_uninit ( ) -> Result < UninitializedSandbox > {
123
+ let sandbox_builder =
124
+ SandboxBuilder :: new ( GuestBinary :: FilePath ( simple_guest_as_string ( ) ? ) ) ? ;
125
+
126
+ sandbox_builder . build ( )
127
+ }
128
+
129
+ /// Test to create a `MultiUseSandbox`, then call several guest functions
130
+ /// on it across different threads.
131
+ ///
132
+ /// This test works by passing messages between threads using Rust's
133
+ /// [mpsc crate](https://doc.rust-lang.org/std/sync/mpsc). Details of this
134
+ /// interaction are as follows.
135
+ ///
136
+ /// One thread acts as the receiver (AKA: consumer) and owns the
137
+ /// `MultiUseSandbox`. This receiver fields requests from N senders
138
+ /// (AKA: producers) to make batches of calls.
139
+ ///
140
+ /// Upon receipt of a message to execute a batch, a new
141
+ /// `MultiUseGuestCallContext` is created in the receiver thread from the
142
+ /// existing `MultiUseSandbox`, and the batch is executed.
143
+ ///
144
+ /// After the batch is complete, the `MultiUseGuestCallContext` is done
145
+ /// and it is converted back to the underlying `MultiUseSandbox`
146
+ #[ test]
147
+ fn test_multi_call_multi_thread ( ) {
148
+ let ( snd, recv) = sync_channel :: < Vec < TestFuncCall > > ( 0 ) ;
149
+
150
+ // create new receiver thread and on it, begin listening for
151
+ // requests to execute batches of calls
152
+ let recv_hdl = thread:: spawn ( move || {
153
+ let mut sbox: MultiUseSandbox = new_uninit ( ) . unwrap ( ) . evolve ( Noop :: default ( ) ) . unwrap ( ) ;
154
+ while let Ok ( calls) = recv. recv ( ) {
155
+ let mut ctx = sbox. new_call_context ( ) ;
156
+ for call in calls {
157
+ let res = ctx
158
+ . call ( call. func_name . as_str ( ) , call. ret_type , call. params )
159
+ . unwrap ( ) ;
160
+ assert_eq ! ( call. expected_ret, res) ;
161
+ }
162
+ sbox = ctx. finish ( ) . unwrap ( ) ;
163
+ }
164
+ } ) ;
165
+
166
+ // create new sender threads
167
+ let send_handles: Vec < JoinHandle < ( ) > > = ( 0 ..10 )
168
+ . map ( |i| {
169
+ let sender = snd. clone ( ) ;
170
+ thread:: spawn ( move || {
171
+ let calls: Vec < TestFuncCall > = vec ! [
172
+ TestFuncCall {
173
+ func_name: "Echo" . to_string( ) ,
174
+ ret_type: ReturnType :: String ,
175
+ params: Some ( vec![ ParameterValue :: String (
176
+ format!( "Hello {}" , i) . to_string( ) ,
177
+ ) ] ) ,
178
+ expected_ret: ReturnValue :: String ( format!( "Hello {}" , i) . to_string( ) ) ,
179
+ } ,
180
+ TestFuncCall {
181
+ func_name: "CallMalloc" . to_string( ) ,
182
+ ret_type: ReturnType :: Int ,
183
+ params: Some ( vec![ ParameterValue :: Int ( i + 2 ) ] ) ,
184
+ expected_ret: ReturnValue :: Int ( i + 2 ) ,
185
+ } ,
186
+ ] ;
187
+ sender. send ( calls) . unwrap ( ) ;
188
+ } )
189
+ } )
190
+ . collect ( ) ;
191
+
192
+ for hdl in send_handles {
193
+ hdl. join ( ) . unwrap ( ) ;
194
+ }
195
+ // after all sender threads are done, drop the sender itself
196
+ // so the receiver thread can exit. then, ensure the receiver
197
+ // thread has exited.
198
+ drop ( snd) ;
199
+ recv_hdl. join ( ) . unwrap ( ) ;
200
+ }
201
+
202
+ pub struct TestSandbox {
203
+ sandbox : MultiUseSandbox ,
204
+ }
205
+
206
+ impl TestSandbox {
207
+ pub fn new ( ) -> Self {
208
+ let sbox: MultiUseSandbox = new_uninit ( ) . unwrap ( ) . evolve ( Noop :: default ( ) ) . unwrap ( ) ;
209
+ Self { sandbox : sbox }
210
+ }
211
+ pub fn call_add_to_static_multiple_times ( mut self , i : i32 ) -> Result < TestSandbox > {
212
+ let mut ctx = self . sandbox . new_call_context ( ) ;
213
+ let mut sum: i32 = 0 ;
214
+ for n in 0 ..i {
215
+ let result = ctx. call (
216
+ "AddToStatic" ,
217
+ ReturnType :: Int ,
218
+ Some ( vec ! [ ParameterValue :: Int ( n) ] ) ,
219
+ ) ;
220
+ sum += n;
221
+ println ! ( "{:?}" , result) ;
222
+ let result = result. unwrap ( ) ;
223
+ assert_eq ! ( result, ReturnValue :: Int ( sum) ) ;
224
+ }
225
+ let result = ctx. finish ( ) ;
226
+ assert ! ( result. is_ok( ) ) ;
227
+ self . sandbox = result. unwrap ( ) ;
228
+ Ok ( self )
229
+ }
230
+
231
+ pub fn call_add_to_static ( mut self , i : i32 ) -> Result < ( ) > {
232
+ for n in 0 ..i {
233
+ let result = self . sandbox . call_guest_function_by_name (
234
+ "AddToStatic" ,
235
+ ReturnType :: Int ,
236
+ Some ( vec ! [ ParameterValue :: Int ( n) ] ) ,
237
+ ) ;
238
+ println ! ( "{:?}" , result) ;
239
+ let result = result. unwrap ( ) ;
240
+ assert_eq ! ( result, ReturnValue :: Int ( n) ) ;
241
+ }
242
+ Ok ( ( ) )
243
+ }
244
+ }
245
+
246
+ #[ test]
247
+ fn ensure_multiusesandbox_multi_calls_dont_reset_state ( ) {
248
+ let sandbox = TestSandbox :: new ( ) ;
249
+ let result = sandbox. call_add_to_static_multiple_times ( 5 ) ;
250
+ assert ! ( result. is_ok( ) ) ;
251
+ }
252
+
253
+ #[ test]
254
+ fn ensure_multiusesandbox_single_calls_do_reset_state ( ) {
255
+ let sandbox = TestSandbox :: new ( ) ;
256
+ let result = sandbox. call_add_to_static ( 5 ) ;
257
+ assert ! ( result. is_ok( ) ) ;
258
+ }
259
+
260
+ struct TestFuncCall {
261
+ func_name : String ,
262
+ ret_type : ReturnType ,
263
+ params : Option < Vec < ParameterValue > > ,
264
+ expected_ret : ReturnValue ,
265
+ }
266
+ }
0 commit comments