From ed66e9a8f90ae242470f9a413eceb73f61c93f14 Mon Sep 17 00:00:00 2001 From: Matthew Jackson <1085847+MattJackson@users.noreply.github.com> Date: Sat, 8 Aug 2026 16:06:44 -0700 Subject: [PATCH 1/3] ci: rust-cache was caching nothing, it needs workspaces Swatinem/rust-cache@v2 was used with no workspaces input. The action looks for one Cargo workspace at the checkout root, and nothing is checked out there: every checkout in these jobs uses path:. The action logged "could not find Cargo.toml" and carried on WITHOUT failing, so the job rebuilt everything from scratch on every run while the log said the cache step succeeded. Every workspace the job actually builds is now named. Where the job also builds the sibling busbar checkout, that is listed too: it is by far the larger of the two builds and the one worth caching most. --- .github/workflows/ci.yml | 9 +++++++++ .github/workflows/release.yml | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5555b8e..79d493b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,6 +71,15 @@ 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: 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 From 9705bb3649316039f6ad28e7af3629094323d794 Mon Sep 17 00:00:00 2001 From: Matthew Jackson <1085847+MattJackson@users.noreply.github.com> Date: Sat, 8 Aug 2026 16:10:53 -0700 Subject: [PATCH 2/3] ci: empty commit to measure a warm cache run From 19f91e2707ad946a6a036e0a4be329fab372c043 Mon Sep 17 00:00:00 2001 From: Matthew Jackson <1085847+MattJackson@users.noreply.github.com> Date: Sat, 8 Aug 2026 19:42:22 -0700 Subject: [PATCH 3/3] ci: the destructive-wipe job could go green having run nothing Two independent ways this job's only real assertion could vanish silently. 1. `cargo test ` is a SUBSTRING match with NO floor. Rename the test -- dropping just `the_` from `wipes_the_entire_namespace_destructively` is enough -- and the filter matches zero tests: running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out exit status 0 The job goes green, having stood up a dedicated valkey/valkey:8 service container to run nothing at all, and because the test is `#[ignore]`d no other job covers it either. The step now asserts `test result: ok. 1 passed`, so a rename fails loudly instead of quietly deleting the coverage. Deliberately NOT `--exact`: the `1 passed` floor is the load-bearing half and cannot break on a guess about the module path. 2. `plugin_path()` in the plugin's e2e tests was the only one of the ten sibling plugin repos without the `is_none() && CI -> panic!()` guard -- while `valkey_url()` seventeen lines below it in the same file has it. Demonstrated rather than assumed, with the cdylib absent: running 3 tests test admin_api_installs_the_valkey_plugin_and_writes_land_in_real_valkey ... ok test load_and_exercise_valkey_plugin_bad_config_fails_over_abi ... ok test load_and_exercise_valkey_plugin_persists_to_real_valkey_across_reopen ... ok test result: ok. 3 passed; ... finished in 0.00s Three tests "passed" in 0.00s without their subject existing. It now checks both the uplifted target dir and target/deps (a bare `cargo test` uplifts to neither for this crate), and refuses to skip under CI. --- .github/workflows/ci.yml | 17 +++++++++++++- Cargo.lock | 13 +++++++++-- store-valkey-plugin/tests/e2e.rs | 38 +++++++++++++++++++++++++++----- 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79d493b..7178138 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,4 +84,19 @@ jobs: 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/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