use super::*;
fn t0() -> Instant {
Instant::now()
}
fn seeded() -> Board {
Board::new([
(Kind::Network, "proj_default".to_string()),
(Kind::Container, "proj-web-1".to_string()),
(Kind::Container, "proj-db-1".to_string()),
])
}
#[test]
fn a_seeded_board_knows_its_total_before_anything_happens() {
assert_eq!(seeded().tally(), (0, 3));
}
#[test]
fn only_finished_rows_count_towards_the_tally() {
let mut b = seeded();
let now = t0();
b.start(Kind::Container, "proj-web-1", "Creating", now);
assert_eq!(b.tally(), (0, 3));
b.finish(Kind::Container, "proj-web-1", "Created", now);
assert_eq!(b.tally(), (1, 3));
}
#[test]
fn a_finish_without_a_start_still_lands() {
let mut b = seeded();
b.finish(Kind::Network, "proj_default", "Created", t0());
assert_eq!(b.tally(), (1, 3));
}
#[test]
fn an_unseeded_resource_is_appended_not_dropped() {
let mut b = seeded();
b.finish(Kind::Volume, "proj_data", "Created", t0());
assert_eq!(b.tally(), (1, 4));
}
#[test]
fn a_row_is_identified_by_kind_and_name_together() {
let mut b = Board::new([
(Kind::Network, "same".to_string()),
(Kind::Container, "same".to_string()),
]);
b.finish(Kind::Network, "same", "Created", t0());
assert_eq!(b.tally(), (1, 2));
}
#[test]
fn completed_rows_flush_from_the_front_in_order() {
let mut b = seeded();
let now = t0();
b.finish(Kind::Network, "proj_default", "Created", now);
let flushed = b.take_completed_prefix();
assert_eq!(flushed.len(), 1);
assert_eq!(flushed[0].name, "proj_default");
assert_eq!(b.live_rows().len(), 2);
}
#[test]
fn a_finished_row_behind_an_unfinished_one_does_not_flush() {
let mut b = seeded();
let now = t0();
b.finish(Kind::Container, "proj-db-1", "Created", now);
assert!(b.take_completed_prefix().is_empty());
assert_eq!(b.live_rows().len(), 3);
b.finish(Kind::Network, "proj_default", "Created", now);
b.finish(Kind::Container, "proj-web-1", "Created", now);
let flushed = b.take_completed_prefix();
assert_eq!(flushed.len(), 3);
assert!(b.live_rows().is_empty());
}
#[test]
fn flushing_is_not_repeatable() {
let mut b = seeded();
b.finish(Kind::Network, "proj_default", "Created", t0());
assert_eq!(b.take_completed_prefix().len(), 1);
assert!(b.take_completed_prefix().is_empty());
}
#[test]
fn a_finished_row_freezes_its_elapsed_time() {
let mut b = seeded();
let start = t0();
b.start(Kind::Container, "proj-web-1", "Creating", start);
let end = start + Duration::from_millis(250);
b.finish(Kind::Container, "proj-web-1", "Created", end);
let row = b
.live_rows()
.iter()
.find(|r| r.name == "proj-web-1")
.unwrap()
.clone();
let much_later = start + Duration::from_secs(30);
assert_eq!(row.duration(much_later), Some(Duration::from_millis(250)));
}
#[test]
fn a_working_row_counts_from_its_own_start() {
let mut b = seeded();
let t = t0();
b.start(
Kind::Container,
"proj-web-1",
"Creating",
t + Duration::from_secs(2),
);
let row = b.live_rows()[1].clone();
assert_eq!(
row.duration(t + Duration::from_secs(5)),
Some(Duration::from_secs(3))
);
}
#[test]
fn a_pending_row_has_no_duration() {
let b = seeded();
assert_eq!(b.live_rows()[0].duration(t0()), None);
}
#[test]
fn restarting_a_working_row_keeps_the_original_start() {
let mut b = seeded();
let t = t0();
b.start(Kind::Container, "proj-web-1", "Creating", t);
b.start(
Kind::Container,
"proj-web-1",
"Starting",
t + Duration::from_secs(4),
);
let row = b.live_rows()[1].clone();
assert_eq!(
row.duration(t + Duration::from_secs(6)),
Some(Duration::from_secs(6))
);
}
#[test]
fn completion_is_every_row_finished() {
let mut b = seeded();
let now = t0();
assert!(!b.is_complete());
for (kind, name) in [
(Kind::Network, "proj_default"),
(Kind::Container, "proj-web-1"),
(Kind::Container, "proj-db-1"),
] {
b.finish(kind, name, "Created", now);
}
assert!(b.is_complete());
}
#[test]
fn every_kind_round_trips_through_its_noun() {
for kind in [
Kind::Network,
Kind::Volume,
Kind::Secret,
Kind::Image,
Kind::Container,
] {
assert_eq!(Kind::from_noun(kind.noun()), Some(kind));
}
assert_eq!(Kind::from_noun("Sandwich"), None);
}