From 32a88299721393a5cbd3b369091de7cb77da349c Mon Sep 17 00:00:00 2001 From: Determinant Date: Wed, 10 Jun 2020 16:17:40 -0400 Subject: add failure generator in test --- tests/common/mod.rs | 77 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 15 deletions(-) (limited to 'tests/common') diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 7a7e42a..2fd7bbb 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -32,15 +32,19 @@ impl std::ops::Deref for FileContentEmul { fn deref(&self) -> &Self::Target {&self.0} } -type FailGen = std::iter::Iterator; +pub trait FailGen { + fn next_fail(&self) -> bool; +} /// Emulate the a virtual file handle. -pub struct WALFileEmul { +pub struct WALFileEmul { file: Rc, + fgen: Rc } -impl WALFile for WALFileEmul { +impl WALFile for WALFileEmul { fn allocate(&self, offset: WALPos, length: usize) -> Result<(), ()> { + if self.fgen.next_fail() { return Err(()) } let offset = offset as usize; if offset + length > self.file.borrow().len() { self.file.borrow_mut().resize(offset + length, 0) @@ -50,17 +54,20 @@ impl WALFile for WALFileEmul { } fn truncate(&self, length: usize) -> Result<(), ()> { + if self.fgen.next_fail() { return Err(()) } self.file.borrow_mut().resize(length, 0); Ok(()) } fn write(&self, offset: WALPos, data: WALBytes) -> Result<(), ()> { + if self.fgen.next_fail() { return Err(()) } let offset = offset as usize; &self.file.borrow_mut()[offset..offset + data.len()].copy_from_slice(&data); Ok(()) } fn read(&self, offset: WALPos, length: usize) -> Result, ()> { + if self.fgen.next_fail() { return Err(()) } let offset = offset as usize; let file = self.file.borrow(); if offset + length > file.len() { Ok(None) } @@ -70,7 +77,7 @@ impl WALFile for WALFileEmul { } } -pub struct WALStoreEmulState{ +pub struct WALStoreEmulState { files: HashMap>, } @@ -79,23 +86,32 @@ impl WALStoreEmulState { } /// Emulate the persistent storage state. -pub struct WALStoreEmul<'a>(&'a mut WALStoreEmulState); +pub struct WALStoreEmul<'a, G: FailGen> { + state: &'a mut WALStoreEmulState, + fgen: Rc +} -impl<'a> WALStoreEmul<'a> { - pub fn new(state: &'a mut WALStoreEmulState) -> Self { - WALStoreEmul(state) +impl<'a, G: FailGen> WALStoreEmul<'a, G> { + pub fn new(state: &'a mut WALStoreEmulState, fail_gen: G) -> Self { + WALStoreEmul { state, fgen: Rc::new(fail_gen) } } } -impl<'a> WALStore for WALStoreEmul<'a> { +impl<'a, G: 'static + FailGen> WALStore for WALStoreEmul<'a, G> { type FileNameIter = std::vec::IntoIter; fn open_file(&mut self, filename: &str, touch: bool) -> Result, ()> { - match self.0.files.entry(filename.to_string()) { - Entry::Occupied(e) => Ok(Box::new(WALFileEmul { file: e.get().clone() })), + if self.fgen.next_fail() { return Err(()) } + match self.state.files.entry(filename.to_string()) { + Entry::Occupied(e) => Ok(Box::new(WALFileEmul { + file: e.get().clone(), + fgen: self.fgen.clone() + })), Entry::Vacant(e) => if touch { - Ok(Box::new( - WALFileEmul { file: e.insert(Rc::new(FileContentEmul::new())).clone() })) + Ok(Box::new(WALFileEmul { + file: e.insert(Rc::new(FileContentEmul::new())).clone(), + fgen: self.fgen.clone() + })) } else { Err(()) } @@ -103,19 +119,50 @@ impl<'a> WALStore for WALStoreEmul<'a> { } fn remove_file(&mut self, filename: &str) -> Result<(), ()> { - self.0.files.remove(filename).ok_or(()).and_then(|_| Ok(())) + if self.fgen.next_fail() { return Err(()) } + self.state.files.remove(filename).ok_or(()).and_then(|_| Ok(())) } fn enumerate_files(&self) -> Result { + if self.fgen.next_fail() { return Err(()) } let mut logfiles = Vec::new(); - for (fname, _) in self.0.files.iter() { + for (fname, _) in self.state.files.iter() { logfiles.push(fname.clone()) } Ok(logfiles.into_iter()) } fn apply_payload(&mut self, payload: WALBytes) -> Result<(), ()> { + if self.fgen.next_fail() { return Err(()) } println!("apply_payload(payload={})", std::str::from_utf8(&payload).unwrap()); Ok(()) } } + +pub struct SingleFailGen { + cnt: std::cell::Cell, + fail_point: usize +} + +impl SingleFailGen { + pub fn new(fail_point: usize) -> Self { + SingleFailGen { + cnt: std::cell::Cell::new(0), + fail_point + } + } +} + +impl FailGen for SingleFailGen { + fn next_fail(&self) -> bool { + let c = self.cnt.get(); + self.cnt.set(c + 1); + c == self.fail_point + } +} + +pub struct ZeroFailGen; + +impl FailGen for ZeroFailGen { + fn next_fail(&self) -> bool { false } +} -- cgit v1.2.3-70-g09d2