Server overhaul: one test harness in tests/common for every test binary
core_api/common.rs becomes tests/common/mod.rs and sync_api/m4.rs tests/common/sync_fixtures.rs; each binary includes them through #[path] (the binaries of SPEC §14.7 stay as they are). TempDir's Default moves into the harness instead of three copies; the skeleton helpers take ids, tokens and TempDir from it. Milestone wording in test docs and the server README replaced by what the code does; README seams and test layout updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
This commit is contained in:
@@ -1,16 +1,10 @@
|
||||
//! M4 scheduler tests (SPEC §9.5 scheduler cases, §14.1 pruning, D-021): the daily run planned at local 06:00 and
|
||||
//! Scheduler tests (SPEC §9.5 scheduler cases, §14.1 pruning, D-021): the daily run planned at local 06:00 and
|
||||
//! 04:00 across both DST changes, the run at start, clock jumps with an injected clock, catch-up after downtime
|
||||
//! through M3's generation function, paused and deleted templates skipped, and the 90-day pruning.
|
||||
//! through the recurring generation, paused and deleted templates skipped, and the 90-day pruning.
|
||||
|
||||
#[path = "../core_api/common.rs"]
|
||||
#[path = "../common/mod.rs"]
|
||||
pub mod common;
|
||||
#[path = "../sync_api/m4.rs"]
|
||||
pub mod m4;
|
||||
#[path = "../common/sync_fixtures.rs"]
|
||||
pub mod sync_fixtures;
|
||||
|
||||
mod scheduler;
|
||||
|
||||
impl Default for common::TempDir {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use kvitt_server::time::{FixedClock, format_ts, parse_ts};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::common::*;
|
||||
use crate::m4;
|
||||
use crate::sync_fixtures;
|
||||
|
||||
fn ts(text: &str) -> chrono::DateTime<chrono::Utc> {
|
||||
parse_ts(text).unwrap()
|
||||
@@ -175,10 +175,10 @@ async fn periods(app: &TestApp, template: &str) -> Vec<String> {
|
||||
|
||||
#[tokio::test]
|
||||
async fn start_runs_generation_catching_up_after_downtime_and_skips_paused_and_deleted() {
|
||||
let mut app = m4::app().await;
|
||||
let active = m4::new_id();
|
||||
let paused = m4::new_id();
|
||||
let deleted = m4::new_id();
|
||||
let mut app = sync_fixtures::app().await;
|
||||
let active = sync_fixtures::new_id();
|
||||
let paused = sync_fixtures::new_id();
|
||||
let deleted = sync_fixtures::new_id();
|
||||
// Last generated July; the server was down since. Now is 17 October 14:00.
|
||||
insert_template(&app, &active, 15, "2026-06", Some("2026-07"), false, false).await;
|
||||
insert_template(&app, &paused, 1, "2026-06", None, true, false).await;
|
||||
@@ -204,8 +204,8 @@ async fn start_runs_generation_catching_up_after_downtime_and_skips_paused_and_d
|
||||
|
||||
#[tokio::test]
|
||||
async fn the_06_00_tick_generates_the_period_due_that_morning() {
|
||||
let app = m4::app().await;
|
||||
let id = m4::new_id();
|
||||
let app = sync_fixtures::app().await;
|
||||
let id = sync_fixtures::new_id();
|
||||
insert_template(&app, &id, 15, "2026-11", None, false, false).await;
|
||||
// 15 November 2026, 05:59 CET: not yet.
|
||||
app.set_now("2026-11-15T04:59:00.000Z");
|
||||
@@ -239,14 +239,14 @@ async fn the_06_00_tick_generates_the_period_due_that_morning() {
|
||||
}
|
||||
|
||||
async fn insert_mutation(app: &TestApp, received_at: &str) -> String {
|
||||
let id = m4::new_id();
|
||||
let id = sync_fixtures::new_id();
|
||||
sqlx::query(
|
||||
"INSERT INTO sync_mutations (mutation_id, device_id, entity_type, entity_id, result, received_at) \
|
||||
VALUES (?, ?, 'expense', ?, '{}', ?)",
|
||||
)
|
||||
.bind(&id)
|
||||
.bind(ADMIN_DEVICE_ID)
|
||||
.bind(m4::new_id())
|
||||
.bind(sync_fixtures::new_id())
|
||||
.bind(received_at)
|
||||
.execute(&app.state.db)
|
||||
.await
|
||||
@@ -256,7 +256,7 @@ async fn insert_mutation(app: &TestApp, received_at: &str) -> String {
|
||||
|
||||
#[tokio::test]
|
||||
async fn pruning_deletes_rows_older_than_90_days_and_keeps_the_rest() {
|
||||
let app = m4::app().await;
|
||||
let app = sync_fixtures::app().await;
|
||||
let now = ts(NOW);
|
||||
insert_mutation(
|
||||
&app,
|
||||
@@ -277,7 +277,7 @@ async fn pruning_deletes_rows_older_than_90_days_and_keeps_the_rest() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn pruning_runs_at_04_00_local() {
|
||||
let app = m4::app().await;
|
||||
let app = sync_fixtures::app().await;
|
||||
// 03:59 CEST on 18 October.
|
||||
app.set_now("2026-10-18T01:59:00.000Z");
|
||||
insert_mutation(&app, "2026-07-01T00:00:00.000Z").await;
|
||||
@@ -290,11 +290,13 @@ async fn pruning_runs_at_04_00_local() {
|
||||
.await;
|
||||
});
|
||||
tokio::time::sleep(Duration::from_millis(30)).await;
|
||||
assert_eq!(m4::count(&app, "sync_mutations").await, 1);
|
||||
assert_eq!(sync_fixtures::count(&app, "sync_mutations").await, 1);
|
||||
app.set_now("2026-10-18T02:00:00.000Z");
|
||||
let deadline = std::time::Instant::now() + Duration::from_secs(5);
|
||||
while m4::count(&app, "sync_mutations").await > 0 && std::time::Instant::now() < deadline {
|
||||
while sync_fixtures::count(&app, "sync_mutations").await > 0
|
||||
&& std::time::Instant::now() < deadline
|
||||
{
|
||||
tokio::time::sleep(Duration::from_millis(5)).await;
|
||||
}
|
||||
assert_eq!(m4::count(&app, "sync_mutations").await, 0);
|
||||
assert_eq!(sync_fixtures::count(&app, "sync_mutations").await, 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user