From f8fe49f7394da266f0af84f583054e0e731f9e1d Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Sun, 25 Oct 2026 20:44:10 +0100 Subject: [PATCH] test: pin migration ledger --- Cargo.lock | 2 + Cargo.toml | 1 + crates/adapters/sqlite/Cargo.toml | 4 ++ .../tests/fixtures/migration_ledger.txt | 31 ++++++++++ .../sqlite/tests/migration_ledger_test.rs | 61 +++++++++++++++++++ 5 files changed, 99 insertions(+) create mode 100644 crates/adapters/sqlite/tests/fixtures/migration_ledger.txt create mode 100644 crates/adapters/sqlite/tests/migration_ledger_test.rs diff --git a/Cargo.lock b/Cargo.lock index 2aeadf3a..f719e86f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5205,8 +5205,10 @@ dependencies = [ "futures", "serde", "serde_json", + "sqlite-event-queue", "sqlite-social", "sqlx", + "tempfile", "tokio", "tracing", "uuid", diff --git a/Cargo.toml b/Cargo.toml index a718d83e..ca6a2d76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,7 @@ sqlx = { version = "0.8.6", features = [ "uuid", ] } rand = "0.9" +tempfile = "3" reqwest = { version = "0.13", features = ["json", "query"] } sha2 = "0.10" hex = "0.4" diff --git a/crates/adapters/sqlite/Cargo.toml b/crates/adapters/sqlite/Cargo.toml index b53c5054..d46f49c5 100644 --- a/crates/adapters/sqlite/Cargo.toml +++ b/crates/adapters/sqlite/Cargo.toml @@ -20,3 +20,7 @@ tokio = { workspace = true } futures = { workspace = true } bytes = { workspace = true } async-stream = { workspace = true } + +[dev-dependencies] +sqlite-event-queue = { workspace = true } +tempfile = { workspace = true } diff --git a/crates/adapters/sqlite/tests/fixtures/migration_ledger.txt b/crates/adapters/sqlite/tests/fixtures/migration_ledger.txt new file mode 100644 index 00000000..98d343ed --- /dev/null +++ b/crates/adapters/sqlite/tests/fixtures/migration_ledger.txt @@ -0,0 +1,31 @@ +1 8E739CFF6E02FED257C86B7FE409EB07C10BA99475A638B4E19840D82D6841C73420C6C4E1328B5EC29DF785EAC3062F +2 BB37ADE7421737C25370B6332E3A1433CC26752A6362FFB3FC96366FC4BD93EF065E8C0167742F869B0CDBCD58F108FD +3 760C99DCD559ECBD4AD0FC0A9DAEDACA621FD46627C94F2A4F0D5EF9586AB00CBFE17DAFC062CFCDAB8475580E15B461 +4 B91289D7629799BCF618B6034702468E914A29B25410D5C2A76FEBAE306CDFBAE0E257BA646EECB1F2E79B419758C996 +5 15E7EF4EF0209C042DAB96C05C59B07E7B31013F7E66944C4B7668272381E79317E141BBD81AA5FBEBB976EAE967A0AC +6 39E160883C51D281E8DD1BA9EAA6AB10DA96E9F6F8C8FEC29C92A8AEBC51BD83132E3DB2D05603097D2C742EB8C5E41A +7 6B1AC746A418CE21C53F6DA4D6B6785B672F0022F5330D2A120C33932151B20F8F3BD8BB1B2A9F21F801D7091C926A3B +8 F14ED60C9D5921B92A7FBAC1576DF1F548FAB34A28326777C689ED32B6125FAC7E6192771DC67D3F036D299A7F6236E6 +9 69E5AD1B6A5D24AF708C9BEA9F4B3695C60E14041DA2BB06EA445F40A24214B30C5771092FEA7BAC0D3335DA3CA797D0 +10 7BA25975CB09BECAE0DE1F2645F089DE2204645C97A014A7C8C9BB915E6EBB40DF695AE076E2CBB1ECEFB26414A769B9 +11 169AD32E5630D2D58E9EABFF22D70EFF97440D486BCEEC5993043E15A1D1C14D69DB1DC65F90CE069D2FBDF7485ABFAA +12 2356ED23B885EC86F96B2E5C1E2B9E7A580B742BC04F6355E2EBB19FEC58988557C8674A1BAB2E13BA2CFE4A9791AB27 +13 595176135F7B5BF6F2304C985AD51FA4D102CCBA58CAA85A436A1C921869E43DEA9054F90ED3D0DC4CFCD640D52BB465 +14 2871A6B456820EB45CAB85FEDBF9FF9E264D7F7E569CA6A114BE6D1FBFD3A42590650B9823AA00A7ABAE944B4FD8EBF6 +15 CC66FD300934364A20866ADFACDCF4DEC65D7011F159A2C16FD6303F3DDBAB331684189EC4CC4FFC62CE6E85D4A42721 +16 347B77FBF9DDFFB17950AF66C0B9DC485A38D4F9E6BFECAFB0F933036DDF0599381848C7635ADD29F4DCF3055C4ACFBE +17 BF5C1E3591A407CA8368AEE41D6CF7D842FE83310653B43747C12F2639D35C6F1E612FDD6739043A8FE226F0132D1B0D +18 7358CDB2DCBE1BDF1EF629C8A68990971B0A6B5D0FE0AC6672791478B0130C817B184F234572C325DE2565CD9C9C03BD +19 BAF7FA0F56E7757AC2F8D52B563902CB77126803304C3BAE35468F9B48B7F735DB2C8D4351ECDDC856916EBE393E1BD6 +20 875E8181058BBB455C6D2D7E3FEA459DC24D500F5C16746EED46D696BBE3D2D07008FB03A29FA3827BF490496902B3CF +21 745DA33DBB2DD0D2E9121756D2D00D23DAE5307396063E300E52203C40A21FB51DEAD0047C901B8A6248098E685E45F3 +22 947E5F3428691FF26E475825CBFE22976FBBA719C0F4547B7D525DCD042B108464A8A75F1F90392189520E94D7031DDA +23 947A36BFAD46B3068AB91FCC8A04A24D7ABCBCF78340DD3CB4B24134DB7C62550D2C9AD017A95C1FC12D362D93EA70AF +24 B5156F76DE0B4903521B19A3DE798EEB1F93193C21CCA69AC79B6945C78C9400AD1E2A4C94D16481C444D7D2579DF8D9 +25 113BFB1C5D3194CCDE7B6C1EDE6A16D956DECFAC6BB3D5AA96D70F7E460A9AF579025373787FAB8482C9F0BDCD3D5AB8 +26 60A5B8D024712B1F2FA0F31DBB4D4079A1BFE562F77E544F5877D5251B829B30FBDBC4B1F8D36B84CEA488B07F94DF3A +27 1E5069F7240DDA6D2BB8160E6997FF8FD6F6993D0D907AB30CC7DE5B774072B4FC46572CB83C038CA3A2BAA124048C84 +28 1D3FE5DA59EBCBC098CB13E40364872906F4E0CCFF355AF3E2BCD3E0A21D88F0522CD8E4674AA075385965DBF719ACD8 +29 56F4F7B41A09F07211D7543204F0EAC93B7BFB15AFD9BC90DF2654DAE5BE96B1E358B50E2190BF25739C5F0B1FD4B806 +30 DAAA0AF35B4ACB271A9D8068B82F02A72EEC62F3AC07ED504C7A7887976C2C8BACB35FFF477B63A931DF15F79018390D +100 310ADC9ABF0CC2F8E9EDAB33168D009D64228FF5BD8D2A14185513699EBB782606A1EEA8FEE6EC6AF65D72396153F13F diff --git a/crates/adapters/sqlite/tests/migration_ledger_test.rs b/crates/adapters/sqlite/tests/migration_ledger_test.rs new file mode 100644 index 00000000..6c5fbe4b --- /dev/null +++ b/crates/adapters/sqlite/tests/migration_ledger_test.rs @@ -0,0 +1,61 @@ +use std::path::Path; + +use sqlx::{ + SqlitePool, + sqlite::{SqliteConnectOptions, SqlitePoolOptions}, +}; + +const LEDGER: &str = include_str!("fixtures/migration_ledger.txt"); +const PRE_MERGE_DB: &str = "tests/fixtures/pre_merge.db"; + +async fn migrate_with_todays_entry_points(pool: &SqlitePool) { + sqlite::migrate(pool).await.unwrap(); + sqlite_event_queue::SqliteEventQueue::create_publisher(pool.clone()) + .await + .unwrap(); +} + +async fn ledger(pool: &SqlitePool) -> String { + let rows: Vec<(i64, String)> = + sqlx::query_as("SELECT version, hex(checksum) FROM _sqlx_migrations ORDER BY version") + .fetch_all(pool) + .await + .unwrap(); + rows.iter().map(|(v, c)| format!("{v} {c}\n")).collect() +} + +async fn file_pool(path: &Path, create: bool) -> SqlitePool { + let opts = SqliteConnectOptions::new() + .filename(path) + .create_if_missing(create); + SqlitePoolOptions::new() + .max_connections(1) + .connect_with(opts) + .await + .unwrap() +} + +#[tokio::test] +async fn migrating_a_fresh_database_produces_the_recorded_ledger() { + let pool = SqlitePool::connect("sqlite::memory:").await.unwrap(); + + migrate_with_todays_entry_points(&pool).await; + + assert_eq!(ledger(&pool).await, LEDGER); +} + +#[tokio::test] +async fn a_database_migrated_by_the_old_layout_migrates_again_cleanly() { + let dir = tempfile::tempdir().unwrap(); + let path = dir.path().join("pre_merge.db"); + std::fs::copy( + Path::new(env!("CARGO_MANIFEST_DIR")).join(PRE_MERGE_DB), + &path, + ) + .unwrap(); + let pool = file_pool(&path, false).await; + + sqlite::migrate(&pool).await.unwrap(); + + assert_eq!(ledger(&pool).await, LEDGER); +}