lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

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 }