From 4cc2b38059db4fcc50220fc3d8abde669c9b1c6a Mon Sep 17 00:00:00 2001 From: Darin Date: Sun, 14 Apr 2019 19:25:45 -0400 Subject: [PATCH] added read_response_json for testing (#776) * added read_response_json for testing * cleaned up * modied docs for read_response_json * typo in doc * test code in doc should compile now * use type coercion in doc * removed generic R, replaced with Request --- awc/src/ws.rs | 4 +++- src/test.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/awc/src/ws.rs b/awc/src/ws.rs index 4f0983dc5..5ed37945b 100644 --- a/awc/src/ws.rs +++ b/awc/src/ws.rs @@ -306,7 +306,9 @@ impl WebsocketsRequest { } } else { log::trace!("Invalid connection header: {:?}", conn); - return Err(WsClientError::InvalidConnectionHeader(conn.clone())); + return Err(WsClientError::InvalidConnectionHeader( + conn.clone(), + )); } } else { log::trace!("Missing connection header"); diff --git a/src/test.rs b/src/test.rs index 7cdf44854..342187048 100644 --- a/src/test.rs +++ b/src/test.rs @@ -11,14 +11,16 @@ use actix_router::{Path, ResourceDef, Url}; use actix_rt::Runtime; use actix_server_config::ServerConfig; use actix_service::{FnService, IntoNewService, NewService, Service}; -use bytes::Bytes; -use futures::future::{lazy, Future}; +use bytes::{Bytes, BytesMut}; +use futures::{future::{lazy, ok, Future}, stream::Stream}; +use serde::de::DeserializeOwned; +use serde_json; pub use actix_http::test::TestBuffer; use crate::config::{AppConfig, AppConfigInner}; use crate::data::RouteData; -use crate::dev::{Body, Payload}; +use crate::dev::{Body, MessageBody, Payload}; use crate::request::HttpRequestPool; use crate::rmap::ResourceMap; use crate::service::{ServiceRequest, ServiceResponse}; @@ -363,4 +365,55 @@ impl TestRequest { { block_on(f) } + + /// Helper function that returns a deserialized response body of a TestRequest + /// This function blocks the current thread until futures complete. + /// + /// ```rust + /// use actix_web::{App, test, web, HttpResponse, http::header}; + /// use serde::{Serialize, Deserialize}; + /// + /// #[derive(Serialize, Deserialize)] + /// pub struct Person { id: String, name: String } + /// + /// #[test] + /// fn test_add_person() { + /// let mut app = test::init_service(App::new().service( + /// web::resource("/people") + /// .route(web::post().to(|person: web::Json| { + /// HttpResponse::Ok() + /// .json(person.into_inner())}) + /// ))); + /// + /// let payload = r#"{"id":"12345","name":"Nikolay Kim"}"#.as_bytes(); + /// + /// let req = test::TestRequest::post() + /// .uri("/people") + /// .header(header::CONTENT_TYPE, "application/json") + /// .set_payload(payload) + /// .to_request(); + /// + /// let result: Person = test::read_response_json(&mut app, req); + /// } + /// ``` + pub fn read_response_json(app: &mut S, req: Request) -> T + where + S: Service, Error = Error>, + B: MessageBody, + T: DeserializeOwned, + { + block_on(app.call(req).and_then(|mut resp: ServiceResponse| { + resp.take_body() + .fold(BytesMut::new(), move |mut body, chunk| { + body.extend_from_slice(&chunk); + Ok::<_, Error>(body) + }) + .and_then(|body: BytesMut| { + ok(serde_json::from_slice(&body).unwrap_or_else(|_| { + panic!("read_response_json failed during deserialization") + })) + }) + })) + .unwrap_or_else(|_| panic!("read_response_json failed at block_on unwrap")) + } }