A now defunct web server engine that is notable for its overuse of unsafe code, the memory safety bugs caused by that, and its deletion by its creator.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1207 lines
37 KiB

  1. //! Various helpers for Actix applications to use during testing.
  2. use std::convert::TryFrom;
  3. use std::net::SocketAddr;
  4. use std::rc::Rc;
  5. use std::sync::mpsc;
  6. use std::{fmt, net, thread, time};
  7. use actix_codec::{AsyncRead, AsyncWrite, Framed};
  8. use actix_http::http::header::{ContentType, Header, HeaderName, IntoHeaderValue};
  9. use actix_http::http::{Error as HttpError, Method, StatusCode, Uri, Version};
  10. use actix_http::test::TestRequest as HttpTestRequest;
  11. use actix_http::{cookie::Cookie, ws, Extensions, HttpService, Request};
  12. use actix_router::{Path, ResourceDef, Url};
  13. use actix_rt::System;
  14. use actix_server::Server;
  15. use actix_service::{
  16. map_config, IntoService, IntoServiceFactory, Service, ServiceFactory,
  17. };
  18. use awc::error::PayloadError;
  19. use awc::{Client, ClientRequest, ClientResponse, Connector};
  20. use bytes::{Bytes, BytesMut};
  21. use futures::future::ok;
  22. use futures::stream::{Stream, StreamExt};
  23. use net2::TcpBuilder;
  24. use serde::de::DeserializeOwned;
  25. use serde::Serialize;
  26. use serde_json;
  27. pub use actix_http::test::TestBuffer;
  28. use crate::config::AppConfig;
  29. use crate::data::Data;
  30. use crate::dev::{Body, MessageBody, Payload};
  31. use crate::request::HttpRequestPool;
  32. use crate::rmap::ResourceMap;
  33. use crate::service::{ServiceRequest, ServiceResponse};
  34. use crate::{Error, HttpRequest, HttpResponse};
  35. /// Create service that always responds with `HttpResponse::Ok()`
  36. pub fn ok_service(
  37. ) -> impl Service<Request = ServiceRequest, Response = ServiceResponse<Body>, Error = Error>
  38. {
  39. default_service(StatusCode::OK)
  40. }
  41. /// Create service that responds with response with specified status code
  42. pub fn default_service(
  43. status_code: StatusCode,
  44. ) -> impl Service<Request = ServiceRequest, Response = ServiceResponse<Body>, Error = Error>
  45. {
  46. (move |req: ServiceRequest| {
  47. ok(req.into_response(HttpResponse::build(status_code).finish()))
  48. })
  49. .into_service()
  50. }
  51. /// This method accepts application builder instance, and constructs
  52. /// service.
  53. ///
  54. /// ```rust
  55. /// use actix_service::Service;
  56. /// use actix_web::{test, web, App, HttpResponse, http::StatusCode};
  57. ///
  58. /// #[actix_rt::test]
  59. /// async fn test_init_service() {
  60. /// let mut app = test::init_service(
  61. /// App::new()
  62. /// .service(web::resource("/test").to(|| async { HttpResponse::Ok() }))
  63. /// ).await;
  64. ///
  65. /// // Create request object
  66. /// let req = test::TestRequest::with_uri("/test").to_request();
  67. ///
  68. /// // Execute application
  69. /// let resp = app.call(req).await.unwrap();
  70. /// assert_eq!(resp.status(), StatusCode::OK);
  71. /// }
  72. /// ```
  73. pub async fn init_service<R, S, B, E>(
  74. app: R,
  75. ) -> impl Service<Request = Request, Response = ServiceResponse<B>, Error = E>
  76. where
  77. R: IntoServiceFactory<S>,
  78. S: ServiceFactory<
  79. Config = AppConfig,
  80. Request = Request,
  81. Response = ServiceResponse<B>,
  82. Error = E,
  83. >,
  84. S::InitError: std::fmt::Debug,
  85. {
  86. let srv = app.into_factory();
  87. srv.new_service(AppConfig::default()).await.unwrap()
  88. }
  89. /// Calls service and waits for response future completion.
  90. ///
  91. /// ```rust
  92. /// use actix_web::{test, App, HttpResponse, http::StatusCode};
  93. /// use actix_service::Service;
  94. ///
  95. /// #[test]
  96. /// fn test_response() {
  97. /// let mut app = test::init_service(
  98. /// App::new()
  99. /// .service(web::resource("/test").to(|| async {
  100. /// HttpResponse::Ok()
  101. /// }))
  102. /// ).await;
  103. ///
  104. /// // Create request object
  105. /// let req = test::TestRequest::with_uri("/test").to_request();
  106. ///
  107. /// // Call application
  108. /// let resp = test::call_service(&mut app, req).await;
  109. /// assert_eq!(resp.status(), StatusCode::OK);
  110. /// }
  111. /// ```
  112. pub async fn call_service<S, R, B, E>(app: &mut S, req: R) -> S::Response
  113. where
  114. S: Service<Request = R, Response = ServiceResponse<B>, Error = E>,
  115. E: std::fmt::Debug,
  116. {
  117. app.call(req).await.unwrap()
  118. }
  119. /// Helper function that returns a response body of a TestRequest
  120. ///
  121. /// ```rust
  122. /// use actix_web::{test, web, App, HttpResponse, http::header};
  123. /// use bytes::Bytes;
  124. ///
  125. /// #[actix_rt::test]
  126. /// async fn test_index() {
  127. /// let mut app = test::init_service(
  128. /// App::new().service(
  129. /// web::resource("/index.html")
  130. /// .route(web::post().to(|| async {
  131. /// HttpResponse::Ok().body("welcome!")
  132. /// })))
  133. /// ).await;
  134. ///
  135. /// let req = test::TestRequest::post()
  136. /// .uri("/index.html")
  137. /// .header(header::CONTENT_TYPE, "application/json")
  138. /// .to_request();
  139. ///
  140. /// let result = test::read_response(&mut app, req).await;
  141. /// assert_eq!(result, Bytes::from_static(b"welcome!"));
  142. /// }
  143. /// ```
  144. pub async fn read_response<S, B>(app: &mut S, req: Request) -> Bytes
  145. where
  146. S: Service<Request = Request, Response = ServiceResponse<B>, Error = Error>,
  147. B: MessageBody,
  148. {
  149. let mut resp = app
  150. .call(req)
  151. .await
  152. .unwrap_or_else(|_| panic!("read_response failed at application call"));
  153. let mut body = resp.take_body();
  154. let mut bytes = BytesMut::new();
  155. while let Some(item) = body.next().await {
  156. bytes.extend_from_slice(&item.unwrap());
  157. }
  158. bytes.freeze()
  159. }
  160. /// Helper function that returns a response body of a ServiceResponse.
  161. ///
  162. /// ```rust
  163. /// use actix_web::{test, web, App, HttpResponse, http::header};
  164. /// use bytes::Bytes;
  165. ///
  166. /// #[actix_rt::test]
  167. /// async fn test_index() {
  168. /// let mut app = test::init_service(
  169. /// App::new().service(
  170. /// web::resource("/index.html")
  171. /// .route(web::post().to(|| async {
  172. /// HttpResponse::Ok().body("welcome!")
  173. /// })))
  174. /// ).await;
  175. ///
  176. /// let req = test::TestRequest::post()
  177. /// .uri("/index.html")
  178. /// .header(header::CONTENT_TYPE, "application/json")
  179. /// .to_request();
  180. ///
  181. /// let resp = test::call_service(&mut app, req).await;
  182. /// let result = test::read_body(resp);
  183. /// assert_eq!(result, Bytes::from_static(b"welcome!"));
  184. /// }
  185. /// ```
  186. pub async fn read_body<B>(mut res: ServiceResponse<B>) -> Bytes
  187. where
  188. B: MessageBody,
  189. {
  190. let mut body = res.take_body();
  191. let mut bytes = BytesMut::new();
  192. while let Some(item) = body.next().await {
  193. bytes.extend_from_slice(&item.unwrap());
  194. }
  195. bytes.freeze()
  196. }
  197. pub async fn load_stream<S>(mut stream: S) -> Result<Bytes, Error>
  198. where
  199. S: Stream<Item = Result<Bytes, Error>> + Unpin,
  200. {
  201. let mut data = BytesMut::new();
  202. while let Some(item) = stream.next().await {
  203. data.extend_from_slice(&item?);
  204. }
  205. Ok(data.freeze())
  206. }
  207. /// Helper function that returns a deserialized response body of a TestRequest
  208. ///
  209. /// ```rust
  210. /// use actix_web::{App, test, web, HttpResponse, http::header};
  211. /// use serde::{Serialize, Deserialize};
  212. ///
  213. /// #[derive(Serialize, Deserialize)]
  214. /// pub struct Person {
  215. /// id: String,
  216. /// name: String
  217. /// }
  218. ///
  219. /// #[actix_rt::test]
  220. /// async fn test_add_person() {
  221. /// let mut app = test::init_service(
  222. /// App::new().service(
  223. /// web::resource("/people")
  224. /// .route(web::post().to(|person: web::Json<Person>| async {
  225. /// HttpResponse::Ok()
  226. /// .json(person.into_inner())})
  227. /// ))
  228. /// ).await;
  229. ///
  230. /// let payload = r#"{"id":"12345","name":"User name"}"#.as_bytes();
  231. ///
  232. /// let req = test::TestRequest::post()
  233. /// .uri("/people")
  234. /// .header(header::CONTENT_TYPE, "application/json")
  235. /// .set_payload(payload)
  236. /// .to_request();
  237. ///
  238. /// let result: Person = test::read_response_json(&mut app, req).await;
  239. /// }
  240. /// ```
  241. pub async fn read_response_json<S, B, T>(app: &mut S, req: Request) -> T
  242. where
  243. S: Service<Request = Request, Response = ServiceResponse<B>, Error = Error>,
  244. B: MessageBody,
  245. T: DeserializeOwned,
  246. {
  247. let body = read_response(app, req).await;
  248. serde_json::from_slice(&body)
  249. .unwrap_or_else(|_| panic!("read_response_json failed during deserialization"))
  250. }
  251. /// Test `Request` builder.
  252. ///
  253. /// For unit testing, actix provides a request builder type and a simple handler runner. TestRequest implements a builder-like pattern.
  254. /// You can generate various types of request via TestRequest's methods:
  255. /// * `TestRequest::to_request` creates `actix_http::Request` instance.
  256. /// * `TestRequest::to_srv_request` creates `ServiceRequest` instance, which is used for testing middlewares and chain adapters.
  257. /// * `TestRequest::to_srv_response` creates `ServiceResponse` instance.
  258. /// * `TestRequest::to_http_request` creates `HttpRequest` instance, which is used for testing handlers.
  259. ///
  260. /// ```rust
  261. /// use actix_web::{test, HttpRequest, HttpResponse, HttpMessage};
  262. /// use actix_web::http::{header, StatusCode};
  263. ///
  264. /// async fn index(req: HttpRequest) -> HttpResponse {
  265. /// if let Some(hdr) = req.headers().get(header::CONTENT_TYPE) {
  266. /// HttpResponse::Ok().into()
  267. /// } else {
  268. /// HttpResponse::BadRequest().into()
  269. /// }
  270. /// }
  271. ///
  272. /// #[test]
  273. /// fn test_index() {
  274. /// let req = test::TestRequest::with_header("content-type", "text/plain")
  275. /// .to_http_request();
  276. ///
  277. /// let resp = index(req).await.unwrap();
  278. /// assert_eq!(resp.status(), StatusCode::OK);
  279. ///
  280. /// let req = test::TestRequest::default().to_http_request();
  281. /// let resp = index(req).await.unwrap();
  282. /// assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
  283. /// }
  284. /// ```
  285. pub struct TestRequest {
  286. req: HttpTestRequest,
  287. rmap: ResourceMap,
  288. config: AppConfig,
  289. path: Path<Url>,
  290. peer_addr: Option<SocketAddr>,
  291. app_data: Extensions,
  292. }
  293. impl Default for TestRequest {
  294. fn default() -> TestRequest {
  295. TestRequest {
  296. req: HttpTestRequest::default(),
  297. rmap: ResourceMap::new(ResourceDef::new("")),
  298. config: AppConfig::default(),
  299. path: Path::new(Url::new(Uri::default())),
  300. peer_addr: None,
  301. app_data: Extensions::new(),
  302. }
  303. }
  304. }
  305. #[allow(clippy::wrong_self_convention)]
  306. impl TestRequest {
  307. /// Create TestRequest and set request uri
  308. pub fn with_uri(path: &str) -> TestRequest {
  309. TestRequest::default().uri(path)
  310. }
  311. /// Create TestRequest and set header
  312. pub fn with_hdr<H: Header>(hdr: H) -> TestRequest {
  313. TestRequest::default().set(hdr)
  314. }
  315. /// Create TestRequest and set header
  316. pub fn with_header<K, V>(key: K, value: V) -> TestRequest
  317. where
  318. HeaderName: TryFrom<K>,
  319. <HeaderName as TryFrom<K>>::Error: Into<HttpError>,
  320. V: IntoHeaderValue,
  321. {
  322. TestRequest::default().header(key, value)
  323. }
  324. /// Create TestRequest and set method to `Method::GET`
  325. pub fn get() -> TestRequest {
  326. TestRequest::default().method(Method::GET)
  327. }
  328. /// Create TestRequest and set method to `Method::POST`
  329. pub fn post() -> TestRequest {
  330. TestRequest::default().method(Method::POST)
  331. }
  332. /// Create TestRequest and set method to `Method::PUT`
  333. pub fn put() -> TestRequest {
  334. TestRequest::default().method(Method::PUT)
  335. }
  336. /// Create TestRequest and set method to `Method::PATCH`
  337. pub fn patch() -> TestRequest {
  338. TestRequest::default().method(Method::PATCH)
  339. }
  340. /// Create TestRequest and set method to `Method::DELETE`
  341. pub fn delete() -> TestRequest {
  342. TestRequest::default().method(Method::DELETE)
  343. }
  344. /// Set HTTP version of this request
  345. pub fn version(mut self, ver: Version) -> Self {
  346. self.req.version(ver);
  347. self
  348. }
  349. /// Set HTTP method of this request
  350. pub fn method(mut self, meth: Method) -> Self {
  351. self.req.method(meth);
  352. self
  353. }
  354. /// Set HTTP Uri of this request
  355. pub fn uri(mut self, path: &str) -> Self {
  356. self.req.uri(path);
  357. self
  358. }
  359. /// Set a header
  360. pub fn set<H: Header>(mut self, hdr: H) -> Self {
  361. self.req.set(hdr);
  362. self
  363. }
  364. /// Set a header
  365. pub fn header<K, V>(mut self, key: K, value: V) -> Self
  366. where
  367. HeaderName: TryFrom<K>,
  368. <HeaderName as TryFrom<K>>::Error: Into<HttpError>,
  369. V: IntoHeaderValue,
  370. {
  371. self.req.header(key, value);
  372. self
  373. }
  374. /// Set cookie for this request
  375. pub fn cookie(mut self, cookie: Cookie<'_>) -> Self {
  376. self.req.cookie(cookie);
  377. self
  378. }
  379. /// Set request path pattern parameter
  380. pub fn param(mut self, name: &'static str, value: &'static str) -> Self {
  381. self.path.add_static(name, value);
  382. self
  383. }
  384. /// Set peer addr
  385. pub fn peer_addr(mut self, addr: SocketAddr) -> Self {
  386. self.peer_addr = Some(addr);
  387. self
  388. }
  389. /// Set request payload
  390. pub fn set_payload<B: Into<Bytes>>(mut self, data: B) -> Self {
  391. self.req.set_payload(data);
  392. self
  393. }
  394. /// Serialize `data` to a URL encoded form and set it as the request payload. The `Content-Type`
  395. /// header is set to `application/x-www-form-urlencoded`.
  396. pub fn set_form<T: Serialize>(mut self, data: &T) -> Self {
  397. let bytes = serde_urlencoded::to_string(data)
  398. .expect("Failed to serialize test data as a urlencoded form");
  399. self.req.set_payload(bytes);
  400. self.req.set(ContentType::form_url_encoded());
  401. self
  402. }
  403. /// Serialize `data` to JSON and set it as the request payload. The `Content-Type` header is
  404. /// set to `application/json`.
  405. pub fn set_json<T: Serialize>(mut self, data: &T) -> Self {
  406. let bytes =
  407. serde_json::to_string(data).expect("Failed to serialize test data to json");
  408. self.req.set_payload(bytes);
  409. self.req.set(ContentType::json());
  410. self
  411. }
  412. /// Set application data. This is equivalent of `App::data()` method
  413. /// for testing purpose.
  414. pub fn data<T: 'static>(mut self, data: T) -> Self {
  415. self.app_data.insert(Data::new(data));
  416. self
  417. }
  418. /// Set application data. This is equivalent of `App::app_data()` method
  419. /// for testing purpose.
  420. pub fn app_data<T: 'static>(mut self, data: T) -> Self {
  421. self.app_data.insert(data);
  422. self
  423. }
  424. #[cfg(test)]
  425. /// Set request config
  426. pub(crate) fn rmap(mut self, rmap: ResourceMap) -> Self {
  427. self.rmap = rmap;
  428. self
  429. }
  430. /// Complete request creation and generate `Request` instance
  431. pub fn to_request(mut self) -> Request {
  432. let mut req = self.req.finish();
  433. req.head_mut().peer_addr = self.peer_addr;
  434. req
  435. }
  436. /// Complete request creation and generate `ServiceRequest` instance
  437. pub fn to_srv_request(mut self) -> ServiceRequest {
  438. let (mut head, payload) = self.req.finish().into_parts();
  439. head.peer_addr = self.peer_addr;
  440. self.path.get_mut().update(&head.uri);
  441. ServiceRequest::new(HttpRequest::new(
  442. self.path,
  443. head,
  444. payload,
  445. Rc::new(self.rmap),
  446. self.config.clone(),
  447. Rc::new(self.app_data),
  448. HttpRequestPool::create(),
  449. ))
  450. }
  451. /// Complete request creation and generate `ServiceResponse` instance
  452. pub fn to_srv_response<B>(self, res: HttpResponse<B>) -> ServiceResponse<B> {
  453. self.to_srv_request().into_response(res)
  454. }
  455. /// Complete request creation and generate `HttpRequest` instance
  456. pub fn to_http_request(mut self) -> HttpRequest {
  457. let (mut head, payload) = self.req.finish().into_parts();
  458. head.peer_addr = self.peer_addr;
  459. self.path.get_mut().update(&head.uri);
  460. HttpRequest::new(
  461. self.path,
  462. head,
  463. payload,
  464. Rc::new(self.rmap),
  465. self.config.clone(),
  466. Rc::new(self.app_data),
  467. HttpRequestPool::create(),
  468. )
  469. }
  470. /// Complete request creation and generate `HttpRequest` and `Payload` instances
  471. pub fn to_http_parts(mut self) -> (HttpRequest, Payload) {
  472. let (mut head, payload) = self.req.finish().into_parts();
  473. head.peer_addr = self.peer_addr;
  474. self.path.get_mut().update(&head.uri);
  475. let req = HttpRequest::new(
  476. self.path,
  477. head,
  478. Payload::None,
  479. Rc::new(self.rmap),
  480. self.config.clone(),
  481. Rc::new(self.app_data),
  482. HttpRequestPool::create(),
  483. );
  484. (req, payload)
  485. }
  486. }
  487. /// Start test server with default configuration
  488. ///
  489. /// Test server is very simple server that simplify process of writing
  490. /// integration tests cases for actix web applications.
  491. ///
  492. /// # Examples
  493. ///
  494. /// ```rust
  495. /// use actix_web::{web, test, App, HttpResponse, Error};
  496. ///
  497. /// async fn my_handler() -> Result<HttpResponse, Error> {
  498. /// Ok(HttpResponse::Ok().into())
  499. /// }
  500. ///
  501. /// #[actix_rt::test]
  502. /// async fn test_example() {
  503. /// let mut srv = test::start(
  504. /// || App::new().service(
  505. /// web::resource("/").to(my_handler))
  506. /// );
  507. ///
  508. /// let req = srv.get("/");
  509. /// let response = req.send().await.unwrap();
  510. /// assert!(response.status().is_success());
  511. /// }
  512. /// ```
  513. pub fn start<F, I, S, B>(factory: F) -> TestServer
  514. where
  515. F: Fn() -> I + Send + Clone + 'static,
  516. I: IntoServiceFactory<S>,
  517. S: ServiceFactory<Config = AppConfig, Request = Request> + 'static,
  518. S::Error: Into<Error> + 'static,
  519. S::InitError: fmt::Debug,
  520. S::Response: Into<HttpResponse<B>> + 'static,
  521. <S::Service as Service>::Future: 'static,
  522. B: MessageBody + 'static,
  523. {
  524. start_with(TestServerConfig::default(), factory)
  525. }
  526. /// Start test server with custom configuration
  527. ///
  528. /// Test server could be configured in different ways, for details check
  529. /// `TestServerConfig` docs.
  530. ///
  531. /// # Examples
  532. ///
  533. /// ```rust
  534. /// use actix_web::{web, test, App, HttpResponse, Error};
  535. ///
  536. /// async fn my_handler() -> Result<HttpResponse, Error> {
  537. /// Ok(HttpResponse::Ok().into())
  538. /// }
  539. ///
  540. /// #[actix_rt::test]
  541. /// async fn test_example() {
  542. /// let mut srv = test::start_with(test::config().h1(), ||
  543. /// App::new().service(web::resource("/").to(my_handler))
  544. /// );
  545. ///
  546. /// let req = srv.get("/");
  547. /// let response = req.send().await.unwrap();
  548. /// assert!(response.status().is_success());
  549. /// }
  550. /// ```
  551. pub fn start_with<F, I, S, B>(cfg: TestServerConfig, factory: F) -> TestServer
  552. where
  553. F: Fn() -> I + Send + Clone + 'static,
  554. I: IntoServiceFactory<S>,
  555. S: ServiceFactory<Config = AppConfig, Request = Request> + 'static,
  556. S::Error: Into<Error> + 'static,
  557. S::InitError: fmt::Debug,
  558. S::Response: Into<HttpResponse<B>> + 'static,
  559. <S::Service as Service>::Future: 'static,
  560. B: MessageBody + 'static,
  561. {
  562. let (tx, rx) = mpsc::channel();
  563. let ssl = match cfg.stream {
  564. StreamType::Tcp => false,
  565. #[cfg(feature = "openssl")]
  566. StreamType::Openssl(_) => true,
  567. #[cfg(feature = "rustls")]
  568. StreamType::Rustls(_) => true,
  569. };
  570. // run server in separate thread
  571. thread::spawn(move || {
  572. let sys = System::new("actix-test-server");
  573. let tcp = net::TcpListener::bind("127.0.0.1:0").unwrap();
  574. let local_addr = tcp.local_addr().unwrap();
  575. let factory = factory.clone();
  576. let cfg = cfg.clone();
  577. let ctimeout = cfg.client_timeout;
  578. let builder = Server::build().workers(1).disable_signals();
  579. match cfg.stream {
  580. StreamType::Tcp => match cfg.tp {
  581. HttpVer::Http1 => builder.listen("test", tcp, move || {
  582. let cfg =
  583. AppConfig::new(false, local_addr, format!("{}", local_addr));
  584. HttpService::build()
  585. .client_timeout(ctimeout)
  586. .h1(map_config(factory(), move |_| cfg.clone()))
  587. .tcp()
  588. }),
  589. HttpVer::Http2 => builder.listen("test", tcp, move || {
  590. let cfg =
  591. AppConfig::new(false, local_addr, format!("{}", local_addr));
  592. HttpService::build()
  593. .client_timeout(ctimeout)
  594. .h2(map_config(factory(), move |_| cfg.clone()))
  595. .tcp()
  596. }),
  597. HttpVer::Both => builder.listen("test", tcp, move || {
  598. let cfg =
  599. AppConfig::new(false, local_addr, format!("{}", local_addr));
  600. HttpService::build()
  601. .client_timeout(ctimeout)
  602. .finish(map_config(factory(), move |_| cfg.clone()))
  603. .tcp()
  604. }),
  605. },
  606. #[cfg(feature = "openssl")]
  607. StreamType::Openssl(acceptor) => match cfg.tp {
  608. HttpVer::Http1 => builder.listen("test", tcp, move || {
  609. let cfg =
  610. AppConfig::new(true, local_addr, format!("{}", local_addr));
  611. HttpService::build()
  612. .client_timeout(ctimeout)
  613. .h1(map_config(factory(), move |_| cfg.clone()))
  614. .openssl(acceptor.clone())
  615. }),
  616. HttpVer::Http2 => builder.listen("test", tcp, move || {
  617. let cfg =
  618. AppConfig::new(true, local_addr, format!("{}", local_addr));
  619. HttpService::build()
  620. .client_timeout(ctimeout)
  621. .h2(map_config(factory(), move |_| cfg.clone()))
  622. .openssl(acceptor.clone())
  623. }),
  624. HttpVer::Both => builder.listen("test", tcp, move || {
  625. let cfg =
  626. AppConfig::new(true, local_addr, format!("{}", local_addr));
  627. HttpService::build()
  628. .client_timeout(ctimeout)
  629. .finish(map_config(factory(), move |_| cfg.clone()))
  630. .openssl(acceptor.clone())
  631. }),
  632. },
  633. #[cfg(feature = "rustls")]
  634. StreamType::Rustls(config) => match cfg.tp {
  635. HttpVer::Http1 => builder.listen("test", tcp, move || {
  636. let cfg =
  637. AppConfig::new(true, local_addr, format!("{}", local_addr));
  638. HttpService::build()
  639. .client_timeout(ctimeout)
  640. .h1(map_config(factory(), move |_| cfg.clone()))
  641. .rustls(config.clone())
  642. }),
  643. HttpVer::Http2 => builder.listen("test", tcp, move || {
  644. let cfg =
  645. AppConfig::new(true, local_addr, format!("{}", local_addr));
  646. HttpService::build()
  647. .client_timeout(ctimeout)
  648. .h2(map_config(factory(), move |_| cfg.clone()))
  649. .rustls(config.clone())
  650. }),
  651. HttpVer::Both => builder.listen("test", tcp, move || {
  652. let cfg =
  653. AppConfig::new(true, local_addr, format!("{}", local_addr));
  654. HttpService::build()
  655. .client_timeout(ctimeout)
  656. .finish(map_config(factory(), move |_| cfg.clone()))
  657. .rustls(config.clone())
  658. }),
  659. },
  660. }
  661. .unwrap()
  662. .start();
  663. tx.send((System::current(), local_addr)).unwrap();
  664. sys.run()
  665. });
  666. let (system, addr) = rx.recv().unwrap();
  667. let client = {
  668. let connector = {
  669. #[cfg(feature = "openssl")]
  670. {
  671. use open_ssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
  672. let mut builder = SslConnector::builder(SslMethod::tls()).unwrap();
  673. builder.set_verify(SslVerifyMode::NONE);
  674. let _ = builder
  675. .set_alpn_protos(b"\x02h2\x08http/1.1")
  676. .map_err(|e| log::error!("Can not set alpn protocol: {:?}", e));
  677. Connector::new()
  678. .conn_lifetime(time::Duration::from_secs(0))
  679. .timeout(time::Duration::from_millis(3000))
  680. .ssl(builder.build())
  681. .finish()
  682. }
  683. #[cfg(not(feature = "openssl"))]
  684. {
  685. Connector::new()
  686. .conn_lifetime(time::Duration::from_secs(0))
  687. .timeout(time::Duration::from_millis(3000))
  688. .finish()
  689. }
  690. };
  691. Client::build().connector(connector).finish()
  692. };
  693. TestServer {
  694. ssl,
  695. addr,
  696. client,
  697. system,
  698. }
  699. }
  700. #[derive(Clone)]
  701. pub struct TestServerConfig {
  702. tp: HttpVer,
  703. stream: StreamType,
  704. client_timeout: u64,
  705. }
  706. #[derive(Clone)]
  707. enum HttpVer {
  708. Http1,
  709. Http2,
  710. Both,
  711. }
  712. #[derive(Clone)]
  713. enum StreamType {
  714. Tcp,
  715. #[cfg(feature = "openssl")]
  716. Openssl(open_ssl::ssl::SslAcceptor),
  717. #[cfg(feature = "rustls")]
  718. Rustls(rust_tls::ServerConfig),
  719. }
  720. impl Default for TestServerConfig {
  721. fn default() -> Self {
  722. TestServerConfig::new()
  723. }
  724. }
  725. /// Create default test server config
  726. pub fn config() -> TestServerConfig {
  727. TestServerConfig::new()
  728. }
  729. impl TestServerConfig {
  730. /// Create default server configuration
  731. pub(crate) fn new() -> TestServerConfig {
  732. TestServerConfig {
  733. tp: HttpVer::Both,
  734. stream: StreamType::Tcp,
  735. client_timeout: 5000,
  736. }
  737. }
  738. /// Start http/1.1 server only
  739. pub fn h1(mut self) -> Self {
  740. self.tp = HttpVer::Http1;
  741. self
  742. }
  743. /// Start http/2 server only
  744. pub fn h2(mut self) -> Self {
  745. self.tp = HttpVer::Http2;
  746. self
  747. }
  748. /// Start openssl server
  749. #[cfg(feature = "openssl")]
  750. pub fn openssl(mut self, acceptor: open_ssl::ssl::SslAcceptor) -> Self {
  751. self.stream = StreamType::Openssl(acceptor);
  752. self
  753. }
  754. /// Start rustls server
  755. #[cfg(feature = "rustls")]
  756. pub fn rustls(mut self, config: rust_tls::ServerConfig) -> Self {
  757. self.stream = StreamType::Rustls(config);
  758. self
  759. }
  760. /// Set server client timeout in milliseconds for first request.
  761. pub fn client_timeout(mut self, val: u64) -> Self {
  762. self.client_timeout = val;
  763. self
  764. }
  765. }
  766. /// Get first available unused address
  767. pub fn unused_addr() -> net::SocketAddr {
  768. let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap();
  769. let socket = TcpBuilder::new_v4().unwrap();
  770. socket.bind(&addr).unwrap();
  771. socket.reuse_address(true).unwrap();
  772. let tcp = socket.to_tcp_listener().unwrap();
  773. tcp.local_addr().unwrap()
  774. }
  775. /// Test server controller
  776. pub struct TestServer {
  777. addr: net::SocketAddr,
  778. client: awc::Client,
  779. system: actix_rt::System,
  780. ssl: bool,
  781. }
  782. impl TestServer {
  783. /// Construct test server url
  784. pub fn addr(&self) -> net::SocketAddr {
  785. self.addr
  786. }
  787. /// Construct test server url
  788. pub fn url(&self, uri: &str) -> String {
  789. let scheme = if self.ssl { "https" } else { "http" };
  790. if uri.starts_with('/') {
  791. format!("{}://localhost:{}{}", scheme, self.addr.port(), uri)
  792. } else {
  793. format!("{}://localhost:{}/{}", scheme, self.addr.port(), uri)
  794. }
  795. }
  796. /// Create `GET` request
  797. pub fn get<S: AsRef<str>>(&self, path: S) -> ClientRequest {
  798. self.client.get(self.url(path.as_ref()).as_str())
  799. }
  800. /// Create `POST` request
  801. pub fn post<S: AsRef<str>>(&self, path: S) -> ClientRequest {
  802. self.client.post(self.url(path.as_ref()).as_str())
  803. }
  804. /// Create `HEAD` request
  805. pub fn head<S: AsRef<str>>(&self, path: S) -> ClientRequest {
  806. self.client.head(self.url(path.as_ref()).as_str())
  807. }
  808. /// Create `PUT` request
  809. pub fn put<S: AsRef<str>>(&self, path: S) -> ClientRequest {
  810. self.client.put(self.url(path.as_ref()).as_str())
  811. }
  812. /// Create `PATCH` request
  813. pub fn patch<S: AsRef<str>>(&self, path: S) -> ClientRequest {
  814. self.client.patch(self.url(path.as_ref()).as_str())
  815. }
  816. /// Create `DELETE` request
  817. pub fn delete<S: AsRef<str>>(&self, path: S) -> ClientRequest {
  818. self.client.delete(self.url(path.as_ref()).as_str())
  819. }
  820. /// Create `OPTIONS` request
  821. pub fn options<S: AsRef<str>>(&self, path: S) -> ClientRequest {
  822. self.client.options(self.url(path.as_ref()).as_str())
  823. }
  824. /// Connect to test http server
  825. pub fn request<S: AsRef<str>>(&self, method: Method, path: S) -> ClientRequest {
  826. self.client.request(method, path.as_ref())
  827. }
  828. pub async fn load_body<S>(
  829. &mut self,
  830. mut response: ClientResponse<S>,
  831. ) -> Result<Bytes, PayloadError>
  832. where
  833. S: Stream<Item = Result<Bytes, PayloadError>> + Unpin + 'static,
  834. {
  835. response.body().limit(10_485_760).await
  836. }
  837. /// Connect to websocket server at a given path
  838. pub async fn ws_at(
  839. &mut self,
  840. path: &str,
  841. ) -> Result<Framed<impl AsyncRead + AsyncWrite, ws::Codec>, awc::error::WsClientError>
  842. {
  843. let url = self.url(path);
  844. let connect = self.client.ws(url).connect();
  845. connect.await.map(|(_, framed)| framed)
  846. }
  847. /// Connect to a websocket server
  848. pub async fn ws(
  849. &mut self,
  850. ) -> Result<Framed<impl AsyncRead + AsyncWrite, ws::Codec>, awc::error::WsClientError>
  851. {
  852. self.ws_at("/").await
  853. }
  854. /// Stop http server
  855. fn stop(&mut self) {
  856. self.system.stop();
  857. }
  858. }
  859. impl Drop for TestServer {
  860. fn drop(&mut self) {
  861. self.stop()
  862. }
  863. }
  864. #[cfg(test)]
  865. mod tests {
  866. use actix_http::httpmessage::HttpMessage;
  867. use futures::FutureExt;
  868. use serde::{Deserialize, Serialize};
  869. use std::time::SystemTime;
  870. use super::*;
  871. use crate::{http::header, web, App, HttpResponse, Responder};
  872. #[actix_rt::test]
  873. async fn test_basics() {
  874. let req = TestRequest::with_hdr(header::ContentType::json())
  875. .version(Version::HTTP_2)
  876. .set(header::Date(SystemTime::now().into()))
  877. .param("test", "123")
  878. .data(10u32)
  879. .app_data(20u64)
  880. .peer_addr("127.0.0.1:8081".parse().unwrap())
  881. .to_http_request();
  882. assert!(req.headers().contains_key(header::CONTENT_TYPE));
  883. assert!(req.headers().contains_key(header::DATE));
  884. assert_eq!(
  885. req.head().peer_addr,
  886. Some("127.0.0.1:8081".parse().unwrap())
  887. );
  888. assert_eq!(&req.match_info()["test"], "123");
  889. assert_eq!(req.version(), Version::HTTP_2);
  890. let data = req.app_data::<Data<u32>>().unwrap();
  891. assert!(req.app_data::<Data<u64>>().is_none());
  892. assert_eq!(*data.get_ref(), 10);
  893. assert!(req.app_data::<u32>().is_none());
  894. let data = req.app_data::<u64>().unwrap();
  895. assert_eq!(*data, 20);
  896. }
  897. #[actix_rt::test]
  898. async fn test_request_methods() {
  899. let mut app = init_service(
  900. App::new().service(
  901. web::resource("/index.html")
  902. .route(web::put().to(|| async { HttpResponse::Ok().body("put!") }))
  903. .route(
  904. web::patch().to(|| async { HttpResponse::Ok().body("patch!") }),
  905. )
  906. .route(
  907. web::delete()
  908. .to(|| async { HttpResponse::Ok().body("delete!") }),
  909. ),
  910. ),
  911. )
  912. .await;
  913. let put_req = TestRequest::put()
  914. .uri("/index.html")
  915. .header(header::CONTENT_TYPE, "application/json")
  916. .to_request();
  917. let result = read_response(&mut app, put_req).await;
  918. assert_eq!(result, Bytes::from_static(b"put!"));
  919. let patch_req = TestRequest::patch()
  920. .uri("/index.html")
  921. .header(header::CONTENT_TYPE, "application/json")
  922. .to_request();
  923. let result = read_response(&mut app, patch_req).await;
  924. assert_eq!(result, Bytes::from_static(b"patch!"));
  925. let delete_req = TestRequest::delete().uri("/index.html").to_request();
  926. let result = read_response(&mut app, delete_req).await;
  927. assert_eq!(result, Bytes::from_static(b"delete!"));
  928. }
  929. #[actix_rt::test]
  930. async fn test_response() {
  931. let mut app =
  932. init_service(App::new().service(web::resource("/index.html").route(
  933. web::post().to(|| async { HttpResponse::Ok().body("welcome!") }),
  934. )))
  935. .await;
  936. let req = TestRequest::post()
  937. .uri("/index.html")
  938. .header(header::CONTENT_TYPE, "application/json")
  939. .to_request();
  940. let result = read_response(&mut app, req).await;
  941. assert_eq!(result, Bytes::from_static(b"welcome!"));
  942. }
  943. #[derive(Serialize, Deserialize)]
  944. pub struct Person {
  945. id: String,
  946. name: String,
  947. }
  948. #[actix_rt::test]
  949. async fn test_response_json() {
  950. let mut app = init_service(App::new().service(web::resource("/people").route(
  951. web::post().to(|person: web::Json<Person>| {
  952. async { HttpResponse::Ok().json(person.into_inner()) }
  953. }),
  954. )))
  955. .await;
  956. let payload = r#"{"id":"12345","name":"User name"}"#.as_bytes();
  957. let req = TestRequest::post()
  958. .uri("/people")
  959. .header(header::CONTENT_TYPE, "application/json")
  960. .set_payload(payload)
  961. .to_request();
  962. let result: Person = read_response_json(&mut app, req).await;
  963. assert_eq!(&result.id, "12345");
  964. }
  965. #[actix_rt::test]
  966. async fn test_request_response_form() {
  967. let mut app = init_service(App::new().service(web::resource("/people").route(
  968. web::post().to(|person: web::Form<Person>| {
  969. async { HttpResponse::Ok().json(person.into_inner()) }
  970. }),
  971. )))
  972. .await;
  973. let payload = Person {
  974. id: "12345".to_string(),
  975. name: "User name".to_string(),
  976. };
  977. let req = TestRequest::post()
  978. .uri("/people")
  979. .set_form(&payload)
  980. .to_request();
  981. assert_eq!(req.content_type(), "application/x-www-form-urlencoded");
  982. let result: Person = read_response_json(&mut app, req).await;
  983. assert_eq!(&result.id, "12345");
  984. assert_eq!(&result.name, "User name");
  985. }
  986. #[actix_rt::test]
  987. async fn test_request_response_json() {
  988. let mut app = init_service(App::new().service(web::resource("/people").route(
  989. web::post().to(|person: web::Json<Person>| {
  990. async { HttpResponse::Ok().json(person.into_inner()) }
  991. }),
  992. )))
  993. .await;
  994. let payload = Person {
  995. id: "12345".to_string(),
  996. name: "User name".to_string(),
  997. };
  998. let req = TestRequest::post()
  999. .uri("/people")
  1000. .set_json(&payload)
  1001. .to_request();
  1002. assert_eq!(req.content_type(), "application/json");
  1003. let result: Person = read_response_json(&mut app, req).await;
  1004. assert_eq!(&result.id, "12345");
  1005. assert_eq!(&result.name, "User name");
  1006. }
  1007. #[actix_rt::test]
  1008. async fn test_async_with_block() {
  1009. async fn async_with_block() -> Result<HttpResponse, Error> {
  1010. let res = web::block(move || Some(4usize).ok_or("wrong")).await;
  1011. match res {
  1012. Ok(value) => Ok(HttpResponse::Ok()
  1013. .content_type("text/plain")
  1014. .body(format!("Async with block value: {}", value))),
  1015. Err(_) => panic!("Unexpected"),
  1016. }
  1017. }
  1018. let mut app = init_service(
  1019. App::new().service(web::resource("/index.html").to(async_with_block)),
  1020. )
  1021. .await;
  1022. let req = TestRequest::post().uri("/index.html").to_request();
  1023. let res = app.call(req).await.unwrap();
  1024. assert!(res.status().is_success());
  1025. }
  1026. #[actix_rt::test]
  1027. async fn test_server_data() {
  1028. async fn handler(data: web::Data<usize>) -> impl Responder {
  1029. assert_eq!(**data, 10);
  1030. HttpResponse::Ok()
  1031. }
  1032. let mut app = init_service(
  1033. App::new()
  1034. .data(10usize)
  1035. .service(web::resource("/index.html").to(handler)),
  1036. )
  1037. .await;
  1038. let req = TestRequest::post().uri("/index.html").to_request();
  1039. let res = app.call(req).await.unwrap();
  1040. assert!(res.status().is_success());
  1041. }
  1042. #[actix_rt::test]
  1043. async fn test_actor() {
  1044. use actix::Actor;
  1045. struct MyActor;
  1046. struct Num(usize);
  1047. impl actix::Message for Num {
  1048. type Result = usize;
  1049. }
  1050. impl actix::Actor for MyActor {
  1051. type Context = actix::Context<Self>;
  1052. }
  1053. impl actix::Handler<Num> for MyActor {
  1054. type Result = usize;
  1055. fn handle(&mut self, msg: Num, _: &mut Self::Context) -> Self::Result {
  1056. msg.0
  1057. }
  1058. }
  1059. let addr = MyActor.start();
  1060. let mut app = init_service(App::new().service(web::resource("/index.html").to(
  1061. move || {
  1062. addr.send(Num(1)).map(|res| match res {
  1063. Ok(res) => {
  1064. if res == 1 {
  1065. Ok(HttpResponse::Ok())
  1066. } else {
  1067. Ok(HttpResponse::BadRequest())
  1068. }
  1069. }
  1070. Err(err) => Err(err),
  1071. })
  1072. },
  1073. )))
  1074. .await;
  1075. let req = TestRequest::post().uri("/index.html").to_request();
  1076. let res = app.call(req).await.unwrap();
  1077. assert!(res.status().is_success());
  1078. }
  1079. }