use reliar_core::{Classify, FailureKind};
use reliar_store_postgres::{
MIN_SERVER_VERSION_NUM, MigrateError, MigrateOptions, PostgresOutboxStore, PostgresStoreError,
migrate,
};
use sqlx::PgPool;
use testcontainers::ImageExt;
use testcontainers::runners::AsyncRunner;
use testcontainers_modules::postgres::Postgres;
async fn migrate_and_connect_refuse_a_server_below_the_floor() {
let pg17 = Postgres::default()
.with_tag("17-alpine") .with_container_name(format!("reliar-pg17-{}", uuid::Uuid::now_v7().simple()))
.with_label("reliar.test", "true")
.start()
.await
.expect("start postgres 17");
let port = pg17
.get_host_port_ipv4(5432)
.await
.expect("mapped port for postgres 17");
let url = format!("postgres://postgres:postgres@127.0.0.1:{port}/postgres");
let pool = PgPool::connect(&url)
.await
.expect("connect to the postgres 17 container");
let err = migrate(&pool, MigrateOptions::default())
.await
.expect_err("migrate() must refuse a server below MIN_SERVER_VERSION_NUM");
let text = err.to_string();
assert!(
!text.contains("postgres://") && !text.contains("127.0.0.1"),
"MigrateError::Display must carry no DSN/host, got: {text}"
);
let MigrateError::UnsupportedServerVersion { required, detected } = err else {
panic!("expected MigrateError::UnsupportedServerVersion, got {err:?}");
};
assert_eq!(required, MIN_SERVER_VERSION_NUM);
assert!(
(170_000..180_000).contains(&detected),
"expected a PostgreSQL 17.x server_version_num below the floor, got {detected}"
);
assert!(
text.contains("180000") && text.contains(&detected.to_string()),
"Display must name both the floor and the detected version, got: {text}"
);
let schema_exists: bool = sqlx::query_scalar(
"SELECT EXISTS (SELECT 1 FROM information_schema.schemata WHERE schema_name = 'reliar')",
)
.fetch_one(&pool)
.await
.expect("query information_schema.schemata");
assert!(
!schema_exists,
"a refused migrate() must leave the database exactly as it found it — no reliar schema"
);
let err = PostgresOutboxStore::new(pool.clone())
.await
.expect_err("construction must also refuse a server below the floor");
let text = err.to_string();
assert!(
!text.contains("postgres://") && !text.contains("127.0.0.1"),
"PostgresStoreError::Display must carry no DSN/host, got: {text}"
);
assert_eq!(
err.kind(),
FailureKind::Permanent,
"a server below the floor never becomes supported on retry"
);
match err {
PostgresStoreError::UnsupportedServerVersion { required, detected } => {
assert_eq!(required, MIN_SERVER_VERSION_NUM);
assert!(
(170_000..180_000).contains(&detected),
"expected a PostgreSQL 17.x server_version_num below the floor, got {detected}"
);
assert!(
text.contains("180000") && text.contains(&detected.to_string()),
"Display must name both the floor and the detected version, got: {text}"
);
}
other => panic!("expected PostgresStoreError::UnsupportedServerVersion, got {other:?}"),
}
}
pub(crate) fn trials(rt: &'static tokio::runtime::Runtime) -> Vec<libtest_mimic::Trial> {
vec![libtest_mimic::Trial::test(
"server_version_floor::migrate_and_connect_refuse_a_server_below_the_floor",
move || {
rt.block_on(migrate_and_connect_refuse_a_server_below_the_floor());
Ok(())
},
)]
}