M12b: category contract v2 on the server (schema 2, fourteen defaults, finer import mapping)
- migrations/0002_categories_v2.sql, byte-identical to contracts/schema/migrations/0002_categories_v2.sql (SPEC §14.1.1), with an identity test; SCHEMA_VERSION = 2 (E-1 reports it, the importer's check follows). - Seed test on a fresh database (the fourteen rows of AC-7.2, server_version 11 to 14) and an upgrade test of a v1 database in use (0001 applied through the migrator, then users, a custom, a renamed and an archived default, an account, a recurring template, expenses): every earlier row unchanged, the four rows above the old sequence, foreign_key_check empty, schema_version 2, a pull from the old cursor returns exactly the four rows. - DefaultCategoryKey with the fourteen keys (wire enum and contracts/openapi.yaml); icons 33 and colours 14 (§9.7) in validation. - The two category examples M12a held back (E-26 response-default, sync/pull-page-categories-v2) and its contracts-check patch for them and the enum. - Importer: splitwise_categories.csv per the §10.8 v0.8 table (D-053), DEFAULT_KEYS of fourteen, synthetic fixtures for the finer mapping (Insurance/Försäkringar to insurance among them), a schema-1 refusal test. - Test harnesses seed users at server_version 15/16 (after the fourteen seeds); pull counts 10 -> 14. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
This commit is contained in:
@@ -62,13 +62,26 @@ pub struct TestApp {
|
||||
impl TestApp {
|
||||
/// A migrated, empty database (no users).
|
||||
pub async fn empty() -> Self {
|
||||
Self::migrated_to(None).await
|
||||
}
|
||||
|
||||
/// An empty database at schema version 1: only `0001_init.sql` applied, through the server's own migrator, so a
|
||||
/// later `db::migrate` upgrades it the way a deployed v1 database is upgraded.
|
||||
pub async fn at_v1() -> Self {
|
||||
Self::migrated_to(Some(1)).await
|
||||
}
|
||||
|
||||
async fn migrated_to(target: Option<i64>) -> Self {
|
||||
let dir = TempDir::new();
|
||||
let config = Config::from_lookup(|k| {
|
||||
(k == "KVITT_DATA_DIR").then(|| dir.0.to_string_lossy().into_owned())
|
||||
})
|
||||
.unwrap();
|
||||
let pool = db::connect(&config.database_path()).await.unwrap();
|
||||
db::migrate(&pool).await.unwrap();
|
||||
match target {
|
||||
Some(version) => db::MIGRATOR.run_to(version, &pool).await.unwrap(),
|
||||
None => db::migrate(&pool).await.unwrap(),
|
||||
}
|
||||
let clock = FixedClock::new(parse_ts(NOW).unwrap());
|
||||
let state = AppState::new(config, pool).with_clock(Arc::new(clock.clone()));
|
||||
Self {
|
||||
@@ -81,10 +94,17 @@ impl TestApp {
|
||||
/// Admin and member users, one device each, plus a revoked device of the member.
|
||||
pub async fn household() -> Self {
|
||||
let app = Self::empty().await;
|
||||
let pool = &app.state.db;
|
||||
app.seed_household().await;
|
||||
app
|
||||
}
|
||||
|
||||
/// Inserts the users and devices of [`TestApp::household`] (users at `server_version` 15 and 16, after the
|
||||
/// fourteen seeded categories; the sequence is not advanced).
|
||||
pub async fn seed_household(&self) {
|
||||
let pool = &self.state.db;
|
||||
for (id, role, name, version) in [
|
||||
(ADMIN_ID, "admin", "Jacob", 11),
|
||||
(MEMBER_ID, "member", "Partner", 12),
|
||||
(ADMIN_ID, "admin", "Jacob", 15),
|
||||
(MEMBER_ID, "member", "Partner", 16),
|
||||
] {
|
||||
sqlx::query(
|
||||
"INSERT INTO users (id, role, display_name, picture_version, created_at, updated_at, server_version) \
|
||||
@@ -122,7 +142,6 @@ impl TestApp {
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
app
|
||||
}
|
||||
|
||||
pub async fn send(&self, request: Request<Body>) -> Reply {
|
||||
|
||||
Reference in New Issue
Block a user