mod apps; mod err; use std::sync::Arc; use parking_lot::Mutex; use qsu::rt::RunCtx; use err::Error; const SVCNAME: &str = "svctest"; /// Returning an `Err(AppErr)` from `init()` should return it back to the /// application's initial call to kick off the runtime. #[test] fn error_from_sync_init() { let runctx = RunCtx::new(SVCNAME).test_mode(); // Prepare a server application context which keeps track of which callbacks // have been called let visited = Arc::new(Mutex::new(apps::Visited::default())); let svcevt_handler = Box::new(move |_msg| {}); let rt_handler = Box::new( apps::MySyncService { visited: Arc::clone(&visited), ..Default::default() } .fail_init() ); // Call RunCtx::run(), expecting an server application callback error. let Err(qsu::CbErr::SrvApp(errs)) = runctx.run_sync(svcevt_handler, rt_handler) else { panic!("Not expected Err(qsu::Error::SrvApp(_))"); }; // Verify that only init() failed assert!(errs.init.is_some()); assert!(errs.run.is_none()); assert!(errs.shutdown.is_none()); let Error::Hello(s) = errs.init.unwrap() else { panic!("Not expected Error::Hello"); }; assert_eq!(s, "From Sync::init()"); // Failing init should cause run() not to be called, but shutdown() should // sitll be called. let visited = Arc::into_inner(visited) .expect("Unable to into_inner Arc") .into_inner(); assert!(visited.init); assert!(!visited.run); assert!(visited.shutdown); } /// Returning an `Err(AppErr)` from `run()` should return it back to the /// application's initial call to kick off the runtime. #[test] fn error_from_sync_run() { let runctx = RunCtx::new(SVCNAME).test_mode(); // Prepare a server application context which keeps track of which callbacks // have been called let visited = Arc::new(Mutex::new(apps::Visited::default())); let svcevt_handler = Box::new(move |_msg| {}); let rt_handler = Box::new( apps::MySyncService { visited: Arc::clone(&visited), ..Default::default() } .fail_run() ); // Call RunCtx::run(), expecting an server application callback error. let Err(qsu::CbErr::SrvApp(errs)) = runctx.run_sync(svcevt_handler, rt_handler) else { panic!("Not expected Err(qsu::Error::SrvApp(_))"); }; // Verify that only run() failed assert!(errs.init.is_none()); assert!(errs.run.is_some()); assert!(errs.shutdown.is_none()); let Error::Hello(s) = errs.run.unwrap() else { panic!("Not expected Error::Hello"); }; assert_eq!(s, "From Sync::run()"); // Failing run should not hinder shutdown() from being called. let visited = Arc::into_inner(visited) .expect("Unable to into_inner Arc") .into_inner(); assert!(visited.init); assert!(visited.run); assert!(visited.shutdown); } /// Returning an `Err(AppErr)` from `run()` should return it back to the /// application's initial call to kick off the runtime. #[test] fn error_from_sync_shutdown() { let runctx = RunCtx::new(SVCNAME).test_mode(); // Prepare a server application context which keeps track of which callbacks // have been called let visited = Arc::new(Mutex::new(apps::Visited::default())); let svcevt_handler = Box::new(move |_msg| {}); let rt_handler = Box::new( apps::MySyncService { visited: Arc::clone(&visited), ..Default::default() } .fail_shutdown() ); // Call RunCtx::run(), expecting an server application callback error. let Err(qsu::CbErr::SrvApp(errs)) = runctx.run_sync(svcevt_handler, rt_handler) else { panic!("Not expected Err(qsu::Error::SrvApp(_))"); }; // Verify that only shutdown() failed assert!(errs.init.is_none()); assert!(errs.run.is_none()); assert!(errs.shutdown.is_some()); let Error::Hello(s) = errs.shutdown.unwrap() else { panic!("Not expected Error::Hello"); }; assert_eq!(s, "From Sync::shutdown()"); // All callbacks should have been visited let visited = Arc::into_inner(visited) .expect("Unable to into_inner Arc") .into_inner(); assert!(visited.init); assert!(visited.run); assert!(visited.shutdown); } /// Returning an `Err(AppErr)` from `init()` should return it back to the /// application's initial call to kick off the runtime. #[cfg(feature = "tokio")] #[test] fn error_from_tokio_init() { let runctx = RunCtx::new(SVCNAME).test_mode(); // Prepare a server application context which keeps track of which callbacks // have been called let visited = Arc::new(Mutex::new(apps::Visited::default())); let svcevt_handler = Box::new(move |_msg| {}); let rt_handler = Box::new( apps::MyTokioService { visited: Arc::clone(&visited), ..Default::default() } .fail_init() ); // Call RunCtx::run(), expecting an server application callback error. let Err(qsu::CbErr::SrvApp(errs)) = runctx.run_tokio(None, svcevt_handler, rt_handler) else { panic!("Not expected Err(qsu::Error::SrvApp(_))"); }; // Verify that only init() failed assert!(errs.init.is_some()); assert!(errs.run.is_none()); assert!(errs.shutdown.is_none()); let Error::Hello(s) = errs.init.unwrap() else { panic!("Not expected Error::Hello"); }; assert_eq!(s, "From Tokio::init()"); // Failing init should cause run() not to be called, but shutdown() should // sitll be called. let visited = Arc::into_inner(visited) .expect("Unable to into_inner Arc") .into_inner(); assert!(visited.init); assert!(!visited.run); assert!(visited.shutdown); } /// Returning an `Err(AppErr)` from `run()` should return it back to the /// application's initial call to kick off the runtime. #[cfg(feature = "tokio")] #[test] fn error_from_tokio_run() { let runctx = RunCtx::new(SVCNAME).test_mode(); // Prepare a server application context which keeps track of which callbacks // have been called let visited = Arc::new(Mutex::new(apps::Visited::default())); let svcevt_handler = Box::new(move |_msg| {}); let rt_handler = Box::new( apps::MyTokioService { visited: Arc::clone(&visited), ..Default::default() } .fail_run() ); // Call RunCtx::run(), expecting an server application callback error. let Err(qsu::CbErr::SrvApp(errs)) = runctx.run_tokio(None, svcevt_handler, rt_handler) else { panic!("Not expected Err(qsu::Error::SrvApp(_))"); }; // Verify that only run() failed assert!(errs.init.is_none()); assert!(errs.run.is_some()); assert!(errs.shutdown.is_none()); let Error::Hello(s) = errs.run.unwrap() else { panic!("Not expected Error::Hello"); }; assert_eq!(s, "From Tokio::run()"); // Failing run should not hinder shutdown() from being called. let visited = Arc::into_inner(visited) .expect("Unable to into_inner Arc") .into_inner(); assert!(visited.init); assert!(visited.run); assert!(visited.shutdown); } /// Returning an `Err(AppErr)` from `run()` should return it back to the /// application's initial call to kick off the runtime. #[cfg(feature = "tokio")] #[test] fn error_from_tokio_shutdown() { let runctx = RunCtx::new(SVCNAME).test_mode(); // Prepare a server application context which keeps track of which callbacks // have been called let visited = Arc::new(Mutex::new(apps::Visited::default())); let svcevt_handler = Box::new(move |_msg| {}); let rt_handler = Box::new( apps::MyTokioService { visited: Arc::clone(&visited), ..Default::default() } .fail_shutdown() ); // Call RunCtx::run(), expecting an server application callback error. let Err(qsu::CbErr::SrvApp(errs)) = runctx.run_tokio(None, svcevt_handler, rt_handler) else { panic!("Not expected Err(qsu::Error::SrvApp(_))"); }; // Verify that only shutdown() failed assert!(errs.init.is_none()); assert!(errs.run.is_none()); assert!(errs.shutdown.is_some()); let Error::Hello(s) = errs.shutdown.unwrap() else { panic!("Not expected Error::Hello"); }; assert_eq!(s, "From Tokio::shutdown()"); // All callbacks should have been visited let visited = Arc::into_inner(visited) .expect("Unable to into_inner Arc") .into_inner(); assert!(visited.init); assert!(visited.run); assert!(visited.shutdown); } /// Returning an `Err(AppErr)` from `init()` should return it back to the /// application's initial call to kick off the runtime. #[cfg(feature = "rocket")] #[test] fn error_from_rocket_init() { let runctx = RunCtx::new(SVCNAME).test_mode(); // Prepare a server application context which keeps track of which callbacks // have been called let visited = Arc::new(Mutex::new(apps::Visited::default())); let svcevt_handler = Box::new(move |_msg| {}); let rt_handler = Box::new( apps::MyRocketService { visited: Arc::clone(&visited), ..Default::default() } .fail_init() ); // Call RunCtx::run(), expecting an server application callback error. let Err(qsu::CbErr::SrvApp(errs)) = runctx.run_rocket(svcevt_handler, rt_handler) else { panic!("Not expected Err(qsu::Error::SrvApp(_))"); }; // Verify that only init() failed assert!(errs.init.is_some()); assert!(errs.run.is_none()); assert!(errs.shutdown.is_none()); let Error::Hello(s) = errs.init.unwrap() else { panic!("Not expected Error::Hello"); }; assert_eq!(s, "From Rocket::init()"); // Failing init should cause run() not to be called, but shutdown() should // sitll be called. let visited = Arc::into_inner(visited) .expect("Unable to into_inner Arc") .into_inner(); assert!(visited.init); assert!(!visited.run); assert!(visited.shutdown); } /// Returning an `Err(AppErr)` from `run()` should return it back to the /// application's initial call to kick off the runtime. #[cfg(feature = "rocket")] #[test] fn error_from_rocket_run() { let runctx = RunCtx::new(SVCNAME).log_init(false); // Prepare a server application context which keeps track of which callbacks // have been called let visited = Arc::new(Mutex::new(apps::Visited::default())); let svcevt_handler = Box::new(move |_msg| {}); let rt_handler = Box::new( apps::MyRocketService { visited: Arc::clone(&visited), ..Default::default() } .fail_run() ); // Call RunCtx::run(), expecting an server application callback error. let Err(qsu::CbErr::SrvApp(errs)) = runctx.run_rocket(svcevt_handler, rt_handler) else { panic!("Not expected Err(qsu::Error::SrvApp(_))"); }; // Verify that only run() failed assert!(errs.init.is_none()); assert!(errs.run.is_some()); assert!(errs.shutdown.is_none()); let Error::Hello(s) = errs.run.unwrap() else { panic!("Not expected Error::Hello"); }; assert_eq!(s, "From Rocket::run()"); // Failing run should not hinder shutdown() from being called. let visited = Arc::into_inner(visited) .expect("Unable to into_inner Arc") .into_inner(); assert!(visited.init); assert!(visited.run); assert!(visited.shutdown); } /// Returning an `Err(AppErr)` from `run()` should return it back to the /// application's initial call to kick off the runtime. #[cfg(feature = "rocket")] #[test] fn error_from_rocket_shutdown() { let runctx = RunCtx::new(SVCNAME).log_init(false); // Prepare a server application context which keeps track of which callbacks // have been called let visited = Arc::new(Mutex::new(apps::Visited::default())); let svcevt_handler = Box::new(move |_msg| {}); let rt_handler = Box::new( apps::MyRocketService { visited: Arc::clone(&visited), ..Default::default() } .fail_shutdown() ); // Call RunCtx::run(), expecting an server application callback error. let Err(qsu::CbErr::SrvApp(errs)) = runctx.run_rocket(svcevt_handler, rt_handler) else { panic!("Not expected Err(qsu::Error::SrvApp(_))"); }; // Verify that only shutdown() failed assert!(errs.init.is_none()); assert!(errs.run.is_none()); assert!(errs.shutdown.is_some()); let Error::Hello(s) = errs.shutdown.unwrap() else { panic!("Not expected Error::Hello"); }; assert_eq!(s, "From Rocket::shutdown()"); // All callbacks should have been visited let visited = Arc::into_inner(visited) .expect("Unable to into_inner Arc") .into_inner(); assert!(visited.init); assert!(visited.run); assert!(visited.shutdown); } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :