diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5555b8e..7178138 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,8 +71,32 @@ jobs: - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 + with: + # REQUIRED. Without `workspaces:` this action looks for ONE Cargo workspace at the + # checkout root, and nothing is checked out there: every checkout above uses `path:`. + # It logged "could not find Cargo.toml" and carried on WITHOUT failing, so this job + # rebuilt everything from scratch on every run while the log said the cache step + # succeeded. Each workspace this job actually builds must be named. + workspaces: | + store-valkey-repo/store-valkey + busbarAI - name: cargo test -p busbar-store-valkey -- --ignored wipes_the_entire_namespace_destructively working-directory: store-valkey-repo/store-valkey env: VALKEY_URL: redis://localhost:6379/0 - run: cargo test -- --ignored --test-threads=1 wipes_the_entire_namespace_destructively + run: | + set -euo pipefail + # FLOOR ASSERTION on the number of tests that actually ran. `cargo test ` is a + # SUBSTRING match with no minimum: rename the test (dropping "the_" is enough) and the + # filter matches ZERO tests, cargo prints "running 0 tests / test result: ok" and EXITS 0. + # This whole job — and the dedicated valkey/valkey:8 service container it stands up — then + # goes green having run nothing, and because the test is #[ignore]'d no other job covers + # it either. Requiring "1 passed" is what makes the rename fail loudly instead. + out="$(cargo test -- --ignored --test-threads=1 \ + wipes_the_entire_namespace_destructively 2>&1 | tee /dev/stderr)" + grep -qE 'test result: ok\. 1 passed' <<<"$out" || { + echo "::error::the destructive-wipe test did not run (renamed, moved, or filtered out)." \ + "The filter matched no tests and cargo exited 0. Re-point the filter at the test's" \ + "current name — do NOT relax this assertion." >&2 + exit 1 + } diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 337614f..1b34a58 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -117,6 +117,15 @@ jobs: with: targets: ${{ matrix.target }} - uses: Swatinem/rust-cache@v2 + with: + # REQUIRED. Without `workspaces:` this action looks for ONE Cargo workspace at the + # checkout root, and nothing is checked out there: every checkout above uses `path:`. + # It logged "could not find Cargo.toml" and carried on WITHOUT failing, so this job + # rebuilt everything from scratch on every run while the log said the cache step + # succeeded. Each workspace this job actually builds must be named. + workspaces: | + store-valkey + busbarAI - name: Build the store-valkey plugin cdylib working-directory: store-valkey diff --git a/Cargo.lock b/Cargo.lock index 2895f85..962fdb0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,6 +121,8 @@ dependencies = [ "busbar-api", "busbar-plugin-abi", "serde_json", + "tracing", + "tracing-core", ] [[package]] @@ -770,9 +772,9 @@ checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "libloading" -version = "0.8.9" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" dependencies = [ "cfg-if", "windows-link", @@ -1528,6 +1530,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", + "valuable", ] [[package]] @@ -1572,6 +1575,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "version_check" version = "0.9.5" diff --git a/store-valkey-plugin/tests/e2e.rs b/store-valkey-plugin/tests/e2e.rs index dc2f0a2..65ee3da 100644 --- a/store-valkey-plugin/tests/e2e.rs +++ b/store-valkey-plugin/tests/e2e.rs @@ -41,11 +41,39 @@ const TEST_SIGNING_KEY: &str = "0123456789abcdef0123456789abcdef0123456789abcdef /// under `cargo test` (which builds the whole package including the cdylib target before running /// tests) it is always present, so this only guards against unusual invocations. fn plugin_path() -> Option { - let exe = std::env::current_exe().ok()?; // .../target//deps/e2e- - let profile_dir = exe.parent()?.parent()?; // .../target/ - let name = plugin_library_filename("busbar_store_valkey_plugin"); - let candidate = profile_dir.join(&name); - candidate.exists().then_some(candidate) + let candidate = (|| { + let exe = std::env::current_exe().ok()?; // .../target//deps/e2e- + let profile_dir = exe.parent()?.parent()?; // .../target/ + let name = plugin_library_filename("busbar_store_valkey_plugin"); + // Check BOTH the "uplifted" / copy and the raw /deps/ + // compiler output, newest wins: a bare `cargo test` does NOT uplift the cdylib to the + // top-level profile dir, only to deps/ (same fix already applied to store-postgres's, + // store-mysql's, auth-oidc's and webrequest-hook's equivalent helpers). + let uplifted = profile_dir.join(&name); + let raw = profile_dir.join("deps").join(&name); + [uplifted, raw] + .into_iter() + .filter_map(|p| { + std::fs::metadata(&p) + .and_then(|m| m.modified()) + .ok() + .map(|mtime| (p, mtime)) + }) + .max_by_key(|(_, mtime)| *mtime) + .map(|(p, _)| p) + })(); + // Under CI a missing cdylib is a HARD FAILURE, never a silent skip — the same discipline + // `valkey_url()` below already applies, and the one every sibling plugin repo applies here. + // Without it the three tests gated on this helper skip to green in 0.00s when their subject + // disappears, which is the only over-the-ABI coverage of the valkey store path. + if candidate.is_none() && std::env::var_os("CI").is_some() { + panic!( + "the store-valkey plugin cdylib is not built under CI: `cargo test` must build it \ + (checked both the uplifted target dir and target/deps). Refusing to silently skip \ + the only over-the-ABI coverage of the durable Valkey store path." + ); + } + candidate } /// The live `VALKEY_URL`, mirroring `busbar-store-valkey`'s own `live_store()` gating discipline