Inject failpoints with the fail library

This commit is contained in:
Savanni D'Gerinel 2022-11-25 12:08:41 -05:00
parent 95a597c8ea
commit 064b754786
3 changed files with 42 additions and 13 deletions

12
server/Cargo.lock generated
View File

@ -103,6 +103,17 @@ dependencies = [
"crypto-common", "crypto-common",
] ]
[[package]]
name = "fail"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe5e43d0f78a42ad591453aedb1d7ae631ce7ee445c7643691055a9ed8d3b01c"
dependencies = [
"log",
"once_cell",
"rand",
]
[[package]] [[package]]
name = "fallible-iterator" name = "fallible-iterator"
version = "0.2.0" version = "0.2.0"
@ -716,6 +727,7 @@ name = "server"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"fail",
"rand", "rand",
"rusqlite", "rusqlite",
"serde", "serde",

View File

@ -8,6 +8,7 @@ default-run = "server"
[dependencies] [dependencies]
anyhow = { version = "1" } anyhow = { version = "1" }
fail = { version = "0.5" }
rand = { version = "0.8" } rand = { version = "0.8" }
rusqlite = { version = "0.26" } rusqlite = { version = "0.26" }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }

View File

@ -1,4 +1,5 @@
use crate::errors::{error, fatal, ok, AppResult, FatalError}; use crate::errors::{error, fatal, ok, AppResult, FatalError};
use fail::fail_point;
use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ValueRef}; use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ValueRef};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
@ -179,8 +180,7 @@ pub struct MemoryAuth {
impl AuthenticationDB for MemoryAuth { impl AuthenticationDB for MemoryAuth {
fn create_user(&mut self, username: Username) -> AppResult<UserId, AuthenticationError> { fn create_user(&mut self, username: Username) -> AppResult<UserId, AuthenticationError> {
#[cfg(test)] fail_point!("create-user", |_| Err(FatalError::DiskFull));
let _ = maybe_fail::<AuthenticationError>(vec![])?;
if self.users.contains_key(&username) { if self.users.contains_key(&username) {
return Ok(Err(AuthenticationError::DuplicateUsername)); return Ok(Err(AuthenticationError::DuplicateUsername));
@ -310,15 +310,30 @@ impl AuthenticationDB for MemoryAuth {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use fail::FailScenario;
use std::panic;
fn with_memory_db<F>(test: F) fn with_memory_db<F>(test: F)
where where
F: Fn(Box<dyn AuthenticationDB>), F: Fn(Box<dyn AuthenticationDB>) -> () + panic::UnwindSafe,
{ {
let authdb: Box<MemoryAuth> = Box::new(Default::default()); let authdb: Box<MemoryAuth> = Box::new(Default::default());
test(authdb); test(authdb);
} }
fn with_failpoints<F>(failpoints: Vec<&str>, test: F)
where
F: Fn() -> () + panic::UnwindSafe,
{
let scenario = FailScenario::setup();
for fp in failpoints {
fail::cfg(fp, "return()").unwrap();
}
let result = panic::catch_unwind(test);
scenario.teardown();
assert!(result.is_ok())
}
#[test] #[test]
fn it_can_create_a_user() { fn it_can_create_a_user() {
fn test_case(mut authdb: Box<dyn AuthenticationDB>) { fn test_case(mut authdb: Box<dyn AuthenticationDB>) {
@ -331,7 +346,8 @@ mod test {
assert_eq!(authdb.get_username(&userid).unwrap(), Ok(username)); assert_eq!(authdb.get_username(&userid).unwrap(), Ok(username));
assert!(authdb.list_users().unwrap().unwrap().contains(&userid)); assert!(authdb.list_users().unwrap().unwrap().contains(&userid));
} }
with_memory_db(test_case);
with_failpoints(vec![], || with_memory_db(test_case));
} }
#[test] #[test]
@ -347,7 +363,7 @@ mod test {
Err(AuthenticationError::DuplicateUsername) Err(AuthenticationError::DuplicateUsername)
); );
} }
with_memory_db(test_case); with_failpoints(vec![], || with_memory_db(test_case));
} }
#[test] #[test]
@ -367,7 +383,7 @@ mod test {
.expect("no fatal errors") .expect("no fatal errors")
.expect("to receive a session token"); .expect("to receive a session token");
} }
with_memory_db(test_case); with_failpoints(vec![], || with_memory_db(test_case));
} }
#[test] #[test]
@ -397,7 +413,7 @@ mod test {
(garrus, garrus_id) (garrus, garrus_id)
); );
} }
with_memory_db(test_case); with_failpoints(vec![], || with_memory_db(test_case));
} }
#[test] #[test]
@ -413,7 +429,7 @@ mod test {
authdb.authenticate(invite1).unwrap().unwrap(); authdb.authenticate(invite1).unwrap().unwrap();
authdb.authenticate(invite2).unwrap().unwrap(); authdb.authenticate(invite2).unwrap().unwrap();
} }
with_memory_db(test_case); with_failpoints(vec![], || with_memory_db(test_case));
} }
#[test] #[test]
@ -439,7 +455,7 @@ mod test {
(username, userid) (username, userid)
); );
} }
with_memory_db(test_case); with_failpoints(vec![], || with_memory_db(test_case));
} }
#[test] #[test]
@ -461,7 +477,7 @@ mod test {
let reuse_result = authdb.authenticate(invitation).expect("no fatal errors"); let reuse_result = authdb.authenticate(invitation).expect("no fatal errors");
assert_eq!(reuse_result, Err(AuthenticationError::InvalidInvitation)); assert_eq!(reuse_result, Err(AuthenticationError::InvalidInvitation));
} }
with_memory_db(test_case); with_failpoints(vec![], || with_memory_db(test_case));
} }
#[test] #[test]
@ -493,7 +509,7 @@ mod test {
Err(AuthenticationError::InvalidInvitation) Err(AuthenticationError::InvalidInvitation)
); );
} }
with_memory_db(test_case); with_failpoints(vec![], || with_memory_db(test_case));
} }
#[test] #[test]
@ -516,7 +532,7 @@ mod test {
Err(AuthenticationError::InvalidSession) Err(AuthenticationError::InvalidSession)
); );
} }
with_memory_db(test_case); with_failpoints(vec![], || with_memory_db(test_case));
} }
#[test] #[test]
@ -541,6 +557,6 @@ mod test {
Err(AuthenticationError::InvalidInvitation) Err(AuthenticationError::InvalidInvitation)
); );
} }
with_memory_db(test_case); with_failpoints(vec![], || with_memory_db(test_case));
} }
} }