use crate::server::handlers;
use crate::server::handlers::mocks::SetMockRequest;
use crate::server::handlers::{HttpMockRequest, HttpMockResponse, HttpMockState};
use actix_web::dev::HttpResponseBuilder;
use actix_web::http::StatusCode;
use actix_web::web::{Bytes, BytesMut, Data, Json, Payload};
use actix_web::{error, Error, HttpRequest, HttpResponse, Result};
use futures::{Future, Stream};
use std::collections::BTreeMap;
pub fn list(state: Data<HttpMockState>) -> Result<HttpResponse> {
let result = handlers::mocks::list_all(&state.into_inner());
if let Err(e) = result {
return Ok(HttpResponse::InternalServerError().body(e));
}
Ok(HttpResponse::Accepted().json(&result.unwrap()))
}
pub fn add(state: Data<HttpMockState>, req: Json<SetMockRequest>) -> Result<HttpResponse> {
let result = handlers::mocks::add_new_mock(&state.into_inner(), req.into_inner());
if let Err(e) = result {
return Ok(HttpResponse::InternalServerError().body(e));
}
Ok(HttpResponse::Created().finish())
}
pub fn clear(state: Data<HttpMockState>) -> Result<HttpResponse> {
let result = handlers::mocks::clear_mocks(&state.into_inner());
if let Err(e) = result {
return Ok(HttpResponse::InternalServerError().body(e));
}
Ok(HttpResponse::Accepted().finish())
}
pub fn serve(
state: Data<HttpMockState>,
req: HttpRequest,
payload: Payload,
) -> impl Future<Item = HttpResponse, Error = Error> {
return payload
.from_err()
.fold(BytesMut::new(), append_chunk)
.and_then(|body| handle_mock_request(body, state, req));
}
fn append_chunk(mut buf: BytesMut, chunk: Bytes) -> Result<BytesMut> {
buf.extend_from_slice(&chunk);
Ok::<_, Error>(buf)
}
fn handle_mock_request(
body_buffer: BytesMut,
state: Data<HttpMockState>,
req: HttpRequest,
) -> Result<HttpResponse> {
return match String::from_utf8(body_buffer.to_vec()) {
Ok(content) => {
let handler_request = to_handler_request(req, content);
let handler_response = handlers::mocks::find_mock(&state, handler_request);
return to_route_response(handler_response);
}
Err(error) => Err(error::ErrorBadRequest(error.to_string())),
};
}
fn to_route_response(
handler_result: Result<Option<HttpMockResponse>, &'static str>,
) -> Result<HttpResponse> {
return match handler_result {
Err(e) => Err(error::ErrorInternalServerError(e)),
Ok(res) => {
return match res {
None => Err(error::ErrorNotFound(
"Request did not match any route or mock",
)),
Some(http_mock_response) => Ok(to_http_response(http_mock_response)),
}
}
};
}
fn to_handler_request(req: HttpRequest, body: String) -> HttpMockRequest {
HttpMockRequest::builder()
.method(req.method().as_str().to_string())
.path(req.path().to_string())
.headers(BTreeMap::new())
.body(body)
.build()
}
fn to_http_response(res: HttpMockResponse) -> HttpResponse {
let status_code = StatusCode::from_u16(res.status).unwrap();
let mut response_builder = HttpResponseBuilder::new(status_code);
return match res.body {
Some(body) => response_builder.body(actix_web::body::Body::from(body.clone())),
None => response_builder.finish(),
};
}
#[cfg(test)]
mod test {
use crate::server::handlers::HttpMockResponse;
use crate::server::routes::mocks::{to_http_response, to_route_response};
use actix_http::body::BodySize;
use actix_http::body::{Body, MessageBody};
use actix_http::Response;
use actix_web::http::StatusCode;
#[test]
fn to_http_response_has_no_body() {
let input = HttpMockResponse::builder().status(200 as u16).build();
let actual = to_http_response(input);
assert_eq!(StatusCode::from_u16(200).unwrap(), actual.status());
assert_eq!(0, body_size(&actual));
}
#[test]
fn to_http_response_has_body() {
let input = HttpMockResponse::builder()
.status(200 as u16)
.body("#".to_string())
.build();
let actual = to_http_response(input);
assert_eq!(StatusCode::from_u16(200).unwrap(), actual.status());
assert_eq!(1, body_size(&actual));
}
#[test]
#[should_panic(expected = "value: InvalidStatusCode ")]
fn to_http_response_fails_invalid_http_status() {
let input = HttpMockResponse::builder().status(999 as u16).build();
to_http_response(input);
}
#[test]
fn to_route_response_internal_server_error() {
let input = Err("error message");
let actual = to_route_response(input);
assert_eq!(true, actual.is_err());
let err = actual.unwrap_err();
assert_eq!("error message", err.to_string());
assert_eq!(
500 as u16,
err.as_response_error().error_response().status()
);
}
#[test]
fn to_route_response_not_found() {
let input = Ok(None);
let actual = to_route_response(input);
assert_eq!(actual.is_err(), true);
let err = actual.unwrap_err();
assert_eq!("Request did not match any route or mock", err.to_string());
assert_eq!(
404 as u16,
err.as_response_error().error_response().status()
);
}
#[test]
fn to_route_response_ok() {
let input_response = HttpMockResponse::builder().status(418 as u16).build();
let input = Ok(Some(input_response));
let actual = to_route_response(input);
assert_eq!(actual.is_ok(), true);
assert_eq!(actual.unwrap().status().as_u16(), 418 as u16);
}
fn body_size(body: &Response<Body>) -> u64 {
match body.body().size() {
BodySize::Sized(x) => x as u64,
BodySize::Sized64(x) => x,
_ => 0,
}
}
}