migration_delivery_facts_tests.rs (5290B)
1 use super::{ 2 tests::{connection, establish_runtime_version, pragma}, 3 *, 4 }; 5 6 const FAILING_V16: &str = concat!( 7 include_str!("migration/runtime/0016_authored_delivery_facts.up.sql"), 8 "\nINSERT INTO missing_fixture_table VALUES (1);" 9 ); 10 11 fn plan(current: u32, fail: bool) -> MigrationPlan { 12 MigrationPlan { 13 database: RUNTIME_DATABASE, 14 application_id: RUNTIME_APPLICATION_ID, 15 set_application_id_sql: SET_RUNTIME_APPLICATION_ID, 16 minimum_version: runtime::MINIMUM_VERSION, 17 current_version: current, 18 steps: runtime::MIGRATIONS 19 .iter() 20 .take(current as usize) 21 .map(|step| MigrationStep { 22 version: step.version(), 23 sql: if fail && step.version() == 16 { 24 FAILING_V16 25 } else { 26 runtime::migration_sql(step.version()).unwrap() 27 }, 28 owned_objects: step.owned_objects(), 29 }) 30 .collect(), 31 } 32 } 33 34 #[tokio::test] 35 async fn delivery_fact_upgrade_preserves_legacy_snapshots_receipts_and_cancelled_stop() { 36 let mut connection = connection().await; 37 establish_runtime_version(&mut connection, 15).await; 38 let old = super::signed_facts_tests::seed(&mut connection).await; 39 let bytes: Vec<u8> = 40 sqlx::query_scalar("SELECT snapshot FROM radroots_runtime_authored_delivery_plans") 41 .fetch_one(&mut connection) 42 .await 43 .unwrap(); 44 let mut wire: serde_json::Value = serde_json::from_slice(&bytes).unwrap(); 45 wire["state"] = serde_json::json!("cancelled"); 46 wire.as_object_mut().unwrap().remove("delivery_facts"); 47 wire.as_object_mut() 48 .unwrap() 49 .remove("stop_requested_at_unix_ms"); 50 let historical = serde_json::to_vec(&wire).unwrap(); 51 sqlx::query( 52 "UPDATE radroots_runtime_authored_delivery_plans SET state = 'cancelled', snapshot = ?", 53 ) 54 .bind(&historical) 55 .execute(&mut connection) 56 .await 57 .unwrap(); 58 assert!(matches!( 59 migrate(&mut connection, OpenMode::ReadOnly, &plan(16, false)).await, 60 Err(Error::SchemaMigrationRequired { 61 actual: 15, 62 current: 16, 63 .. 64 }) 65 )); 66 assert_eq!( 67 migrate( 68 &mut connection, 69 OpenMode::ReadWriteExisting, 70 &plan(16, false) 71 ) 72 .await 73 .unwrap() 74 .applied(), 75 1 76 ); 77 assert_eq!(pragma(&mut connection, "user_version").await, 16); 78 super::signed_facts_tests::retained(&mut connection, &old).await; 79 let (actual, stop): (Vec<u8>, Option<i64>) = sqlx::query_as( 80 "SELECT snapshot, stop_requested_at_unix_ms FROM radroots_runtime_authored_delivery_plans", 81 ) 82 .fetch_one(&mut connection) 83 .await 84 .unwrap(); 85 assert_eq!(actual, historical); 86 assert_eq!(stop, Some(10)); 87 let decoded: radroots_storage::authored_delivery::AuthoredDeliveryPlan = 88 serde_json::from_slice(&actual).unwrap(); 89 assert_eq!(decoded.stop_requested_at_unix_ms(), Some(10)); 90 assert!(decoded.delivery_facts().is_empty()); 91 for mode in [OpenMode::ReadOnly, OpenMode::ReadWriteExisting] { 92 assert!(matches!( 93 migrate(&mut connection, mode, &plan(15, false)).await, 94 Err(Error::SchemaTooNew { 95 actual: 16, 96 supported: 15, 97 .. 98 }) 99 )); 100 } 101 connection.close().await.unwrap(); 102 } 103 104 #[tokio::test] 105 async fn failed_delivery_fact_migration_rolls_back_every_new_schema_object() { 106 let mut connection = connection().await; 107 establish_runtime_version(&mut connection, 15).await; 108 let old = super::signed_facts_tests::seed(&mut connection).await; 109 assert!( 110 migrate( 111 &mut connection, 112 OpenMode::ReadWriteExisting, 113 &plan(16, true) 114 ) 115 .await 116 .is_err() 117 ); 118 assert_eq!(pragma(&mut connection, "user_version").await, 15); 119 super::signed_facts_tests::retained(&mut connection, &old).await; 120 assert!( 121 sqlx::query( 122 "SELECT stop_requested_at_unix_ms FROM radroots_runtime_authored_delivery_plans" 123 ) 124 .fetch_all(&mut connection) 125 .await 126 .is_err() 127 ); 128 assert_eq!(sqlx::query_scalar::<_, i64>("SELECT COUNT(*) FROM sqlite_schema WHERE name LIKE 'radroots_runtime_authored_delivery_facts%' OR name = 'radroots_runtime_authored_delivery_stop_guard'").fetch_one(&mut connection).await.unwrap(), 0); 129 migrate_runtime(&mut connection, OpenMode::ReadWriteExisting) 130 .await 131 .unwrap(); 132 super::signed_facts_tests::retained(&mut connection, &old).await; 133 connection.close().await.unwrap(); 134 } 135 136 #[test] 137 fn delivery_fact_decision_binds_unchanged_historical_migrations_and_exact_successor() { 138 let decision: serde_json::Value = serde_json::from_str(include_str!( 139 "../../../contracts/architecture/decisions/authored_delivery_facts.v1.json" 140 )) 141 .unwrap(); 142 let migration = runtime::MIGRATIONS[15]; 143 assert_eq!(decision["migration"]["version"], migration.version()); 144 assert_eq!(decision["migration"]["name"], migration.name()); 145 assert_eq!(decision["migration"]["sha256"], migration.up_sha256()); 146 }