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:
2026-10-18 22:31:04 +02:00
parent 6c405e142d
commit 8cb42f85a9
19 changed files with 118 additions and 146 deletions
@@ -1,5 +1,8 @@
//! Integration tests of the M2a server skeleton: migration identity and pragmas, routes, authentication and the
//! protocol rule, error shapes, and the wire types against `contracts/examples/`.
//! Base server tests: migration identity and pragmas, routes, authentication and the protocol rule, error shapes,
//! and the wire types against `contracts/examples/`.
#[path = "../common/mod.rs"]
pub mod common;
mod errors;
mod migration;
@@ -80,7 +80,7 @@ async fn every_route_is_registered_and_implemented() {
33,
"SPEC §7 has 33 operations"
);
// M3 implemented E-3 to E-30 and E-33 (tests/core_api), M4 the sync routes (tests/sync_api): nothing is 501.
// Every route has its handler (behaviour in tests/core_api and tests/sync_api): nothing is 501.
for (method, path, _) in routes {
let reply = app
.send(authed(method.clone(), &path, &admin_token()))
@@ -1,7 +1,7 @@
//! Shared helpers of the skeleton tests: a migrated temporary database, seeded users and devices, a fixed
//! clock and a one-shot request helper.
//! Helpers of the base tests: a database migrated to a chosen schema version, seeded users and devices (the
//! revoked device here is the member's), a fixed clock and a one-shot request helper. Ids, tokens and the
//! temporary directory come from the shared harness (`tests/common/`).
use std::path::PathBuf;
use std::sync::Arc;
use axum::body::Body;
@@ -12,45 +12,14 @@ use kvitt_server::time::{FixedClock, parse_ts};
use kvitt_server::{AppState, auth, db, router};
use serde_json::Value;
use tower::ServiceExt;
use uuid::Uuid;
pub const ADMIN_ID: &str = "0192a000-0000-7000-8000-000000000001";
pub const MEMBER_ID: &str = "0192a000-0000-7000-8000-000000000002";
pub const ADMIN_DEVICE_ID: &str = "0192a001-0000-7000-8000-000000000001";
pub const MEMBER_DEVICE_ID: &str = "0192a001-0000-7000-8000-000000000002";
pub const REVOKED_DEVICE_ID: &str = "0192a001-0000-7000-8000-000000000003";
pub const NOW: &str = "2026-10-17T12:00:00.000Z";
pub use crate::common::{
ADMIN_DEVICE_ID, ADMIN_ID, MEMBER_DEVICE_ID, MEMBER_ID, NOW, TempDir, admin_token,
member_token, old_device_token as revoked_token, token,
};
pub fn token(tag: char) -> String {
format!("kvt_{}", tag.to_string().repeat(43))
}
pub fn admin_token() -> String {
token('A')
}
pub fn member_token() -> String {
token('M')
}
pub fn revoked_token() -> String {
token('R')
}
/// A data directory removed on drop.
pub struct TempDir(pub PathBuf);
impl TempDir {
pub fn new() -> Self {
let dir = std::env::temp_dir().join(format!("kvitt-test-{}", Uuid::now_v7()));
std::fs::create_dir_all(&dir).unwrap();
Self(dir)
}
}
impl Drop for TempDir {
fn drop(&mut self) {
let _ = std::fs::remove_dir_all(&self.0);
}
}
/// The member's revoked device (the id of the shared harness's old admin device).
pub const REVOKED_DEVICE_ID: &str = crate::common::ADMIN_OLD_DEVICE_ID;
pub struct TestApp {
/// Kept alive so the directory is removed when the app is dropped.
@@ -103,7 +103,7 @@ fn every_example_round_trips() {
round_trip::<ErrorBody>(&name, &example);
checked += 1;
} else if dir_name == "push" {
// FCM payloads (SPEC §14.6) are built by M4's sender, not by a wire type of this crate.
// FCM payloads (SPEC §14.6) are built by the push sender, not by a wire type of this crate.
continue;
} else if check(&name, &example) {
checked += 1;