omaha_client/http_request/
mock.rs
1use crate::http_request::{Error, HttpRequest};
10use futures::future::BoxFuture;
11use futures::prelude::*;
12use http::StatusCode;
13use hyper::{Body, Request, Response};
14use pretty_assertions::assert_eq;
15use std::{cell::RefCell, collections::VecDeque, rc::Rc};
16
17#[cfg(test)]
18use futures::executor::block_on;
19
20#[derive(Debug, Default)]
21pub struct MockHttpRequest {
22 requests: Rc<RefCell<Vec<Request<Body>>>>,
24 responses: VecDeque<Result<Response<Vec<u8>>, Error>>,
26}
27
28impl HttpRequest for MockHttpRequest {
29 fn request(&mut self, req: Request<Body>) -> BoxFuture<'_, Result<Response<Vec<u8>>, Error>> {
30 self.requests.borrow_mut().push(req);
31
32 future::ready(if let Some(resp) = self.responses.pop_front() {
33 resp
34 } else {
35 Ok(Response::builder()
37 .status(StatusCode::INTERNAL_SERVER_ERROR)
38 .body(vec![])
39 .unwrap())
40 })
41 .boxed()
42 }
43}
44
45impl MockHttpRequest {
46 pub fn new(res: Response<Vec<u8>>) -> Self {
47 Self {
48 responses: vec![Ok(res)].into(),
49 ..Default::default()
50 }
51 }
52
53 pub fn empty() -> Self {
54 Default::default()
55 }
56
57 pub fn from_request_cell(request: Rc<RefCell<Vec<Request<Body>>>>) -> Self {
58 Self {
59 requests: request,
60 ..Default::default()
61 }
62 }
63
64 pub fn get_request_cell(&self) -> Rc<RefCell<Vec<Request<Body>>>> {
65 Rc::clone(&self.requests)
66 }
67
68 pub fn add_response(&mut self, res: Response<Vec<u8>>) {
69 self.responses.push_back(Ok(res));
70 }
71
72 pub fn add_error(&mut self, error: Error) {
73 self.responses.push_back(Err(error));
74 }
75
76 pub fn assert_method(&self, method: &hyper::Method) {
77 assert_eq!(method, self.requests.borrow().last().unwrap().method());
78 }
79
80 pub fn assert_uri(&self, uri: &str) {
81 assert_eq!(
82 &uri.parse::<hyper::Uri>().unwrap(),
83 self.requests.borrow().last().unwrap().uri()
84 );
85 }
86
87 pub fn assert_header(&self, key: &str, value: &str) {
88 let requests = self.requests.borrow();
89 let request = requests.last().unwrap();
90 let headers = request.headers();
91 assert!(headers.contains_key(key));
92 assert_eq!(headers[key], value);
93 }
94
95 fn take_request(&self) -> Request<Body> {
96 self.requests.borrow_mut().pop().unwrap()
97 }
98
99 pub async fn assert_body(&self, body: &[u8]) {
100 let bytes = hyper::body::to_bytes(self.take_request()).await.unwrap();
101 assert_eq!(body, &bytes);
102 }
103
104 pub async fn assert_body_str(&self, body: &str) {
105 let bytes = hyper::body::to_bytes(self.take_request()).await.unwrap();
106 assert_eq!(body, String::from_utf8_lossy(&bytes));
107 }
108}
109
110#[test]
111fn test_mock() {
112 let res_body = vec![1, 2, 3];
113 let mut mock = MockHttpRequest::new(Response::new(res_body.clone()));
114
115 let req_body = vec![4, 5, 6];
116 let uri = "https://mock.uri/";
117 let req = Request::get(uri)
118 .header("X-Custom-Foo", "Bar")
119 .body(req_body.clone().into())
120 .unwrap();
121 block_on(async {
122 let response = mock.request(req).await.unwrap();
123 assert_eq!(res_body, response.into_body());
124
125 mock.assert_method(&hyper::Method::GET);
126 mock.assert_uri(uri);
127 mock.assert_header("X-Custom-Foo", "Bar");
128 mock.assert_body(req_body.as_slice()).await;
129 });
130}
131
132#[test]
133fn test_missing_response() {
134 let res_body = vec![1, 2, 3];
135 let mut mock = MockHttpRequest::new(Response::new(res_body.clone()));
136 block_on(async {
137 let response = mock.request(Request::default()).await.unwrap();
138 assert_eq!(res_body, response.into_body());
139
140 let response2 = mock.request(Request::default()).await.unwrap();
141 assert_eq!(response2.status(), hyper::StatusCode::INTERNAL_SERVER_ERROR);
142 });
143}
144
145#[test]
146fn test_multiple_responses() {
147 let res_body = vec![1, 2, 3];
148 let mut mock = MockHttpRequest::new(Response::new(res_body.clone()));
149 let res_body2 = vec![4, 5, 6];
150 mock.add_response(Response::new(res_body2.clone()));
151
152 block_on(async {
153 let response = mock.request(Request::default()).await.unwrap();
154 assert_eq!(res_body, response.into_body());
155
156 let response2 = mock.request(Request::default()).await.unwrap();
157 assert_eq!(res_body2, response2.into_body());
158 });
159}