Skip to main content

omaha_client/http_request/
mock.rs

1// Copyright 2019 The Fuchsia Authors
2//
3// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6// This file may not be copied, modified, or distributed except according to
7// those terms.
8
9use crate::http_request::{Body, Error, HttpRequest, Request, Response, to_bytes};
10use futures::future::BoxFuture;
11use futures::prelude::*;
12use http::StatusCode;
13use pretty_assertions::assert_eq;
14use std::{cell::RefCell, collections::VecDeque, rc::Rc};
15
16#[cfg(test)]
17use futures::executor::block_on;
18
19#[derive(Debug, Default)]
20pub struct MockHttpRequest {
21    // The requests made using this mock.
22    requests: Rc<RefCell<Vec<Request<Body>>>>,
23    // The queue of fake responses for the upcoming requests.
24    responses: VecDeque<Result<Response<Vec<u8>>, Error>>,
25}
26
27impl HttpRequest for MockHttpRequest {
28    fn request(&mut self, req: Request<Body>) -> BoxFuture<'_, Result<Response<Vec<u8>>, Error>> {
29        self.requests.borrow_mut().push(req);
30
31        future::ready(if let Some(resp) = self.responses.pop_front() {
32            resp
33        } else {
34            // No response to return, generate a 500 internal server error
35            Ok(Response::builder().status(StatusCode::INTERNAL_SERVER_ERROR).body(vec![]).unwrap())
36        })
37        .boxed()
38    }
39}
40
41impl MockHttpRequest {
42    pub fn new(res: Response<Vec<u8>>) -> Self {
43        Self { responses: vec![Ok(res)].into(), ..Default::default() }
44    }
45
46    pub fn empty() -> Self {
47        Default::default()
48    }
49
50    pub fn from_request_cell(request: Rc<RefCell<Vec<Request<Body>>>>) -> Self {
51        Self { requests: request, ..Default::default() }
52    }
53
54    pub fn get_request_cell(&self) -> Rc<RefCell<Vec<Request<Body>>>> {
55        Rc::clone(&self.requests)
56    }
57
58    pub fn add_response(&mut self, res: Response<Vec<u8>>) {
59        self.responses.push_back(Ok(res));
60    }
61
62    pub fn add_error(&mut self, error: Error) {
63        self.responses.push_back(Err(error));
64    }
65
66    pub fn assert_method(&self, method: &hyper::Method) {
67        assert_eq!(method, self.requests.borrow().last().unwrap().method());
68    }
69
70    pub fn assert_uri(&self, uri: &str) {
71        assert_eq!(
72            &uri.parse::<hyper::Uri>().unwrap(),
73            self.requests.borrow().last().unwrap().uri()
74        );
75    }
76
77    pub fn assert_header(&self, key: &str, value: &str) {
78        let requests = self.requests.borrow();
79        let request = requests.last().unwrap();
80        let headers = request.headers();
81        assert!(headers.contains_key(key));
82        assert_eq!(headers[key], value);
83    }
84
85    fn take_request(&self) -> Request<Body> {
86        self.requests.borrow_mut().pop().unwrap()
87    }
88
89    pub async fn assert_body(&self, body: &[u8]) {
90        let bytes = to_bytes(self.take_request()).await.unwrap();
91        assert_eq!(body, &bytes);
92    }
93
94    pub async fn assert_body_str(&self, body: &str) {
95        let bytes = to_bytes(self.take_request()).await.unwrap();
96        assert_eq!(body, String::from_utf8_lossy(&bytes));
97    }
98}
99
100#[test]
101fn test_mock() {
102    let res_body = vec![1, 2, 3];
103    let mut mock = MockHttpRequest::new(Response::new(res_body.clone()));
104
105    let req_body = vec![4, 5, 6];
106    let uri = "https://mock.uri/";
107    let req =
108        Request::get(uri).header("X-Custom-Foo", "Bar").body(req_body.clone().into()).unwrap();
109    block_on(async {
110        let response = mock.request(req).await.unwrap();
111        assert_eq!(res_body, response.into_body());
112
113        mock.assert_method(&hyper::Method::GET);
114        mock.assert_uri(uri);
115        mock.assert_header("X-Custom-Foo", "Bar");
116        mock.assert_body(req_body.as_slice()).await;
117    });
118}
119
120#[test]
121fn test_missing_response() {
122    let res_body = vec![1, 2, 3];
123    let mut mock = MockHttpRequest::new(Response::new(res_body.clone()));
124    block_on(async {
125        let response = mock.request(Request::default()).await.unwrap();
126        assert_eq!(res_body, response.into_body());
127
128        let response2 = mock.request(Request::default()).await.unwrap();
129        assert_eq!(response2.status(), hyper::StatusCode::INTERNAL_SERVER_ERROR);
130    });
131}
132
133#[test]
134fn test_multiple_responses() {
135    let res_body = vec![1, 2, 3];
136    let mut mock = MockHttpRequest::new(Response::new(res_body.clone()));
137    let res_body2 = vec![4, 5, 6];
138    mock.add_response(Response::new(res_body2.clone()));
139
140    block_on(async {
141        let response = mock.request(Request::default()).await.unwrap();
142        assert_eq!(res_body, response.into_body());
143
144        let response2 = mock.request(Request::default()).await.unwrap();
145        assert_eq!(res_body2, response2.into_body());
146    });
147}