domani/src/origin/store/mux.rs

169 lines
4.7 KiB
Rust
Raw Normal View History

use crate::error::unexpected::Mappable;
use crate::origin::{self, store};
use std::sync;
2023-06-29 14:54:55 +00:00
pub struct Store<F, S>
where
2023-06-29 14:54:55 +00:00
S: store::Store + 'static,
F: Fn(&origin::Descr) -> Option<S> + Sync + Send,
{
mapping_fn: F,
stores: Vec<S>,
}
2023-06-29 14:54:55 +00:00
impl<F, S> Store<F, S>
where
S: store::Store + 'static,
2023-06-29 14:54:55 +00:00
F: Fn(&origin::Descr) -> Option<S> + Sync + Send,
{
2023-06-29 14:54:55 +00:00
pub fn new(mapping_fn: F, stores: Vec<S>) -> Store<F, S> {
Store { mapping_fn, stores }
}
}
impl<F, S> store::Store for Store<F, S>
where
2023-06-29 14:54:55 +00:00
S: store::Store + 'static,
F: Fn(&origin::Descr) -> Option<S> + Sync + Send,
{
fn sync(&self, descr: origin::Descr, limits: store::Limits) -> Result<(), store::SyncError> {
(self.mapping_fn)(&descr)
2023-07-03 12:30:41 +00:00
.or_unexpected_while(format!("mapping {:?} to store", &descr))?
.sync(descr, limits)
}
fn get(&self, descr: origin::Descr) -> Result<sync::Arc<dyn origin::Origin>, store::GetError> {
(self.mapping_fn)(&descr)
2023-07-03 12:30:41 +00:00
.or_unexpected_while(format!("mapping {:?} to store", &descr))?
.get(descr)
}
fn all_descrs(&self) -> Result<Vec<origin::Descr>, store::AllDescrsError> {
let mut res = Vec::<origin::Descr>::new();
for store in self.stores.iter() {
store.all_descrs()?.into_iter().collect_into(&mut res);
}
Ok(res)
}
}
#[cfg(test)]
mod tests {
use crate::origin::{self, store};
use mockall::predicate;
2023-07-03 12:30:41 +00:00
use std::sync;
struct Harness {
descr_a: origin::Descr,
descr_b: origin::Descr,
descr_unknown: origin::Descr,
store_a: sync::Arc<sync::Mutex<store::MockStore>>,
store_b: sync::Arc<sync::Mutex<store::MockStore>>,
store: Box<dyn store::Store>,
}
2023-07-03 12:30:41 +00:00
impl Harness {
fn new() -> Harness {
let descr_a = origin::Descr::Git {
url: "A".to_string(),
branch_name: "A".to_string(),
};
let descr_b = origin::Descr::Git {
url: "B".to_string(),
branch_name: "B".to_string(),
};
let store_a = store::new_mock();
let store_b = store::new_mock();
Harness {
descr_a: descr_a.clone(),
descr_b: descr_b.clone(),
descr_unknown: origin::Descr::Git {
url: "X".to_string(),
branch_name: "X".to_string(),
},
2023-07-03 12:30:41 +00:00
store_a: store_a.clone(),
store_b: store_b.clone(),
store: Box::from(super::Store::new(
{
let store_a = store_a.clone();
let store_b = store_b.clone();
move |descr| match descr {
&origin::Descr::Git { ref url, .. } if url == "A" => {
Some(store_a.clone())
}
&origin::Descr::Git { ref url, .. } if url == "B" => {
Some(store_b.clone())
}
_ => None,
}
},
vec![store_a.clone(), store_b.clone()],
)),
}
}
}
#[test]
fn sync() {
let h = Harness::new();
h.store_a
.lock()
.unwrap()
.expect_sync()
.with(predicate::eq(h.descr_a.clone()), predicate::always())
.times(1)
.return_const(Ok::<(), store::SyncError>(()));
assert_eq!(Ok(()), h.store.sync(h.descr_a.clone(), store::Limits {}));
2023-07-03 12:30:41 +00:00
h.store_b
.lock()
.unwrap()
.expect_sync()
2023-07-03 12:30:41 +00:00
.with(predicate::eq(h.descr_b.clone()), predicate::always())
.times(1)
.return_const(Ok::<(), store::SyncError>(()));
2023-07-03 12:30:41 +00:00
assert_eq!(Ok(()), h.store.sync(h.descr_b.clone(), store::Limits {}));
assert!(h
.store
.sync(h.descr_unknown.clone(), store::Limits {})
.is_err());
}
#[test]
fn all_descrs() {
let h = Harness::new();
h.store_a
.lock()
.unwrap()
.expect_all_descrs()
.times(1)
.return_const(Ok::<Vec<origin::Descr>, store::AllDescrsError>(vec![h
.descr_a
.clone()]));
h.store_b
.lock()
.unwrap()
.expect_all_descrs()
.times(1)
.return_const(Ok::<Vec<origin::Descr>, store::AllDescrsError>(vec![h
.descr_b
.clone()]));
assert_eq!(
Ok(vec![h.descr_a.clone(), h.descr_b.clone()]),
h.store.all_descrs(),
)
}
}