use std::time::Duration; use remora_schema::{SCHEMA_GENERATION, generation, is_ready, migrate}; use sqlx::{PgPool, postgres::PgPoolOptions}; async fn test_pool() -> Option { let Some(url) = std::env::var("DATABASE_URL") .ok() .filter(|value| !value.is_empty()) else { if std::env::var("REMORA_SCHEMA_REQUIRE").is_ok() { panic!("DATABASE_URL is required when REMORA_SCHEMA_REQUIRE is set"); } return None; }; Some( PgPoolOptions::new() .max_connections(12) .acquire_timeout(Duration::from_secs(10)) .connect(&url) .await .expect("connect postgres"), ) } #[tokio::test] async fn migration_is_idempotent_and_marks_the_complete_generation() { let Some(pool) = test_pool().await else { return; }; migrate(&pool).await.expect("first migration"); migrate(&pool).await.expect("second migration"); assert_eq!( generation(&pool).await.expect("schema generation"), Some(SCHEMA_GENERATION) ); assert!(is_ready(&pool).await.expect("schema readiness")); let missing_tables: Vec = sqlx::query_scalar( "SELECT table_name FROM unnest(ARRAY[ 'mutation_records', 'principal_identities', 'source_credentials', 'jobs', 'attempts', 'result_inventories', 'deletion_operations', 'live_event_history_state', 'worker_descriptors', 'remora_schema_state' ]) AS expected(table_name) WHERE to_regclass('public.' || table_name) IS NULL ORDER BY table_name", ) .fetch_all(&pool) .await .expect("schema tables"); assert!( missing_tables.is_empty(), "missing tables: {missing_tables:?}" ); } #[tokio::test] async fn concurrent_owners_converge_before_readiness() { let Some(pool) = test_pool().await else { return; }; let (first, second) = tokio::join!(migrate(&pool), migrate(&pool)); first.expect("first owner"); second.expect("second owner"); assert!(is_ready(&pool).await.expect("schema readiness")); }