Skip to content

Commit

Permalink
unit-test keret service logic
Browse files Browse the repository at this point in the history
  • Loading branch information
kelko committed Oct 14, 2024
1 parent ce3919d commit d968479
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 1 deletion.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion src/keret-service-transmit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,21 @@ use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::time::Duration;

#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct ActionReport {
timestamp: DateTime<Utc>,
duration: Duration,
}

impl ActionReport {
pub fn new(timestamp: DateTime<Utc>, duration: Duration) -> Self {
Self {
timestamp,
duration,
}
}
}

impl From<u64> for ActionReport {
fn from(value: u64) -> Self {
Self {
Expand Down
2 changes: 2 additions & 0 deletions src/keret-service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
snafu = { version = "0.8.4" }
prometheus = { version = "0.13.4", features = ["process"] }
lazy_static = "1.5.0"
mockall = "0.13.0"
chrono = { version = "0.4.38" }
keret-service-transmit = { path = "../keret-service-transmit" }
3 changes: 3 additions & 0 deletions src/keret-service/src/repository/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ pub enum RepositoryError {
},
#[snafu(display("Lock is poisoned, can't acquire"))]
LockPoisoned { backtrace: Option<Backtrace> },
#[cfg(test)]
#[snafu(display("Test Error"))]
ErrorOnTest,
}

pub(crate) trait RepositoryStorage {
Expand Down
236 changes: 236 additions & 0 deletions src/keret-service/src/repository/storage_based_repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,239 @@ impl ToDoRepository for StorageBasedRepository {
Ok(new_index)
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::repository::*;
use chrono::{DateTime, Utc};
use mockall::mock;
use mockall::predicate::eq;
use std::time::Duration;

mock! {
MyRepositoryStorage {}

impl RepositoryStorage for MyRepositoryStorage {
fn list(&self) -> Result<Vec<ActionReport>, RepositoryError>;
fn store(&mut self, list: Vec<ActionReport>) -> Result<(), RepositoryError>;
}
}

#[test]
fn list_with_empty_storage_returns_empty_vec() {
// arrange
let mut storage = MockMyRepositoryStorage::default();
storage.expect_list().once().returning(|| Ok(vec![]));
let repo = StorageBasedRepository::new(storage);

// act
let actual = repo.list();

// assert
assert!(actual.is_ok());
assert_eq!(actual.unwrap(), vec![]);
}

#[test]
fn list_with_filled_storage_returns_all_elements() {
// arrange
let mut storage = MockMyRepositoryStorage::default();
storage.expect_list().once().returning(|| {
Ok(vec![
ActionReport::new(
DateTime::<Utc>::from_timestamp(10, 0).unwrap(),
Duration::new(1, 0),
),
ActionReport::new(
DateTime::<Utc>::from_timestamp(20, 0).unwrap(),
Duration::new(1, 0),
),
ActionReport::new(
DateTime::<Utc>::from_timestamp(30, 0).unwrap(),
Duration::new(1, 0),
),
])
});
let repo = StorageBasedRepository::new(storage);

// act
let actual = repo.list();

// assert
assert!(actual.is_ok());
assert_eq!(
actual.unwrap(),
vec![
ActionReport::new(
DateTime::<Utc>::from_timestamp(10, 0).unwrap(),
Duration::new(1, 0)
),
ActionReport::new(
DateTime::<Utc>::from_timestamp(20, 0).unwrap(),
Duration::new(1, 0)
),
ActionReport::new(
DateTime::<Utc>::from_timestamp(30, 0).unwrap(),
Duration::new(1, 0)
),
]
);
}

#[test]
fn list_failing_read_from_storage_returns_error() {
// arrange
let mut storage = MockMyRepositoryStorage::default();
storage
.expect_list()
.once()
.returning(|| ErrorOnTestSnafu.fail());
let repo = StorageBasedRepository::new(storage);

// act
let actual = repo.list();

// assert
assert!(matches!(actual, Err(RepositoryError::ErrorOnTest)));
}

#[test]
fn add_on_empty_storage_writes_one_element() {
// arrange
let mut storage = MockMyRepositoryStorage::default();
storage.expect_list().once().returning(|| Ok(vec![]));
storage
.expect_store()
.once()
.with(eq(vec![ActionReport::new(
DateTime::<Utc>::from_timestamp(10, 0).unwrap(),
Duration::new(1, 0),
)]))
.returning(|_| Ok(()));
let repo = StorageBasedRepository::new(storage);

// act
let actual = repo.add(ActionReport::new(
DateTime::<Utc>::from_timestamp(10, 0).unwrap(),
Duration::new(1, 0),
));

// assert -> mockall
assert!(actual.is_ok());
assert_eq!(actual.unwrap(), 0);
}

#[test]
fn add_on_filled_storage_writes_all_plus_one_elements() {
// arrange
let mut storage = MockMyRepositoryStorage::default();
storage.expect_list().once().returning(|| {
Ok(vec![
ActionReport::new(
DateTime::<Utc>::from_timestamp(10, 0).unwrap(),
Duration::new(1, 0),
),
ActionReport::new(
DateTime::<Utc>::from_timestamp(20, 0).unwrap(),
Duration::new(1, 0),
),
])
});
storage
.expect_store()
.once()
.with(eq(vec![
ActionReport::new(
DateTime::<Utc>::from_timestamp(10, 0).unwrap(),
Duration::new(1, 0),
),
ActionReport::new(
DateTime::<Utc>::from_timestamp(20, 0).unwrap(),
Duration::new(1, 0),
),
ActionReport::new(
DateTime::<Utc>::from_timestamp(90, 0).unwrap(),
Duration::new(1, 0),
),
]))
.returning(|_| Ok(()));
let repo = StorageBasedRepository::new(storage);

// act
let actual = repo.add(ActionReport::new(
DateTime::<Utc>::from_timestamp(90, 0).unwrap(),
Duration::new(1, 0),
));

// assert -> mockall
assert!(actual.is_ok());
assert_eq!(actual.unwrap(), 2);
}

#[test]
fn add_failing_read_from_storage_does_not_store() {
// arrange
let mut storage = MockMyRepositoryStorage::default();
storage
.expect_list()
.once()
.returning(|| ErrorOnTestSnafu.fail());
storage.expect_store().never().returning(|_| Ok(()));
let repo = StorageBasedRepository::new(storage);

// act
let _ = repo.add(ActionReport::new(
DateTime::<Utc>::from_timestamp(90, 0).unwrap(),
Duration::new(1, 0),
));

// assert -> mockall
}

#[test]
fn add_failing_read_from_storage_returns_error() {
// arrange
let mut storage = MockMyRepositoryStorage::default();
storage
.expect_list()
.once()
.returning(|| ErrorOnTestSnafu.fail());
storage.expect_store().never().returning(|_| Ok(()));
let repo = StorageBasedRepository::new(storage);

// act
let actual = repo.add(ActionReport::new(
DateTime::<Utc>::from_timestamp(90, 0).unwrap(),
Duration::new(1, 0),
));

// assert
assert!(matches!(actual, Err(RepositoryError::ErrorOnTest)));
}

#[test]
fn add_failing_store_in_storage_returns_error() {
// arrange
let mut storage = MockMyRepositoryStorage::default();
storage.expect_list().once().returning(|| Ok(vec![]));
storage
.expect_store()
.once()
.with(eq(vec![ActionReport::new(
DateTime::<Utc>::from_timestamp(90, 0).unwrap(),
Duration::new(1, 0),
)]))
.returning(|_| ErrorOnTestSnafu.fail());
let repo = StorageBasedRepository::new(storage);

// act
let actual = repo.add(ActionReport::new(
DateTime::<Utc>::from_timestamp(90, 0).unwrap(),
Duration::new(1, 0),
));

// assert
assert!(matches!(actual, Err(RepositoryError::ErrorOnTest)));
}
}

0 comments on commit d968479

Please sign in to comment.