Skip to content

Commit 2ec34d3

Browse files
committed
fix(tests): embed Tier A fixture corpus at compile time so CI shards find it
The fixture-oracle property tests loaded their corpus at runtime via std::fs::read_to_string keyed off CARGO_MANIFEST_DIR/fixtures/eql_v2_<T>.sql. In CI's archive->shard split the test shards do a fresh checkout where those gitignored fixtures are absent, so int2/text (and every Tier A oracle test) failed with "No such file or directory". Only 3 surfaced because nextest fail-fast cancelled the shard after 93/518. Embed the fixture SQL into the test binary via include_str! at compile time, exactly like sqlx::test's scripts(...) does, so the corpus travels inside the prebuilt nextest archive. The embed lives in the fixture_oracle test target (not the eql_tests lib) so generate_all_fixtures still compiles before the fixtures exist. ensure_fixture_loaded now takes the script as a parameter. No CI or catalog changes.
1 parent 7b38962 commit 2ec34d3

2 files changed

Lines changed: 48 additions & 21 deletions

File tree

tests/sqlx/src/property.rs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,33 +23,36 @@ static FIXTURE_LOADED: OnceLock<Mutex<HashSet<&'static str>>> = OnceLock::new();
2323

2424
/// Materialise the live-encrypted fixture corpus for `T` into the connected DB.
2525
///
26-
/// The fixture `.sql` files (`tests/sqlx/fixtures/eql_v2_<T>.sql`, regenerated
27-
/// each `test:sqlx:prep`) are normally loaded only into `#[sqlx::test]`'s
28-
/// ephemeral per-test databases. The property tiers connect to the shared test
29-
/// DB directly (they cannot use `#[sqlx::test]`'s injected pool from a sync
30-
/// `proptest!` body), so the corpus is not present there. This loads it on
31-
/// demand: the script is self-contained and idempotent
32-
/// (`CREATE SCHEMA IF NOT EXISTS` / `DROP TABLE IF EXISTS` / `CREATE` /
33-
/// `INSERT`), and a process-wide async mutex guarantees exactly-once execution
34-
/// per type across the parallel test threads (each driving its own runtime).
35-
/// `CARGO_MANIFEST_DIR` resolves the path independent of the test's CWD.
36-
pub async fn ensure_fixture_loaded<T: ScalarType>(pool: &PgPool) -> Result<()> {
26+
/// The fixture `.sql` files (`tests/sqlx/fixtures/eql_v2_<T>.sql`) are normally
27+
/// loaded only into `#[sqlx::test]`'s ephemeral per-test databases. The property
28+
/// tiers connect to the shared test DB directly (they cannot use
29+
/// `#[sqlx::test]`'s injected pool from a sync `proptest!` body), so the corpus
30+
/// is not present there. This loads it on demand: the script is self-contained
31+
/// and idempotent (`CREATE SCHEMA IF NOT EXISTS` / `DROP TABLE IF EXISTS` /
32+
/// `CREATE` / `INSERT`), and a process-wide async mutex guarantees exactly-once
33+
/// execution per type across the parallel test threads (each driving its own
34+
/// runtime).
35+
///
36+
/// `script` is the fixture SQL, passed in by the caller. It is `include_str!`-
37+
/// embedded into the test binary at compile time (see `fixture_oracle.rs`) so it
38+
/// travels inside the prebuilt nextest archive that CI shards run from — those
39+
/// shards do a fresh checkout where the gitignored `.sql` files are absent, so a
40+
/// runtime `std::fs` read would fail there.
41+
pub async fn ensure_fixture_loaded<T: ScalarType>(pool: &PgPool, script: &str) -> Result<()> {
3742
let guard = FIXTURE_LOADED.get_or_init(|| Mutex::new(HashSet::new()));
3843
let mut loaded = guard.lock().await;
3944
if loaded.contains(T::PG_TYPE) {
4045
return Ok(());
4146
}
42-
let path = format!(
43-
"{}/fixtures/eql_v2_{}.sql",
44-
env!("CARGO_MANIFEST_DIR"),
45-
T::PG_TYPE
46-
);
47-
let script = std::fs::read_to_string(&path)
48-
.with_context(|| format!("reading fixture script {path} (run test:sqlx:prep first)"))?;
49-
sqlx::raw_sql(&script)
47+
sqlx::raw_sql(script)
5048
.execute(pool)
5149
.await
52-
.with_context(|| format!("loading fixture corpus into shared DB from {path}"))?;
50+
.with_context(|| {
51+
format!(
52+
"loading fixture corpus for {} into shared DB",
53+
T::PG_TYPE
54+
)
55+
})?;
5356
loaded.insert(T::PG_TYPE);
5457
Ok(())
5558
}

tests/sqlx/tests/encrypted_domain/property/fixture_oracle.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,35 @@ use proptest::prelude::*;
1717
use proptest::test_runner::{Config, TestCaseError, TestRunner};
1818
use sqlx::PgPool;
1919

20+
/// The fixture corpus SQL for `T`, `include_str!`-embedded into this test binary
21+
/// at compile time (one arm per catalog token). Embedding rather than reading
22+
/// from disk at runtime is what lets the prebuilt nextest archive carry the
23+
/// corpus into CI shards, which do a fresh checkout where the gitignored
24+
/// `tests/sqlx/fixtures/eql_v2_<T>.sql` files are absent. The path resolves
25+
/// against the `eql_tests` crate root (`tests/sqlx`). Mirrors the loud catch-all
26+
/// of the `generate_for_token` fixture dispatch.
27+
fn embedded_fixture_sql<T: ScalarType>() -> &'static str {
28+
match T::PG_TYPE {
29+
"int4" => include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/fixtures/eql_v2_int4.sql")),
30+
"int2" => include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/fixtures/eql_v2_int2.sql")),
31+
"int8" => include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/fixtures/eql_v2_int8.sql")),
32+
"date" => include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/fixtures/eql_v2_date.sql")),
33+
"text" => include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/fixtures/eql_v2_text.sql")),
34+
"timestamptz" => {
35+
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/fixtures/eql_v2_timestamptz.sql"))
36+
}
37+
other => panic!(
38+
"no embedded fixture for catalog token '{other}'; \
39+
add an include_str! arm in fixture_oracle.rs"
40+
),
41+
}
42+
}
43+
2044
/// Read every `(plaintext, payload::text)` fixture row for `T`, in id order.
2145
/// Ensures the corpus is present in the shared DB first (it lives in
2246
/// `#[sqlx::test]`'s ephemeral DBs by default, not the pool we connect to).
2347
async fn load_fixture_rows<T: ScalarType>(pool: &PgPool) -> Result<Vec<Row<T>>> {
24-
ensure_fixture_loaded::<T>(pool).await?;
48+
ensure_fixture_loaded::<T>(pool, embedded_fixture_sql::<T>()).await?;
2549
let sql = format!(
2650
"SELECT plaintext, payload::text FROM {} ORDER BY id",
2751
T::fixture_table_name()

0 commit comments

Comments
 (0)