update store tests

This commit is contained in:
mpostma 2021-10-05 11:47:50 +02:00
parent 85ae34cf9f
commit ece4c739f4
2 changed files with 211 additions and 131 deletions

View File

@ -103,20 +103,31 @@ pub mod test {
} }
} }
pub struct StubBuilder<'a> { pub struct StubBuilder<'a, A, R> {
name: String, name: String,
store: &'a StubStore, store: &'a StubStore,
times: Option<usize>, times: Option<usize>,
_f: std::marker::PhantomData<fn(A) -> R>
} }
impl<'a> StubBuilder<'a> { impl<'a, A: 'static, R: 'static> StubBuilder<'a, A, R> {
/// Asserts the stub has been called exactly `times` times.
#[must_use] #[must_use]
pub fn times(mut self, times: usize) -> Self { pub fn times(mut self, times: usize) -> Self {
self.times = Some(times); self.times = Some(times);
self self
} }
pub fn then<A: 'static, R: 'static>(self, f: impl Fn(A) -> R + Sync + Send + 'static) { /// Asserts the stub has been called exactly once.
#[must_use]
pub fn once(mut self) -> Self {
self.times = Some(1);
self
}
/// The function that will be called when the stub is called. This needs to be called to
/// actually build the stub and register it to the stub store.
pub fn then(self, f: impl Fn(A) -> R + Sync + Send + 'static) {
let stub = Stub { let stub = Stub {
stub: Box::new(f), stub: Box::new(f),
times: self.times, times: self.times,
@ -130,21 +141,18 @@ pub mod test {
/// Mocker allows to stub metod call on any struct. you can register stubs by calling /// Mocker allows to stub metod call on any struct. you can register stubs by calling
/// `Mocker::when` and retrieve it in the proxy implementation when with `Mocker::get`. /// `Mocker::when` and retrieve it in the proxy implementation when with `Mocker::get`.
///
/// Mocker uses unsafe code to erase function types, because `Any` is too restrictive with it's
/// requirement for all stub arguments to be static. Because of that panic inside a stub is UB,
/// and it has been observed to crash with an illegal hardware instruction. Use with caution.
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Mocker { pub struct Mocker {
store: StubStore, store: StubStore,
} }
impl Mocker { impl Mocker {
pub fn when(&self, name: &str) -> StubBuilder { pub fn when<A, R>(&self, name: &str) -> StubBuilder<A, R> {
StubBuilder { StubBuilder {
name: name.to_string(), name: name.to_string(),
store: &self.store, store: &self.store,
times: None, times: None,
_f: std::marker::PhantomData,
} }
} }
@ -191,7 +199,7 @@ pub mod test {
pub fn handle_update(&self, update: Processing) -> std::result::Result<Processed, Failed> { pub fn handle_update(&self, update: Processing) -> std::result::Result<Processed, Failed> {
match self { match self {
MockIndex::Vrai(index) => index.handle_update(update), MockIndex::Vrai(index) => index.handle_update(update),
MockIndex::Faux(_) => todo!(), MockIndex::Faux(faux) => faux.get("handle_update").call(update),
} }
} }

View File

@ -569,149 +569,221 @@ impl UpdateStore {
} }
} }
//#[cfg(test)] #[cfg(test)]
//mod test { mod test {
//use super::*; use futures::future::ok;
//use crate::index_controller::{ use mockall::predicate::eq;
//index_actor::{error::IndexActorError, MockIndexActorHandle},
//UpdateResult,
//};
//use futures::future::ok; use crate::index::error::IndexError;
use crate::index::test::Mocker;
use crate::index_controller::index_resolver::uuid_store::MockUuidStore;
use crate::index_controller::index_resolver::index_store::MockIndexStore;
use crate::index_controller::updates::status::{Failed, Processed};
//#[actix_rt::test] use super::*;
//async fn test_next_id() {
//let dir = tempfile::tempdir_in(".").unwrap();
//let mut options = EnvOpenOptions::new();
//let handle = Arc::new(MockIndexActorHandle::new());
//options.map_size(4096 * 100);
//let update_store = UpdateStore::open(
//options,
//dir.path(),
//handle,
//Arc::new(AtomicBool::new(false)),
//)
//.unwrap();
//let index1_uuid = Uuid::new_v4(); #[actix_rt::test]
//let index2_uuid = Uuid::new_v4(); async fn test_next_id() {
let dir = tempfile::tempdir_in(".").unwrap();
let mut options = EnvOpenOptions::new();
let index_store = MockIndexStore::new();
let uuid_store = MockUuidStore::new();
let index_resolver = IndexResolver::new(uuid_store, index_store);
let update_file_store = UpdateFileStore::new(dir.path()).unwrap();
options.map_size(4096 * 100);
let update_store = UpdateStore::open(
options,
dir.path(),
Arc::new(index_resolver),
Arc::new(AtomicBool::new(false)),
update_file_store,
)
.unwrap();
//let mut txn = update_store.env.write_txn().unwrap(); let index1_uuid = Uuid::new_v4();
//let ids = update_store.next_update_id(&mut txn, index1_uuid).unwrap(); let index2_uuid = Uuid::new_v4();
//txn.commit().unwrap();
//assert_eq!((0, 0), ids);
//let mut txn = update_store.env.write_txn().unwrap(); let mut txn = update_store.env.write_txn().unwrap();
//let ids = update_store.next_update_id(&mut txn, index2_uuid).unwrap(); let ids = update_store.next_update_id(&mut txn, index1_uuid).unwrap();
//txn.commit().unwrap(); txn.commit().unwrap();
//assert_eq!((1, 0), ids); assert_eq!((0, 0), ids);
//let mut txn = update_store.env.write_txn().unwrap(); let mut txn = update_store.env.write_txn().unwrap();
//let ids = update_store.next_update_id(&mut txn, index1_uuid).unwrap(); let ids = update_store.next_update_id(&mut txn, index2_uuid).unwrap();
//txn.commit().unwrap(); txn.commit().unwrap();
//assert_eq!((2, 1), ids); assert_eq!((1, 0), ids);
//}
//#[actix_rt::test] let mut txn = update_store.env.write_txn().unwrap();
//async fn test_register_update() { let ids = update_store.next_update_id(&mut txn, index1_uuid).unwrap();
//let dir = tempfile::tempdir_in(".").unwrap(); txn.commit().unwrap();
//let mut options = EnvOpenOptions::new(); assert_eq!((2, 1), ids);
//let handle = Arc::new(MockIndexActorHandle::new()); }
//options.map_size(4096 * 100);
//let update_store = UpdateStore::open(
//options,
//dir.path(),
//handle,
//Arc::new(AtomicBool::new(false)),
//)
//.unwrap();
//let meta = UpdateMeta::ClearDocuments;
//let uuid = Uuid::new_v4();
//let store_clone = update_store.clone();
//tokio::task::spawn_blocking(move || {
//store_clone.register_update(meta, None, uuid).unwrap();
//})
//.await
//.unwrap();
//let txn = update_store.env.read_txn().unwrap(); #[actix_rt::test]
//assert!(update_store async fn test_register_update() {
//.pending_queue let dir = tempfile::tempdir_in(".").unwrap();
//.get(&txn, &(0, uuid, 0)) let index_store = MockIndexStore::new();
//.unwrap() let uuid_store = MockUuidStore::new();
//.is_some()); let index_resolver = IndexResolver::new(uuid_store, index_store);
//} let update_file_store = UpdateFileStore::new(dir.path()).unwrap();
let mut options = EnvOpenOptions::new();
options.map_size(4096 * 100);
let update_store = UpdateStore::open(
options,
dir.path(),
Arc::new(index_resolver),
Arc::new(AtomicBool::new(false)),
update_file_store,
)
.unwrap();
let update = Update::ClearDocuments;
let uuid = Uuid::new_v4();
let store_clone = update_store.clone();
tokio::task::spawn_blocking(move || {
store_clone.register_update(uuid, update).unwrap();
})
.await
.unwrap();
//#[actix_rt::test] let txn = update_store.env.read_txn().unwrap();
//async fn test_process_update() { assert!(update_store
//let dir = tempfile::tempdir_in(".").unwrap(); .pending_queue
//let mut handle = MockIndexActorHandle::new(); .get(&txn, &(0, uuid, 0))
.unwrap()
.is_some());
}
//handle #[actix_rt::test]
//.expect_update() async fn test_process_update_success() {
//.times(2) let dir = tempfile::tempdir_in(".").unwrap();
//.returning(|_index_uuid, processing, _file| { let index_uuid = Uuid::new_v4();
//if processing.id() == 0 {
//Box::pin(ok(Ok(processing.process(UpdateResult::Other))))
//} else {
//Box::pin(ok(Err(
//processing.fail(IndexActorError::ExistingPrimaryKey.into())
//)))
//}
//});
//let handle = Arc::new(handle); let mut index_store = MockIndexStore::new();
index_store
.expect_get()
.with(eq(index_uuid))
.returning(|_uuid| {
let mocker = Mocker::default();
mocker
.when::<Processing, std::result::Result<Processed, Failed>>("handle_update")
.once()
.then(|update| Ok(update.process(status::UpdateResult::Other)));
//let mut options = EnvOpenOptions::new(); Box::pin(ok(Some(Index::faux(mocker))))
//options.map_size(4096 * 100); });
//let store = UpdateStore::open(
//options,
//dir.path(),
//handle.clone(),
//Arc::new(AtomicBool::new(false)),
//)
//.unwrap();
//// wait a bit for the event loop exit. let uuid_store = MockUuidStore::new();
//tokio::time::sleep(std::time::Duration::from_millis(50)).await; let index_resolver = Arc::new(IndexResolver::new(uuid_store, index_store));
//let mut txn = store.env.write_txn().unwrap();
//let update = Enqueued::new(UpdateMeta::ClearDocuments, 0, None); let update_file_store = UpdateFileStore::new(dir.path()).unwrap();
//let uuid = Uuid::new_v4(); let mut options = EnvOpenOptions::new();
options.map_size(4096 * 100);
let store = UpdateStore::open(
options,
dir.path(),
index_resolver.clone(),
Arc::new(AtomicBool::new(false)),
update_file_store,
)
.unwrap();
//store // wait a bit for the event loop exit.
//.pending_queue tokio::time::sleep(std::time::Duration::from_millis(50)).await;
//.put(&mut txn, &(0, uuid, 0), &update)
//.unwrap();
//let update = Enqueued::new(UpdateMeta::ClearDocuments, 1, None); let mut txn = store.env.write_txn().unwrap();
//store let update = Enqueued::new(Update::ClearDocuments, 0);
//.pending_queue
//.put(&mut txn, &(1, uuid, 1), &update)
//.unwrap();
//txn.commit().unwrap(); store
.pending_queue
.put(&mut txn, &(0, index_uuid, 0), &update)
.unwrap();
//// Process the pending, and check that it has been moved to the update databases, and
//// removed from the pending database.
//let store_clone = store.clone();
//tokio::task::spawn_blocking(move || {
//store_clone.process_pending_update(handle.clone()).unwrap();
//store_clone.process_pending_update(handle).unwrap();
//})
//.await
//.unwrap();
//let txn = store.env.read_txn().unwrap(); txn.commit().unwrap();
//assert!(store.pending_queue.first(&txn).unwrap().is_none()); // Process the pending, and check that it has been moved to the update databases, and
//let update = store.updates.get(&txn, &(uuid, 0)).unwrap().unwrap(); // removed from the pending database.
let store_clone = store.clone();
tokio::task::spawn_blocking(move || {
store_clone.process_pending_update(index_resolver).unwrap();
})
.await
.unwrap();
//assert!(matches!(update, UpdateStatus::Processed(_))); let txn = store.env.read_txn().unwrap();
//let update = store.updates.get(&txn, &(uuid, 1)).unwrap().unwrap();
//assert!(matches!(update, UpdateStatus::Failed(_))); assert!(store.pending_queue.first(&txn).unwrap().is_none());
//} let update = store.updates.get(&txn, &(index_uuid, 0)).unwrap().unwrap();
//}
assert!(matches!(update, UpdateStatus::Processed(_)));
}
#[actix_rt::test]
async fn test_process_update_failure() {
let dir = tempfile::tempdir_in(".").unwrap();
let index_uuid = Uuid::new_v4();
let mut index_store = MockIndexStore::new();
index_store
.expect_get()
.with(eq(index_uuid))
.returning(|_uuid| {
let mocker = Mocker::default();
mocker
.when::<Processing, std::result::Result<Processed, Failed>>("handle_update")
.once()
.then(|update| Err(update.fail(IndexError::ExistingPrimaryKey)));
Box::pin(ok(Some(Index::faux(mocker))))
});
let uuid_store = MockUuidStore::new();
let index_resolver = Arc::new(IndexResolver::new(uuid_store, index_store));
let update_file_store = UpdateFileStore::new(dir.path()).unwrap();
let mut options = EnvOpenOptions::new();
options.map_size(4096 * 100);
let store = UpdateStore::open(
options,
dir.path(),
index_resolver.clone(),
Arc::new(AtomicBool::new(false)),
update_file_store,
)
.unwrap();
// wait a bit for the event loop exit.
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
let mut txn = store.env.write_txn().unwrap();
let update = Enqueued::new(Update::ClearDocuments, 0);
store
.pending_queue
.put(&mut txn, &(0, index_uuid, 0), &update)
.unwrap();
txn.commit().unwrap();
// Process the pending, and check that it has been moved to the update databases, and
// removed from the pending database.
let store_clone = store.clone();
tokio::task::spawn_blocking(move || {
store_clone.process_pending_update(index_resolver).unwrap();
})
.await
.unwrap();
let txn = store.env.read_txn().unwrap();
assert!(store.pending_queue.first(&txn).unwrap().is_none());
let update = store.updates.get(&txn, &(index_uuid, 0)).unwrap().unwrap();
assert!(matches!(update, UpdateStatus::Failed(_)));
}
}