@@ -104,163 +104,163 @@ impl MultiUseGuestCallContext {
104104 }
105105}
106106
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