migration_draft_query_tests.rs (4887B)
1 use super::tests::{connection, establish_runtime_version, pragma}; 2 use super::*; 3 4 const FAILING_V14: &str = concat!( 5 include_str!("migration/runtime/0014_authored_draft_query_metadata.up.sql"), 6 "\nINSERT INTO missing_fixture_table VALUES (1);" 7 ); 8 9 async fn seed(connection: &mut SqliteConnection) -> Vec<Vec<u8>> { 10 let snapshots = vec![ 11 br#"{"payload_schema":"fixture.composer.v1","payload":[49,46]}"#.to_vec(), 12 b"{broken historical row".to_vec(), 13 ]; 14 for (index, snapshot) in snapshots.iter().enumerate() { 15 sqlx::query("INSERT INTO radroots_runtime_authored_draft_revisions 16 (draft_id, revision, author, stage, payload_sha256, created_at_unix_ms, updated_at_unix_ms, snapshot) 17 VALUES (?, 1, ?, 0, ?, 10, 10, ?)") 18 .bind([index as u8 + 1; 16].as_slice()).bind([7; 32].as_slice()).bind([3; 32].as_slice()).bind(snapshot) 19 .execute(&mut *connection).await.unwrap(); 20 } 21 snapshots 22 } 23 fn plan(current: u32, fail: bool) -> MigrationPlan { 24 let steps = runtime::MIGRATIONS 25 .iter() 26 .take(current as usize) 27 .map(|step| MigrationStep { 28 version: step.version(), 29 sql: if fail && step.version() == 14 { 30 FAILING_V14 31 } else { 32 runtime::migration_sql(step.version()).unwrap() 33 }, 34 owned_objects: step.owned_objects(), 35 }) 36 .collect(); 37 MigrationPlan { 38 database: RUNTIME_DATABASE, 39 application_id: RUNTIME_APPLICATION_ID, 40 set_application_id_sql: SET_RUNTIME_APPLICATION_ID, 41 minimum_version: runtime::MINIMUM_VERSION, 42 current_version: current, 43 steps, 44 } 45 } 46 47 #[tokio::test] 48 async fn draft_metadata_upgrade_preserves_source_and_rejects_prior_schema_policy() { 49 let mut connection = connection().await; 50 establish_runtime_version(&mut connection, 13).await; 51 let snapshots = seed(&mut connection).await; 52 assert!(matches!( 53 migrate(&mut connection, OpenMode::ReadOnly, &plan(14, false)).await, 54 Err(Error::SchemaMigrationRequired { 55 current: 14, 56 actual: 13, 57 .. 58 }) 59 )); 60 let report = migrate( 61 &mut connection, 62 OpenMode::ReadWriteExisting, 63 &plan(14, false), 64 ) 65 .await 66 .unwrap(); 67 assert_eq!(report.applied(), 1); 68 assert_eq!(pragma(&mut connection, "user_version").await, 14); 69 let actual: Vec<Vec<u8>> = sqlx::query_scalar( 70 "SELECT snapshot FROM radroots_runtime_authored_draft_revisions ORDER BY draft_id", 71 ) 72 .fetch_all(&mut connection) 73 .await 74 .unwrap(); 75 assert_eq!(actual, snapshots); 76 let schemas: Vec<String> = sqlx::query_scalar( 77 "SELECT payload_schema FROM radroots_runtime_authored_draft_revisions ORDER BY draft_id", 78 ) 79 .fetch_all(&mut connection) 80 .await 81 .unwrap(); 82 assert_eq!(schemas, ["fixture.composer.v1", ""]); 83 assert!(matches!( 84 migrate(&mut connection, OpenMode::ReadOnly, &plan(13, false)).await, 85 Err(Error::SchemaTooNew { 86 supported: 13, 87 actual: 14, 88 .. 89 }) 90 )); 91 assert!( 92 sqlx::query( 93 "UPDATE radroots_runtime_authored_draft_revisions SET payload_schema = 'changed'" 94 ) 95 .execute(&mut connection) 96 .await 97 .is_err() 98 ); 99 assert_eq!( 100 migrate(&mut connection, OpenMode::ReadOnly, &plan(14, false)) 101 .await 102 .unwrap() 103 .applied(), 104 0 105 ); 106 connection.close().await.unwrap(); 107 } 108 109 #[tokio::test] 110 async fn metadata_migration_failure_rolls_back_columns_index_guards_and_version() { 111 let mut connection = connection().await; 112 establish_runtime_version(&mut connection, 13).await; 113 let snapshots = seed(&mut connection).await; 114 assert!( 115 migrate( 116 &mut connection, 117 OpenMode::ReadWriteExisting, 118 &plan(14, true) 119 ) 120 .await 121 .is_err() 122 ); 123 assert_eq!(pragma(&mut connection, "user_version").await, 13); 124 assert!( 125 sqlx::query("SELECT payload_schema FROM radroots_runtime_authored_draft_revisions") 126 .fetch_all(&mut connection) 127 .await 128 .is_err() 129 ); 130 let actual: Vec<Vec<u8>> = sqlx::query_scalar( 131 "SELECT snapshot FROM radroots_runtime_authored_draft_revisions ORDER BY draft_id", 132 ) 133 .fetch_all(&mut connection) 134 .await 135 .unwrap(); 136 assert_eq!(actual, snapshots); 137 assert!( 138 sqlx::query("UPDATE radroots_runtime_authored_draft_revisions SET stage = 1") 139 .execute(&mut connection) 140 .await 141 .is_err() 142 ); 143 migrate( 144 &mut connection, 145 OpenMode::ReadWriteExisting, 146 &plan(14, false), 147 ) 148 .await 149 .unwrap(); 150 connection.close().await.unwrap(); 151 }