refactor: improve replay test naming and add more docs

pull/24376/head
Marco Neumann 2021-07-26 17:31:13 +02:00
parent 43cb148566
commit aa61eb2732
1 changed files with 110 additions and 85 deletions

View File

@ -229,7 +229,7 @@ mod tests {
/// Different checks for replay tests /// Different checks for replay tests
#[derive(Debug)] #[derive(Debug)]
enum ReplayTestCheck { enum Check {
/// Check that the set of partitions is as expected. /// Check that the set of partitions is as expected.
/// ///
/// The partitions are by table name and partition key. /// The partitions are by table name and partition key.
@ -243,7 +243,7 @@ mod tests {
/// Action or check for replay test. /// Action or check for replay test.
#[derive(Debug)] #[derive(Debug)]
enum ReplayTestAOC { enum ActionOrCheck {
/// Ingest new entries into the write buffer. /// Ingest new entries into the write buffer.
Ingest(Vec<TestSequencedEntry>), Ingest(Vec<TestSequencedEntry>),
@ -259,12 +259,12 @@ mod tests {
Persist(Vec<(&'static str, &'static str)>), Persist(Vec<(&'static str, &'static str)>),
/// Assert that all these checks pass. /// Assert that all these checks pass.
Assert(Vec<ReplayTestCheck>), Assert(Vec<Check>),
/// Wait that background loop generates desired state (all checks pass). /// Wait that background loop generates desired state (all checks pass).
/// ///
/// Background loop is started before the check and stopped afterwards. /// Background loop is started before the check and stopped afterwards.
Await(Vec<ReplayTestCheck>), Await(Vec<Check>),
} }
#[derive(Debug)] #[derive(Debug)]
@ -272,8 +272,21 @@ mod tests {
/// Number of sequencers in this test setup. /// Number of sequencers in this test setup.
n_sequencers: u32, n_sequencers: u32,
/// What to do in which order /// What to do in which order.
actions_and_checks: Vec<ReplayTestAOC>, ///
/// # Serialization
/// The execution of the entire test is purely serial with the exception of [`Await`](ActionOrCheck::Await) (see
/// next section). That means that nothing happens concurrently during each step. Every step is finished and
/// checked for errors before the next is started (e.g. [`Replay`](ActionOrCheck::Replay) is fully executed and
/// it is ensured that there were no errors before a subsequent [`Assert`](ActionOrCheck::Assert) is evaluated).
/// The database background worker is NOT active during any non-[`Await`](ActionOrCheck::Await)
///
/// # Await
/// Sometimes the background worker is needed to perform something, e.g. to consume some data from the write
/// buffer. In that case [`Await`](ActionOrCheck::Await) can be used. During this check (and only during this
/// check) the background worker is active and the checks passed to [`Await`](ActionOrCheck::Await) are
/// evaluated until they succeed. The background worker is stopped before the next test step is evaluated.
steps: Vec<ActionOrCheck>,
} }
impl ReplayTest { impl ReplayTest {
@ -301,16 +314,16 @@ mod tests {
); );
// ==================== do: main loop ==================== // ==================== do: main loop ====================
for (step, action_or_check) in self.actions_and_checks.into_iter().enumerate() { for (step, action_or_check) in self.steps.into_iter().enumerate() {
println!("===== step {} =====\n{:?}", step + 1, action_or_check); println!("===== step {} =====\n{:?}", step + 1, action_or_check);
match action_or_check { match action_or_check {
ReplayTestAOC::Ingest(entries) => { ActionOrCheck::Ingest(entries) => {
for se in entries { for se in entries {
write_buffer_state.push_entry(se.build(&partition_template)); write_buffer_state.push_entry(se.build(&partition_template));
} }
} }
ReplayTestAOC::Restart => { ActionOrCheck::Restart => {
// first drop old DB // first drop old DB
#[allow(unused_assignments)] #[allow(unused_assignments)]
{ {
@ -329,7 +342,7 @@ mod tests {
.await, .await,
); );
} }
ReplayTestAOC::Replay => { ActionOrCheck::Replay => {
let test_db = test_db.as_ref().unwrap(); let test_db = test_db.as_ref().unwrap();
test_db test_db
@ -338,7 +351,7 @@ mod tests {
.await .await
.unwrap(); .unwrap();
} }
ReplayTestAOC::Persist(partitions) => { ActionOrCheck::Persist(partitions) => {
let test_db = test_db.as_ref().unwrap(); let test_db = test_db.as_ref().unwrap();
let db = &test_db.db; let db = &test_db.db;
@ -367,11 +380,11 @@ mod tests {
.unwrap(); .unwrap();
} }
} }
ReplayTestAOC::Assert(checks) => { ActionOrCheck::Assert(checks) => {
let test_db = test_db.as_ref().unwrap(); let test_db = test_db.as_ref().unwrap();
Self::eval_checks(&checks, true, test_db).await; Self::eval_checks(&checks, true, test_db).await;
} }
ReplayTestAOC::Await(checks) => { ActionOrCheck::Await(checks) => {
let test_db = test_db.as_ref().unwrap(); let test_db = test_db.as_ref().unwrap();
let db = &test_db.db; let db = &test_db.db;
@ -450,18 +463,18 @@ mod tests {
.await .await
} }
async fn eval_checks( /// Evaluates given checks.
checks: &[ReplayTestCheck], ///
use_assert: bool, /// If `use_assert = true` this function will panic in case of a failure. If `use_assert = false` it will just
test_db: &TestDb, /// return `false` in the error case. `true` is returned in all checks passed.
) -> bool { async fn eval_checks(checks: &[Check], use_assert: bool, test_db: &TestDb) -> bool {
let db = &test_db.db; let db = &test_db.db;
for (step, check) in checks.iter().enumerate() { for (step, check) in checks.iter().enumerate() {
println!("check {}: {:?}", step + 1, check); println!("check {}: {:?}", step + 1, check);
let res = match check { let res = match check {
ReplayTestCheck::Partitions(partitions) => { Check::Partitions(partitions) => {
let partitions_actual = Self::get_partitions(db); let partitions_actual = Self::get_partitions(db);
let partitions_actual: Vec<(&str, &str)> = partitions_actual let partitions_actual: Vec<(&str, &str)> = partitions_actual
.iter() .iter()
@ -475,7 +488,7 @@ mod tests {
use_assert, use_assert,
) )
} }
ReplayTestCheck::Query(query, expected) => { Check::Query(query, expected) => {
let batches = run_query(Arc::clone(&db), query).await; let batches = run_query(Arc::clone(&db), query).await;
// we are throwing away the record batches after the assert, so we don't care about interior // we are throwing away the record batches after the assert, so we don't care about interior
@ -499,11 +512,23 @@ mod tests {
true true
} }
fn eval_assert<F>(f: F, bubble: bool) -> bool /// Evaluates given function that may contain an `assert`.
///
/// This helper allows you use the same `assert` statement no matter if you want the error case to panic or if
/// you just want to have an boolean expression that states "did it succeed?".
///
/// Behavior dependson `raise`:
///
/// - `raise = true`: The given function `f` will be executed. If it panics, `eval_assert` will just bubble up
/// the error (aka panic as well). If the function `f` does not panic, `true` is returned (aka "it
/// succeeded").
/// - `raise = false`: The given function `f` will be executed but unwinds will be caught. If `f` did panic
/// `false` will be returned (aka "it failed"), otherwise `true` will be returned (aka "it succeeded").
fn eval_assert<F>(f: F, raise: bool) -> bool
where where
F: Fn() + std::panic::UnwindSafe, F: Fn() + std::panic::UnwindSafe,
{ {
if bubble { if raise {
f(); f();
true true
} else { } else {
@ -517,11 +542,11 @@ mod tests {
async fn replay_metatest_fail_assert_partitions() { async fn replay_metatest_fail_assert_partitions() {
ReplayTest { ReplayTest {
n_sequencers: 1, n_sequencers: 1,
actions_and_checks: vec![ steps: vec![
// that passes // that passes
ReplayTestAOC::Assert(vec![ReplayTestCheck::Partitions(vec![])]), ActionOrCheck::Assert(vec![Check::Partitions(vec![])]),
// that fails // that fails
ReplayTestAOC::Assert(vec![ReplayTestCheck::Partitions(vec![( ActionOrCheck::Assert(vec![Check::Partitions(vec![(
"table_2", "table_2",
"tag_partition_by_a", "tag_partition_by_a",
)])]), )])]),
@ -536,18 +561,18 @@ mod tests {
async fn replay_metatest_fail_assert_query() { async fn replay_metatest_fail_assert_query() {
ReplayTest { ReplayTest {
n_sequencers: 1, n_sequencers: 1,
actions_and_checks: vec![ steps: vec![
ReplayTestAOC::Ingest(vec![TestSequencedEntry { ActionOrCheck::Ingest(vec![TestSequencedEntry {
sequencer_id: 0, sequencer_id: 0,
sequence_number: 0, sequence_number: 0,
lp: "table_1,tag_partition_by=a bar=1 0", lp: "table_1,tag_partition_by=a bar=1 0",
}]), }]),
ReplayTestAOC::Await(vec![ReplayTestCheck::Partitions(vec![( ActionOrCheck::Await(vec![Check::Partitions(vec![(
"table_1", "table_1",
"tag_partition_by_a", "tag_partition_by_a",
)])]), )])]),
// that fails // that fails
ReplayTestAOC::Assert(vec![ReplayTestCheck::Query( ActionOrCheck::Assert(vec![Check::Query(
"select * from table_1", "select * from table_1",
vec![ vec![
"+-----+------------------+----------------------+", "+-----+------------------+----------------------+",
@ -567,8 +592,8 @@ mod tests {
async fn replay_ok_two_partitions_persist_second() { async fn replay_ok_two_partitions_persist_second() {
ReplayTest { ReplayTest {
n_sequencers: 1, n_sequencers: 1,
actions_and_checks: vec![ steps: vec![
ReplayTestAOC::Ingest(vec![ ActionOrCheck::Ingest(vec![
TestSequencedEntry { TestSequencedEntry {
sequencer_id: 0, sequencer_id: 0,
sequence_number: 0, sequence_number: 0,
@ -580,17 +605,17 @@ mod tests {
lp: "table_2,tag_partition_by=a bar=20 0", lp: "table_2,tag_partition_by=a bar=20 0",
}, },
]), ]),
ReplayTestAOC::Await(vec![ReplayTestCheck::Partitions(vec![ ActionOrCheck::Await(vec![Check::Partitions(vec![
("table_1", "tag_partition_by_a"), ("table_1", "tag_partition_by_a"),
("table_2", "tag_partition_by_a"), ("table_2", "tag_partition_by_a"),
])]), ])]),
ReplayTestAOC::Persist(vec![("table_2", "tag_partition_by_a")]), ActionOrCheck::Persist(vec![("table_2", "tag_partition_by_a")]),
ReplayTestAOC::Restart, ActionOrCheck::Restart,
ReplayTestAOC::Assert(vec![ReplayTestCheck::Partitions(vec![( ActionOrCheck::Assert(vec![Check::Partitions(vec![(
"table_2", "table_2",
"tag_partition_by_a", "tag_partition_by_a",
)])]), )])]),
ReplayTestAOC::Ingest(vec![ ActionOrCheck::Ingest(vec![
TestSequencedEntry { TestSequencedEntry {
sequencer_id: 0, sequencer_id: 0,
sequence_number: 2, sequence_number: 2,
@ -602,13 +627,13 @@ mod tests {
lp: "table_2,tag_partition_by=b bar=21 10", lp: "table_2,tag_partition_by=b bar=21 10",
}, },
]), ]),
ReplayTestAOC::Replay, ActionOrCheck::Replay,
ReplayTestAOC::Assert(vec![ ActionOrCheck::Assert(vec![
ReplayTestCheck::Partitions(vec![ Check::Partitions(vec![
("table_1", "tag_partition_by_a"), ("table_1", "tag_partition_by_a"),
("table_2", "tag_partition_by_a"), ("table_2", "tag_partition_by_a"),
]), ]),
ReplayTestCheck::Query( Check::Query(
"select * from table_1 order by time", "select * from table_1 order by time",
vec![ vec![
"+-----+------------------+----------------------+", "+-----+------------------+----------------------+",
@ -618,7 +643,7 @@ mod tests {
"+-----+------------------+----------------------+", "+-----+------------------+----------------------+",
], ],
), ),
ReplayTestCheck::Query( Check::Query(
"select * from table_2 order by time", "select * from table_2 order by time",
vec![ vec![
"+-----+------------------+----------------------+", "+-----+------------------+----------------------+",
@ -629,14 +654,14 @@ mod tests {
], ],
), ),
]), ]),
ReplayTestAOC::Await(vec![ReplayTestCheck::Partitions(vec![ ActionOrCheck::Await(vec![Check::Partitions(vec![
("table_1", "tag_partition_by_a"), ("table_1", "tag_partition_by_a"),
("table_1", "tag_partition_by_b"), ("table_1", "tag_partition_by_b"),
("table_2", "tag_partition_by_a"), ("table_2", "tag_partition_by_a"),
("table_2", "tag_partition_by_b"), ("table_2", "tag_partition_by_b"),
])]), ])]),
ReplayTestAOC::Assert(vec![ ActionOrCheck::Assert(vec![
ReplayTestCheck::Query( Check::Query(
"select * from table_1 order by time", "select * from table_1 order by time",
vec![ vec![
"+-----+------------------+--------------------------------+", "+-----+------------------+--------------------------------+",
@ -647,7 +672,7 @@ mod tests {
"+-----+------------------+--------------------------------+", "+-----+------------------+--------------------------------+",
], ],
), ),
ReplayTestCheck::Query( Check::Query(
"select * from table_2 order by time", "select * from table_2 order by time",
vec![ vec![
"+-----+------------------+--------------------------------+", "+-----+------------------+--------------------------------+",
@ -669,8 +694,8 @@ mod tests {
async fn replay_ok_two_partitions_persist_first() { async fn replay_ok_two_partitions_persist_first() {
ReplayTest { ReplayTest {
n_sequencers: 1, n_sequencers: 1,
actions_and_checks: vec![ steps: vec![
ReplayTestAOC::Ingest(vec![ ActionOrCheck::Ingest(vec![
TestSequencedEntry { TestSequencedEntry {
sequencer_id: 0, sequencer_id: 0,
sequence_number: 0, sequence_number: 0,
@ -682,17 +707,17 @@ mod tests {
lp: "table_2,tag_partition_by=a bar=20 0", lp: "table_2,tag_partition_by=a bar=20 0",
}, },
]), ]),
ReplayTestAOC::Await(vec![ReplayTestCheck::Partitions(vec![ ActionOrCheck::Await(vec![Check::Partitions(vec![
("table_1", "tag_partition_by_a"), ("table_1", "tag_partition_by_a"),
("table_2", "tag_partition_by_a"), ("table_2", "tag_partition_by_a"),
])]), ])]),
ReplayTestAOC::Persist(vec![("table_1", "tag_partition_by_a")]), ActionOrCheck::Persist(vec![("table_1", "tag_partition_by_a")]),
ReplayTestAOC::Restart, ActionOrCheck::Restart,
ReplayTestAOC::Assert(vec![ReplayTestCheck::Partitions(vec![( ActionOrCheck::Assert(vec![Check::Partitions(vec![(
"table_1", "table_1",
"tag_partition_by_a", "tag_partition_by_a",
)])]), )])]),
ReplayTestAOC::Ingest(vec![ ActionOrCheck::Ingest(vec![
TestSequencedEntry { TestSequencedEntry {
sequencer_id: 0, sequencer_id: 0,
sequence_number: 2, sequence_number: 2,
@ -704,13 +729,13 @@ mod tests {
lp: "table_2,tag_partition_by=b bar=21 10", lp: "table_2,tag_partition_by=b bar=21 10",
}, },
]), ]),
ReplayTestAOC::Replay, ActionOrCheck::Replay,
ReplayTestAOC::Assert(vec![ ActionOrCheck::Assert(vec![
ReplayTestCheck::Partitions(vec![ Check::Partitions(vec![
("table_1", "tag_partition_by_a"), ("table_1", "tag_partition_by_a"),
("table_2", "tag_partition_by_a"), ("table_2", "tag_partition_by_a"),
]), ]),
ReplayTestCheck::Query( Check::Query(
"select * from table_1 order by time", "select * from table_1 order by time",
vec![ vec![
"+-----+------------------+----------------------+", "+-----+------------------+----------------------+",
@ -720,7 +745,7 @@ mod tests {
"+-----+------------------+----------------------+", "+-----+------------------+----------------------+",
], ],
), ),
ReplayTestCheck::Query( Check::Query(
"select * from table_2 order by time", "select * from table_2 order by time",
vec![ vec![
"+-----+------------------+----------------------+", "+-----+------------------+----------------------+",
@ -731,14 +756,14 @@ mod tests {
], ],
), ),
]), ]),
ReplayTestAOC::Await(vec![ReplayTestCheck::Partitions(vec![ ActionOrCheck::Await(vec![Check::Partitions(vec![
("table_1", "tag_partition_by_a"), ("table_1", "tag_partition_by_a"),
("table_1", "tag_partition_by_b"), ("table_1", "tag_partition_by_b"),
("table_2", "tag_partition_by_a"), ("table_2", "tag_partition_by_a"),
("table_2", "tag_partition_by_b"), ("table_2", "tag_partition_by_b"),
])]), ])]),
ReplayTestAOC::Assert(vec![ ActionOrCheck::Assert(vec![
ReplayTestCheck::Query( Check::Query(
"select * from table_1 order by time", "select * from table_1 order by time",
vec![ vec![
"+-----+------------------+--------------------------------+", "+-----+------------------+--------------------------------+",
@ -749,7 +774,7 @@ mod tests {
"+-----+------------------+--------------------------------+", "+-----+------------------+--------------------------------+",
], ],
), ),
ReplayTestCheck::Query( Check::Query(
"select * from table_2 order by time", "select * from table_2 order by time",
vec![ vec![
"+-----+------------------+--------------------------------+", "+-----+------------------+--------------------------------+",
@ -771,21 +796,21 @@ mod tests {
async fn replay_ok_nothing_to_replay() { async fn replay_ok_nothing_to_replay() {
ReplayTest { ReplayTest {
n_sequencers: 1, n_sequencers: 1,
actions_and_checks: vec![ steps: vec![
ReplayTestAOC::Restart, ActionOrCheck::Restart,
ReplayTestAOC::Assert(vec![ReplayTestCheck::Partitions(vec![])]), ActionOrCheck::Assert(vec![Check::Partitions(vec![])]),
ReplayTestAOC::Ingest(vec![TestSequencedEntry { ActionOrCheck::Ingest(vec![TestSequencedEntry {
sequencer_id: 0, sequencer_id: 0,
sequence_number: 2, sequence_number: 2,
lp: "table_1,tag_partition_by=a bar=1 0", lp: "table_1,tag_partition_by=a bar=1 0",
}]), }]),
ReplayTestAOC::Replay, ActionOrCheck::Replay,
ReplayTestAOC::Assert(vec![ReplayTestCheck::Partitions(vec![])]), ActionOrCheck::Assert(vec![Check::Partitions(vec![])]),
ReplayTestAOC::Await(vec![ReplayTestCheck::Partitions(vec![( ActionOrCheck::Await(vec![Check::Partitions(vec![(
"table_1", "table_1",
"tag_partition_by_a", "tag_partition_by_a",
)])]), )])]),
ReplayTestAOC::Assert(vec![ReplayTestCheck::Query( ActionOrCheck::Assert(vec![Check::Query(
"select * from table_1 order by time", "select * from table_1 order by time",
vec![ vec![
"+-----+------------------+----------------------+", "+-----+------------------+----------------------+",
@ -814,8 +839,8 @@ mod tests {
// table 2: partition a: from sequencer 1, not persisted but recovered during replay // table 2: partition a: from sequencer 1, not persisted but recovered during replay
ReplayTest { ReplayTest {
n_sequencers: 3, n_sequencers: 3,
actions_and_checks: vec![ steps: vec![
ReplayTestAOC::Ingest(vec![ ActionOrCheck::Ingest(vec![
TestSequencedEntry { TestSequencedEntry {
sequencer_id: 1, sequencer_id: 1,
sequence_number: 0, sequence_number: 0,
@ -832,28 +857,28 @@ mod tests {
lp: "table_2,tag_partition_by=a bar=20 0", lp: "table_2,tag_partition_by=a bar=20 0",
}, },
]), ]),
ReplayTestAOC::Await(vec![ReplayTestCheck::Partitions(vec![ ActionOrCheck::Await(vec![Check::Partitions(vec![
("table_1", "tag_partition_by_a"), ("table_1", "tag_partition_by_a"),
("table_2", "tag_partition_by_a"), ("table_2", "tag_partition_by_a"),
])]), ])]),
ReplayTestAOC::Persist(vec![("table_1", "tag_partition_by_a")]), ActionOrCheck::Persist(vec![("table_1", "tag_partition_by_a")]),
ReplayTestAOC::Restart, ActionOrCheck::Restart,
ReplayTestAOC::Assert(vec![ReplayTestCheck::Partitions(vec![( ActionOrCheck::Assert(vec![Check::Partitions(vec![(
"table_1", "table_1",
"tag_partition_by_a", "tag_partition_by_a",
)])]), )])]),
ReplayTestAOC::Ingest(vec![TestSequencedEntry { ActionOrCheck::Ingest(vec![TestSequencedEntry {
sequencer_id: 0, sequencer_id: 0,
sequence_number: 1, sequence_number: 1,
lp: "table_1,tag_partition_by=b bar=12 20", lp: "table_1,tag_partition_by=b bar=12 20",
}]), }]),
ReplayTestAOC::Replay, ActionOrCheck::Replay,
ReplayTestAOC::Assert(vec![ ActionOrCheck::Assert(vec![
ReplayTestCheck::Partitions(vec![ Check::Partitions(vec![
("table_1", "tag_partition_by_a"), ("table_1", "tag_partition_by_a"),
("table_2", "tag_partition_by_a"), ("table_2", "tag_partition_by_a"),
]), ]),
ReplayTestCheck::Query( Check::Query(
"select * from table_1 order by time", "select * from table_1 order by time",
vec![ vec![
"+-----+------------------+--------------------------------+", "+-----+------------------+--------------------------------+",
@ -864,7 +889,7 @@ mod tests {
"+-----+------------------+--------------------------------+", "+-----+------------------+--------------------------------+",
], ],
), ),
ReplayTestCheck::Query( Check::Query(
"select * from table_2 order by time", "select * from table_2 order by time",
vec![ vec![
"+-----+------------------+----------------------+", "+-----+------------------+----------------------+",
@ -875,13 +900,13 @@ mod tests {
], ],
), ),
]), ]),
ReplayTestAOC::Await(vec![ReplayTestCheck::Partitions(vec![ ActionOrCheck::Await(vec![Check::Partitions(vec![
("table_1", "tag_partition_by_a"), ("table_1", "tag_partition_by_a"),
("table_1", "tag_partition_by_b"), ("table_1", "tag_partition_by_b"),
("table_2", "tag_partition_by_a"), ("table_2", "tag_partition_by_a"),
])]), ])]),
ReplayTestAOC::Assert(vec![ ActionOrCheck::Assert(vec![
ReplayTestCheck::Query( Check::Query(
"select * from table_1 order by time", "select * from table_1 order by time",
vec![ vec![
"+-----+------------------+--------------------------------+", "+-----+------------------+--------------------------------+",
@ -893,7 +918,7 @@ mod tests {
"+-----+------------------+--------------------------------+", "+-----+------------------+--------------------------------+",
], ],
), ),
ReplayTestCheck::Query( Check::Query(
"select * from table_2 order by time", "select * from table_2 order by time",
vec![ vec![
"+-----+------------------+----------------------+", "+-----+------------------+----------------------+",