Inject failpoints with the fail library
This commit is contained in:
parent
95a597c8ea
commit
064b754786
|
@ -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",
|
||||||
|
|
|
@ -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"] }
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue