1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
//! Various helpers for Actix applications to use during testing. use std::cell::RefCell; use actix_rt::{System, SystemRunner}; use actix_service::Service; use futures::future::{lazy, Future, IntoFuture}; thread_local! { static RT: RefCell<Inner> = { RefCell::new(Inner(Some(System::builder().build()))) }; } struct Inner(Option<SystemRunner>); impl Inner { fn get_mut(&mut self) -> &mut SystemRunner { self.0.as_mut().unwrap() } } impl Drop for Inner { fn drop(&mut self) { std::mem::forget(self.0.take().unwrap()) } } /// Runs the provided future, blocking the current thread until the future /// completes. /// /// This function can be used to synchronously block the current thread /// until the provided `future` has resolved either successfully or with an /// error. The result of the future is then returned from this function /// call. /// /// Note that this function is intended to be used only for testing purpose. /// This function panics on nested call. pub fn block_on<F>(f: F) -> Result<F::Item, F::Error> where F: IntoFuture, { RT.with(move |rt| rt.borrow_mut().get_mut().block_on(f.into_future())) } /// Runs the provided function, blocking the current thread until the result /// future completes. /// /// This function can be used to synchronously block the current thread /// until the provided `future` has resolved either successfully or with an /// error. The result of the future is then returned from this function /// call. /// /// Note that this function is intended to be used only for testing purpose. /// This function panics on nested call. pub fn block_fn<F, R>(f: F) -> Result<R::Item, R::Error> where F: FnOnce() -> R, R: IntoFuture, { RT.with(move |rt| rt.borrow_mut().get_mut().block_on(lazy(f))) } /// Spawn future to the current test runtime. pub fn spawn<F>(fut: F) where F: Future<Item = (), Error = ()> + 'static, { run_on(move || { actix_rt::spawn(fut); }); } /// Runs the provided function, with runtime enabled. /// /// Note that this function is intended to be used only for testing purpose. /// This function panics on nested call. pub fn run_on<F, R>(f: F) -> R where F: FnOnce() -> R, { RT.with(move |rt| { rt.borrow_mut() .get_mut() .block_on(lazy(|| Ok::<_, ()>(f()))) }) .unwrap() } /// Calls service and waits for response future completion. /// /// ```rust,ignore /// use actix_web::{test, App, HttpResponse, http::StatusCode}; /// use actix_service::Service; /// /// #[test] /// fn test_response() { /// let mut app = test::init_service( /// App::new() /// .service(web::resource("/test").to(|| HttpResponse::Ok())) /// ); /// /// // Create request object /// let req = test::TestRequest::with_uri("/test").to_request(); /// /// // Call application /// let resp = test::call_service(&mut app, req); /// assert_eq!(resp.status(), StatusCode::OK); /// } /// ``` pub fn call_service<S, R>(app: &mut S, req: R) -> S::Response where S: Service<Request = R>, S::Error: std::fmt::Debug, { block_on(run_on(move || app.call(req))).unwrap() }