use crate::{
api::server::MockServer,
common::{
data::RecordingRuleConfig,
data::RequestRequirements,
util::{write_file, Join},
},
When,
};
use bytes::Bytes;
use std::{
cell::Cell,
path::{Path, PathBuf},
rc::Rc,
};
pub struct ForwardingRule<'a> {
pub id: usize,
pub(crate) server: &'a MockServer,
}
impl<'a> ForwardingRule<'a> {
pub fn new(id: usize, server: &'a MockServer) -> Self {
Self { id, server }
}
pub fn delete(&mut self) {
self.delete_async().join();
}
pub async fn delete_async(&self) {
self.server
.server_adapter
.as_ref()
.unwrap()
.delete_forwarding_rule(self.id)
.await
.expect("could not delete mock from server");
}
}
pub struct ProxyRule<'a> {
pub id: usize,
pub(crate) server: &'a MockServer,
}
impl<'a> ProxyRule<'a> {
pub fn new(id: usize, server: &'a MockServer) -> Self {
Self { id, server }
}
pub fn delete(&mut self) {
self.delete_async().join();
}
pub async fn delete_async(&self) {
self.server
.server_adapter
.as_ref()
.unwrap()
.delete_proxy_rule(self.id)
.await
.expect("could not delete mock from server");
}
}
pub struct Recording<'a> {
pub id: usize,
pub(crate) server: &'a MockServer,
}
impl<'a> Recording<'a> {
pub fn new(id: usize, server: &'a MockServer) -> Self {
Self { id, server }
}
pub fn delete(&mut self) {
self.delete_async().join();
}
pub async fn delete_async(&self) {
self.server
.server_adapter
.as_ref()
.unwrap()
.delete_recording(self.id)
.await
.expect("could not delete mock from server");
}
#[cfg(feature = "record")]
pub fn export(&self) -> Result<Option<Bytes>, Box<dyn std::error::Error>> {
self.export_async().join()
}
#[cfg(feature = "record")]
pub async fn export_async(&self) -> Result<Option<Bytes>, Box<dyn std::error::Error>> {
let rec = self
.server
.server_adapter
.as_ref()
.unwrap()
.export_recording(self.id)
.await?;
Ok(rec)
}
#[cfg(feature = "record")]
pub fn save_to<PathRef: AsRef<Path>, IntoString: Into<String>>(
&self,
dir: PathRef,
scenario_name: IntoString,
) -> Result<PathBuf, Box<dyn std::error::Error>> {
self.save_to_async(dir, scenario_name).join()
}
#[cfg(feature = "record")]
pub async fn save_to_async<PathRef: AsRef<Path>, IntoString: Into<String>>(
&self,
dir: PathRef,
scenario: IntoString,
) -> Result<PathBuf, Box<dyn std::error::Error>> {
let rec = self.export_async().await?;
let scenario = scenario.into();
let dir = dir.as_ref();
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)?
.as_secs();
let filename = format!("{}_{}.yaml", scenario, timestamp);
let filepath = dir.join(filename);
if let Some(bytes) = rec {
return Ok(write_file(&filepath, &bytes, true).await?);
}
Err("No recording data available".into())
}
#[cfg(feature = "record")]
pub fn save<IntoString: Into<String>>(
&self,
scenario_name: IntoString,
) -> Result<PathBuf, Box<dyn std::error::Error>> {
self.save_async(scenario_name).join()
}
#[cfg(feature = "record")]
pub async fn save_async<IntoString: Into<String>>(
&self,
scenario: IntoString,
) -> Result<PathBuf, Box<dyn std::error::Error>> {
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("target")
.join("httpmock")
.join("recordings");
self.save_to_async(path, scenario).await
}
}
pub struct ForwardingRuleBuilder {
pub(crate) request_requirements: Rc<Cell<RequestRequirements>>,
pub(crate) headers: Rc<Cell<Vec<(String, String)>>>,
}
impl ForwardingRuleBuilder {
pub fn add_request_header<Key: Into<String>, Value: Into<String>>(
self,
key: Key,
value: Value,
) -> Self {
let mut headers = self.headers.take();
headers.push((key.into(), value.into()));
self.headers.set(headers);
self
}
pub fn filter<WhenSpecFn>(self, when: WhenSpecFn) -> Self
where
WhenSpecFn: FnOnce(When),
{
when(When {
expectations: self.request_requirements.clone(),
});
self
}
}
pub struct ProxyRuleBuilder {
pub(crate) request_requirements: Rc<Cell<RequestRequirements>>,
pub(crate) headers: Rc<Cell<Vec<(String, String)>>>,
}
impl ProxyRuleBuilder {
pub fn add_request_header<Key: Into<String>, Value: Into<String>>(
self,
key: Key,
value: Value,
) -> Self {
let mut headers = self.headers.take();
headers.push((key.into(), value.into()));
self.headers.set(headers);
self
}
pub fn filter<WhenSpecFn>(self, when: WhenSpecFn) -> Self
where
WhenSpecFn: FnOnce(When),
{
when(When {
expectations: self.request_requirements.clone(),
});
self
}
}
pub struct RecordingRuleBuilder {
pub config: Rc<Cell<RecordingRuleConfig>>,
}
impl RecordingRuleBuilder {
pub fn record_request_header<IntoString: Into<String>>(self, header: IntoString) -> Self {
let mut config = self.config.take();
config.record_headers.push(header.into());
self.config.set(config);
self
}
pub fn record_request_headers<IntoString: Into<String>>(
self,
headers: Vec<IntoString>,
) -> Self {
let mut config = self.config.take();
config
.record_headers
.extend(headers.into_iter().map(Into::into));
self.config.set(config);
self
}
pub fn filter<WhenSpecFn>(self, when: WhenSpecFn) -> Self
where
WhenSpecFn: FnOnce(When),
{
let mut config = self.config.take();
let request_requirements = Rc::new(Cell::new(config.request_requirements));
when(When {
expectations: request_requirements.clone(),
});
config.request_requirements = request_requirements.take();
self.config.set(config);
self
}
pub fn record_response_delays(self, record: bool) -> Self {
let mut config = self.config.take();
config.record_response_delays = record;
self.config.set(config);
self
}
}