Files
kvitt/server/crates/kvitt-server/tests/skeleton/migration.rs
T
jacobh2 06f48ef9e9 M2a: server workspace, kvitt-domain, skeleton routes, OpenAPI match, Dockerfile
Cargo workspace (kvitt-domain, kvitt-server, kvitt-import), Rust 1.99.1 pinned.
kvitt-domain passes every Rust vector and adds next_occurrence_date (D-015).
kvitt-server: config, SQLite pool (WAL, §8.9 pragmas), migration 0001 identical to
the contract schema, error type for all 25 codes, auth extractor and protocol
layer, all 33 routes (E-1/E-2 implemented, the rest 501), utoipa document equal
to contracts/openapi.yaml, seams for M3/M4/M9, serve/migrate/healthcheck.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 21:30:20 +02:00

97 lines
3.1 KiB
Rust

//! `0001_init.sql` is the contract schema byte for byte (SPEC §14.1), and connections carry the §8.9 pragmas.
use std::path::PathBuf;
use kvitt_server::db;
use crate::support::TestApp;
fn manifest(path: &str) -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(path)
}
#[test]
fn migration_0001_is_byte_identical_to_contract_schema() {
let migration = std::fs::read(manifest("migrations/0001_init.sql")).unwrap();
let contract = std::fs::read(manifest("../../../contracts/schema/server-v1.sql")).unwrap();
assert!(
migration == contract,
"migrations/0001_init.sql differs from contracts/schema/server-v1.sql"
);
}
#[test]
fn the_embedded_migrator_holds_exactly_that_migration() {
let contract =
std::fs::read_to_string(manifest("../../../contracts/schema/server-v1.sql")).unwrap();
let migrations: Vec<_> = db::MIGRATOR.iter().collect();
assert_eq!(migrations.len(), 1);
assert_eq!(migrations[0].version, 1);
assert_eq!(migrations[0].sql.as_ref(), contract.as_str());
}
#[tokio::test]
async fn migrated_database_has_schema_version_seed_rows_and_pragmas() {
let app = TestApp::empty().await;
let pool = &app.state.db;
let version: String = sqlx::query_scalar("SELECT value FROM meta WHERE key = 'schema_version'")
.fetch_one(pool)
.await
.unwrap();
assert_eq!(version, db::SCHEMA_VERSION.to_string());
let epoch: String = sqlx::query_scalar("SELECT value FROM meta WHERE key = 'sync_epoch'")
.fetch_one(pool)
.await
.unwrap();
assert_eq!(epoch.len(), 32);
let categories: i64 = sqlx::query_scalar("SELECT COUNT(*) FROM categories")
.fetch_one(pool)
.await
.unwrap();
assert_eq!(categories, 10);
let mut conn = pool.acquire().await.unwrap();
let journal: String = sqlx::query_scalar("PRAGMA journal_mode")
.fetch_one(&mut *conn)
.await
.unwrap();
assert_eq!(journal, "wal");
let fk: i64 = sqlx::query_scalar("PRAGMA foreign_keys")
.fetch_one(&mut *conn)
.await
.unwrap();
assert_eq!(fk, 1);
let sync: i64 = sqlx::query_scalar("PRAGMA synchronous")
.fetch_one(&mut *conn)
.await
.unwrap();
assert_eq!(sync, 1, "synchronous = NORMAL");
let busy: i64 = sqlx::query_scalar("PRAGMA busy_timeout")
.fetch_one(&mut *conn)
.await
.unwrap();
assert_eq!(busy, 5000);
}
#[tokio::test]
async fn migrating_twice_is_a_no_op() {
let app = TestApp::empty().await;
db::migrate(&app.state.db).await.unwrap();
}
#[tokio::test]
async fn server_version_sequence_starts_after_the_seed_and_increments() {
let app = TestApp::empty().await;
let mut tx = db::begin_immediate(&app.state.db).await.unwrap();
assert_eq!(db::next_server_version(&mut tx).await.unwrap(), 11);
assert_eq!(db::next_server_version(&mut tx).await.unwrap(), 12);
tx.commit().await.unwrap();
let mut conn = app.state.db.acquire().await.unwrap();
assert_eq!(
db::sequence::current_server_version(&mut conn)
.await
.unwrap(),
12
);
}