use std::collections::BTreeMap;
use std::sync::{Arc, Mutex};
use super::traits::{GenericTestClient, GenericTestServer};
use super::{HttpMethod, TestRequestBuilder, TestResponse};
pub struct TestClientWrapper<C: GenericTestClient>(
Arc<Mutex<C>>,
);
impl<C: GenericTestClient> Clone for TestClientWrapper<C> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<C: GenericTestClient> TestClientWrapper<C> {
#[must_use]
pub fn new(client: C) -> Self {
Self(Arc::new(Mutex::new(client)))
}
#[must_use]
pub fn base_url(&self) -> String {
self.0.lock().unwrap().base_url()
}
#[must_use]
pub fn url(&self, path: &str) -> String {
let base = self.base_url();
if path.starts_with('/') {
format!("{base}{path}")
} else {
format!("{base}/{path}")
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum TestClientWrapperError {
#[error("Test client error: {0}")]
Client(Box<dyn std::error::Error + Send + Sync>),
#[error("Failed to acquire client lock")]
Lock,
}
impl<C: GenericTestClient> super::TestClient for TestClientWrapper<C> {
type Error = TestClientWrapperError;
fn get(&self, path: &str) -> TestRequestBuilder<'_, Self> {
TestRequestBuilder::new(self, HttpMethod::Get, path.to_string())
}
fn post(&self, path: &str) -> TestRequestBuilder<'_, Self> {
TestRequestBuilder::new(self, HttpMethod::Post, path.to_string())
}
fn put(&self, path: &str) -> TestRequestBuilder<'_, Self> {
TestRequestBuilder::new(self, HttpMethod::Put, path.to_string())
}
fn delete(&self, path: &str) -> TestRequestBuilder<'_, Self> {
TestRequestBuilder::new(self, HttpMethod::Delete, path.to_string())
}
fn execute_request(
&self,
method: &str,
path: &str,
headers: &BTreeMap<String, String>,
body: Option<&[u8]>,
) -> Result<TestResponse, Self::Error> {
let client = self.0.lock().map_err(|_| TestClientWrapperError::Lock)?;
client
.execute_request(method, path, headers, body)
.map_err(|e| TestClientWrapperError::Client(Box::new(e)))
}
}
pub struct TestServerWrapper<S: GenericTestServer>(
Arc<Mutex<S>>,
);
impl<S: GenericTestServer> Clone for TestServerWrapper<S> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<S: GenericTestServer> TestServerWrapper<S> {
#[must_use]
pub fn new(server: S) -> Self {
Self(Arc::new(Mutex::new(server)))
}
#[must_use]
pub fn url(&self) -> String {
self.0.lock().unwrap().url()
}
#[must_use]
pub fn port(&self) -> u16 {
self.0.lock().unwrap().port()
}
pub fn start(&self) -> Result<(), TestServerWrapperError> {
let mut server = self.0.lock().map_err(|_| TestServerWrapperError::Lock)?;
server
.start()
.map_err(|e| TestServerWrapperError::Server(Box::new(e)))
}
pub fn stop(&self) -> Result<(), TestServerWrapperError> {
let mut server = self.0.lock().map_err(|_| TestServerWrapperError::Lock)?;
server
.stop()
.map_err(|e| TestServerWrapperError::Server(Box::new(e)))
}
}
#[derive(Debug, thiserror::Error)]
pub enum TestServerWrapperError {
#[error("Test server error: {0}")]
Server(Box<dyn std::error::Error + Send + Sync>),
#[error("Failed to acquire server lock")]
Lock,
}