From cab7a837a744daebe6fb20231674c8ea741621cc Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Tue, 16 May 2023 17:17:47 +0200 Subject: [PATCH] Introduced separate 'Boxed' traits, to allow for mocks --- src/domain/config.rs | 16 +++++++++------ src/domain/manager.rs | 45 +++++++++++++++++++++++++---------------- src/main.rs | 1 - src/origin/store.rs | 10 +++++++-- src/origin/store/git.rs | 6 ++++-- src/service.rs | 38 +++++++++++++++++++++++++--------- 6 files changed, 78 insertions(+), 38 deletions(-) diff --git a/src/domain/config.rs b/src/domain/config.rs index 141947d..9b7cdcd 100644 --- a/src/domain/config.rs +++ b/src/domain/config.rs @@ -1,6 +1,6 @@ use std::error::Error; use std::path::{Path, PathBuf}; -use std::{fs, io}; +use std::{fs, io, sync}; use crate::domain; use crate::origin::Descr; @@ -39,20 +39,22 @@ pub enum SetError { } #[mockall::automock] -pub trait Store: std::marker::Send + std::marker::Sync { +pub trait Store { fn get(&self, domain: &domain::Name) -> Result; fn set(&self, domain: &domain::Name, config: &Config) -> Result<(), SetError>; } +pub trait BoxedStore: Store + Send + Sync + Clone {} + struct FSStore { dir_path: PathBuf, } -pub fn new(dir_path: &Path) -> io::Result { +pub fn new(dir_path: &Path) -> io::Result { fs::create_dir_all(dir_path)?; - Ok(FSStore { + Ok(sync::Arc::new(FSStore { dir_path: dir_path.into(), - }) + })) } impl FSStore { @@ -65,7 +67,9 @@ impl FSStore { } } -impl Store for FSStore { +impl BoxedStore for sync::Arc {} + +impl Store for sync::Arc { fn get(&self, domain: &domain::Name) -> Result { let config_file = fs::File::open(self.config_file_path(domain)).map_err(|e| match e.kind() { diff --git a/src/domain/manager.rs b/src/domain/manager.rs index 80d84d9..b3c8deb 100644 --- a/src/domain/manager.rs +++ b/src/domain/manager.rs @@ -2,7 +2,7 @@ use crate::domain::{self, checker, config}; use crate::origin; use std::error::Error; use std::future::Future; -use std::pin; +use std::{pin, sync}; #[derive(thiserror::Error, Debug)] pub enum GetConfigError { @@ -113,8 +113,8 @@ impl From for SyncWithConfigError { } } -//#[mockall::automock(type Origin=origin::MockOrigin;)] -pub trait Manager: Send + Sync { +//#[mockall::automock] +pub trait Manager { fn get_config(&self, domain: &domain::Name) -> Result; fn get_origin( &self, @@ -128,36 +128,47 @@ pub trait Manager: Send + Sync { ) -> pin::Pin> + Send + '_>>; } +pub trait BoxedManager: Manager + Send + Sync + Clone {} + +struct ManagerImpl +where + OriginStore: origin::store::BoxedStore, + DomainConfigStore: config::BoxedStore, +{ + origin_store: OriginStore, + domain_config_store: DomainConfigStore, + domain_checker: checker::DNSChecker, +} + pub fn new( origin_store: OriginStore, domain_config_store: DomainConfigStore, domain_checker: checker::DNSChecker, -) -> impl Manager +) -> impl BoxedManager where - OriginStore: origin::store::Store, - DomainConfigStore: config::Store, + OriginStore: origin::store::BoxedStore, + DomainConfigStore: config::BoxedStore, { - ManagerImpl { + sync::Arc::new(ManagerImpl { origin_store, domain_config_store, domain_checker, - } + }) } -struct ManagerImpl +impl BoxedManager + for sync::Arc> where - OriginStore: origin::store::Store, - DomainConfigStore: config::Store, + OriginStore: origin::store::BoxedStore, + DomainConfigStore: config::BoxedStore, { - origin_store: OriginStore, - domain_config_store: DomainConfigStore, - domain_checker: checker::DNSChecker, } -impl Manager for ManagerImpl +impl Manager + for sync::Arc> where - OriginStore: origin::store::Store, - DomainConfigStore: config::Store, + OriginStore: origin::store::BoxedStore, + DomainConfigStore: config::BoxedStore, { fn get_config(&self, domain: &domain::Name) -> Result { Ok(self.domain_config_store.get(domain)?) diff --git a/src/main.rs b/src/main.rs index 0c512d7..c7c2873 100644 --- a/src/main.rs +++ b/src/main.rs @@ -123,7 +123,6 @@ fn main() { .expect("domain config store initialized"); let manager = domiply::domain::manager::new(origin_store, domain_config_store, domain_checker); - let manager = sync::Arc::new(manager); let service = domiply::service::new( manager, diff --git a/src/origin/store.rs b/src/origin/store.rs index 6ddc424..1f8ca2e 100644 --- a/src/origin/store.rs +++ b/src/origin/store.rs @@ -41,13 +41,17 @@ pub enum AllDescrsError { /// Used in the return from all_descrs from Store. pub type AllDescrsResult = Result; +#[mockall::automock( + type Origin=origin::MockOrigin; + type AllDescrsIter=Vec>; + )] /// Describes a storage mechanism for Origins. Each Origin is uniquely identified by its Descr. -pub trait Store: Send + Sync + Clone { +pub trait Store { type Origin<'store>: origin::Origin + 'store where Self: 'store; - type AllDescrsIter<'store>: IntoIterator> + Send + 'store + type AllDescrsIter<'store>: IntoIterator> + 'store where Self: 'store; @@ -58,3 +62,5 @@ pub trait Store: Send + Sync + Clone { fn get(&self, descr: origin::Descr) -> Result, GetError>; fn all_descrs(&self) -> AllDescrsResult>; } + +pub trait BoxedStore: Store + Send + Sync + Clone {} diff --git a/src/origin/store/git.rs b/src/origin/store/git.rs index f6d1ccb..9d004b2 100644 --- a/src/origin/store/git.rs +++ b/src/origin/store/git.rs @@ -65,7 +65,7 @@ struct Store { origins: sync::RwLock>>, } -pub fn new(dir_path: PathBuf) -> io::Result { +pub fn new(dir_path: PathBuf) -> io::Result { fs::create_dir_all(&dir_path)?; Ok(sync::Arc::new(Store { dir_path, @@ -191,11 +191,13 @@ impl Store { } } +impl super::BoxedStore for sync::Arc {} + impl super::Store for sync::Arc { type Origin<'store> = sync::Arc where Self: 'store; - type AllDescrsIter<'store> = Box> + Send + 'store> + type AllDescrsIter<'store> = Box> + 'store> where Self: 'store; fn sync(&self, descr: origin::Descr, limits: store::Limits) -> Result<(), store::SyncError> { diff --git a/src/service.rs b/src/service.rs index 56f8915..773234d 100644 --- a/src/service.rs +++ b/src/service.rs @@ -15,20 +15,26 @@ mod util; type SvcResponse = Result, String>; #[derive(Clone)] -pub struct Service<'svc> { - domain_manager: sync::Arc, +pub struct Service<'svc, DomainManager> +where + DomainManager: domain::manager::BoxedManager, +{ + domain_manager: DomainManager, target_a: net::Ipv4Addr, passphrase: String, http_domain: String, handlebars: handlebars::Handlebars<'svc>, } -pub fn new<'svc>( - domain_manager: sync::Arc, +pub fn new<'svc, DomainManager>( + domain_manager: DomainManager, target_a: net::Ipv4Addr, passphrase: String, http_domain: String, -) -> Service<'svc> { +) -> Service<'svc, DomainManager> +where + DomainManager: domain::manager::BoxedManager, +{ Service { domain_manager, target_a, @@ -60,7 +66,10 @@ struct DomainSyncArgs { passphrase: String, } -impl<'svc> Service<'svc> { +impl<'svc, DomainManager> Service<'svc, DomainManager> +where + DomainManager: domain::manager::BoxedManager, +{ fn serve_string(&self, status_code: u16, path: &'_ str, body: Vec) -> SvcResponse { let content_type = mime_guess::from_path(path) .first_or_octet_stream() @@ -280,10 +289,13 @@ impl<'svc> Service<'svc> { } } -pub async fn handle_request( - svc: sync::Arc>, +pub async fn handle_request( + svc: sync::Arc>, req: Request, -) -> Result, Infallible> { +) -> Result, Infallible> +where + DomainManager: domain::manager::BoxedManager, +{ match handle_request_inner(svc, req).await { Ok(res) => Ok(res), Err(err) => panic!("unexpected error {err}"), @@ -297,7 +309,13 @@ fn strip_port(host: &str) -> &str { } } -pub async fn handle_request_inner(svc: sync::Arc>, req: Request) -> SvcResponse { +pub async fn handle_request_inner( + svc: sync::Arc>, + req: Request, +) -> SvcResponse +where + DomainManager: domain::manager::BoxedManager, +{ let maybe_host = match ( req.headers() .get("Host")