use crate::wiremock::delay::LognormalDelay;
use http_types::headers::{HeaderName, HeaderValue};
use http_types::{Response, StatusCode};
use serde::Serialize;
use std::collections::HashMap;
use std::convert::TryInto;
use std::str::FromStr;
use std::time::Duration;
#[derive(Clone, Debug, Default)]
pub struct ResponseTemplate {
pub(crate) mime: Option<http_types::Mime>,
pub(crate) http_status_code: Option<StatusCode>,
#[cfg(feature = "grpc")]
pub(crate) grpc_status_code: Option<tonic::Code>,
pub(crate) headers: HashMap<HeaderName, Vec<HeaderValue>>,
pub(crate) body: Option<Vec<u8>>,
pub(crate) delay: Option<Duration>,
pub(crate) lognormal_delay: Option<LognormalDelay>,
}
impl ResponseTemplate {
pub fn new<S>(s: S) -> Self
where
S: TryInto<StatusCode>,
<S as TryInto<StatusCode>>::Error: std::fmt::Debug,
{
Self {
http_status_code: s.try_into().ok(),
..Default::default()
}
}
pub fn append_header<K, V>(mut self, key: K, value: V) -> Self
where
K: TryInto<HeaderName>,
<K as TryInto<HeaderName>>::Error: std::fmt::Debug,
V: TryInto<HeaderValue>,
<V as TryInto<HeaderValue>>::Error: std::fmt::Debug,
{
let key = key.try_into().expect("Failed to convert into header name.");
let value = value.try_into().expect("Failed to convert into header value.");
match self.headers.get_mut(&key) {
Some(headers) => {
headers.push(value);
},
None => {
self.headers.insert(key, vec![value]);
},
}
self
}
pub fn insert_header<K, V>(mut self, key: K, value: V) -> Self
where
K: TryInto<HeaderName>,
<K as TryInto<HeaderName>>::Error: std::fmt::Debug,
V: TryInto<HeaderValue>,
<V as TryInto<HeaderValue>>::Error: std::fmt::Debug,
{
let key = key.try_into().expect("Failed to convert into header name.");
let value = value.try_into().expect("Failed to convert into header value.");
self.headers.insert(key, vec![value]);
self
}
pub fn set_body_bytes<B>(mut self, body: B) -> Self
where
B: TryInto<Vec<u8>>,
<B as TryInto<Vec<u8>>>::Error: std::fmt::Debug,
{
let body = body.try_into().expect("Failed to convert into body.");
self.body = Some(body);
self
}
pub fn set_body_json<B: Serialize>(mut self, body: B) -> Self {
let body = serde_json::to_vec(&body).expect("Failed to convert into body.");
self.body = Some(body);
self.mime = Some(http_types::Mime::from_str("application/json").expect("Failed to convert into Mime header"));
self
}
pub fn set_body_string<T>(mut self, body: T) -> Self
where
T: TryInto<String>,
<T as TryInto<String>>::Error: std::fmt::Debug,
{
let body = body.try_into().expect("Failed to convert into body.");
self.body = Some(body.into_bytes());
self.mime = Some(http_types::Mime::from_str("text/plain").expect("Failed to convert into Mime header"));
self
}
pub fn set_body_raw<B>(mut self, body: B, mime: &str) -> Self
where
B: TryInto<Vec<u8>>,
<B as TryInto<Vec<u8>>>::Error: std::fmt::Debug,
{
let body = body.try_into().expect("Failed to convert into body.");
self.body = Some(body);
self.mime = Some(http_types::Mime::from_str(mime).expect("Failed to convert into Mime header"));
self
}
pub fn set_delay(mut self, delay: Duration) -> Self {
self.delay = Some(delay);
self
}
pub fn set_lognormal_delay(mut self, median: u64, sigma: f64) -> Self {
self.lognormal_delay = Some(LognormalDelay { median, sigma });
self
}
pub(crate) fn generate_response(&self) -> Response {
if let Some(status) = self.http_status_code {
let mut response = Response::new(status);
for (header_name, header_values) in &self.headers {
response.insert_header(header_name.clone(), header_values.as_slice());
}
if let Some(body) = &self.body {
response.set_body(body.clone());
}
if let Some(mime) = &self.mime {
response.set_content_type(mime.to_owned());
}
response
} else {
panic!("Implementation error")
}
}
pub(crate) fn delay(&self) -> Option<std::borrow::Cow<Duration>> {
if let Some(delay) = self.delay.as_ref() {
Some(std::borrow::Cow::Borrowed(delay))
} else {
self.lognormal_delay
.as_ref()
.map(|lognormal_delay| std::borrow::Cow::Owned(lognormal_delay.new_sample()))
}
}
}