test(harness): sweep hardcoded binary paths + unguarded child spawns#376
Conversation
Two defect classes across the integration-test suites in tests/:
Class A — hardcoded binary paths. Several suites resolved the moon
server binary via a bare `./target/release/moon` default, a
CARGO_MANIFEST_DIR-relative `target/release/moon` guess, or a local
`find_moon_binary()`/`moon_bin()` copy that stopped at
target/{release,debug}/moon and never checked CARGO_BIN_EXE_moon (the
binary cargo actually built for THIS test run, right profile/target-dir,
guaranteed to exist whenever the env!() macro is referenced). A stale
target/release/moon of unknown provenance on a shared checkout then
runs silently instead of the freshly built binary. Migrated 33 files to
`common::find_moon_binary()` (adding `mod common;` where missing):
aof_multidb_kill9, the 10 replication_*.rs suites sharing the identical
`moon_bin() -> String` pattern, 11 suites with an inline
`Command::new("./target/release/moon")`, 4 suites with a
CARGO_MANIFEST_DIR-relative `bin_path()`/`release_binary()`, and 2
crash_recovery_* suites whose local `find_moon_binary()` predated the
CARGO_BIN_EXE_moon fallback added to tests/common/mod.rs. 5 suites
(pubsub_multi_channel_acl, sharded_multi_exec_{routing,durability,
locality}, pubsub_kv_ordering) intentionally keep their own
Option<PathBuf>-returning "skip gracefully when unbuilt" contract
(documented in their module docs) rather than switching to
find_moon_binary()'s panic-on-missing behavior; fixed in place instead
by inserting the same CARGO_BIN_EXE_moon tier ahead of their
target/{release,debug} fallback loop.
Class B — unguarded spawns. A handful of single-restart suites held a
bare `Child` across many assert!/expect() calls and only killed it in a
manual cleanup line at the end of the function, so any panic in between
orphaned a live server (the exact shape behind issue #366's 667%-CPU
incident). Converted console_gateway_test, scan_fanout_multishard,
allocator_mimalloc_smoke, perf_v0112_arenas_cap (2 tests), and both
replication_readonly_{eval,ws_mq} suites to the kill-on-drop MoonGuard
pattern from tests/bgsave_startup_race.rs (post-390308fb) /
tests/dir_deleted_degraded.rs.
Left alone (complex multi-restart harnesses, per the sweep's own
scoping rule — do not refactor these, only note them): aof_multidb_kill9
(4 tests, each with a kill+restart+reassert cycle), crash_matrix_per_shard_
{aof,bgrewriteaof}, crash_recovery_{cold_del_resurrection,
disk_offload_no_aof,orphan_sweep_readiness}, cold_shadow_{overwrite_
resurrection,single_shard_tokio}, jepsen_lite (restart-cycle Jepsen
harness with concurrent writer threads), sharded_multi_exec_{durability,
routing} (interleaved m1/m2 restart legs behind a consuming `kill9(self)`
method), used_memory_offload_truthful (kill+restart+resample), wal_group_
commit's `mod integration` block (spawn/sigkill/respawn/sigkill legs),
instance_lock (three interleaved live processes proving flock semantics),
and sigterm_shutdown (SIGTERM *is* the behavior under test; already
follows a consistent kill-before-panic ordering). aof_fsync_err_
subscribe_ordering, aof_toplevel_multishard_refusal, and
multishard_serve_smoke were already safe (catch_unwind-wrapped asserts,
self-exiting child, or kill-before-assert ordering respectively).
Verification: `cargo check --tests` green under default features,
--no-default-features --features runtime-tokio,jemalloc (CI parity),
and --features console,graph,text-index (covers every touched file's
feature gate). `cargo test --test perf_v0112_arenas_cap` run as a
representative spot check (2/2 passed) since most other touched suites
are `#[ignore]`d and need a prebuilt/feature-matched binary that CI
builds per job.
No behavior change for the default `common::find_moon_binary()` path
(unchanged); the 5 "skip gracefully" suites keep their Option contract.
author: Tin Dang <tindang.ht97@gmail.com>
Adds the [Unreleased] / ### Fixed bullet for the test-harness hygiene sweep (hardcoded target/release/moon paths + unguarded child spawns across tests/), required alongside the code change per repo convention. author: Tin Dang <tindang.ht97@gmail.com>
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
📝 WalkthroughWalkthroughIntegration test harnesses now centralize Moon executable discovery, prefer the Cargo-built binary in selected helpers, and use kill-on-drop guards in several tests to terminate and reap spawned servers. ChangesIntegration test harness hygiene
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
tests/pubsub_kv_ordering.rs (1)
29-37: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicated
moon_binary()implementation across test suites.The exact same
Option<PathBuf>binary resolver is duplicated across 5 test suites.
tests/pubsub_kv_ordering.rs#L29-L37: Extract the duplicatedmoon_binarylogic into a sharedcommon::find_moon_binary_opt() -> Option<PathBuf>helper and reuse it.tests/pubsub_multi_channel_acl.rs#L26-L34: Replace this duplicated logic with the extracted helper.tests/sharded_multi_exec_durability.rs#L36-L44: Replace this duplicated logic with the extracted helper.tests/sharded_multi_exec_locality.rs#L37-L45: Replace this duplicated logic with the extracted helper.tests/sharded_multi_exec_routing.rs#L31-L39: Replace this duplicated logic with the extracted helper.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/pubsub_kv_ordering.rs` around lines 29 - 37, Extract the duplicated moon_binary resolver into shared common::find_moon_binary_opt() -> Option<PathBuf>, preserving its existing CARGO_BIN_EXE_moon lookup and fallback behavior. Update tests/pubsub_kv_ordering.rs:29-37, tests/pubsub_multi_channel_acl.rs:26-34, tests/sharded_multi_exec_durability.rs:36-44, tests/sharded_multi_exec_locality.rs:37-45, and tests/sharded_multi_exec_routing.rs:31-39 to call the shared helper instead of maintaining local copies.tests/console_gateway_test.rs (1)
49-62: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueExtract
MoonGuardto thecommonmodule to avoid code duplication.The
MoonGuardstruct and itsDropimplementation are identical across multiple test suites. Consider extracting this utility into the sharedtests/common/mod.rsfile to adhere to DRY principles and centralize the child-process cleanup logic.
tests/console_gateway_test.rs#L49-L62: Remove this local definition and use the sharedMoonGuard.tests/scan_fanout_multishard.rs#L72-L85: Remove this local definition and use the sharedMoonGuard.♻️ Proposed refactor (in `tests/common/mod.rs`)
use std::process::Child; pub struct MoonGuard(pub Option<Child>); impl Drop for MoonGuard { fn drop(&mut self) { if let Some(mut child) = self.0.take() { sigkill(&mut child); } } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/console_gateway_test.rs` around lines 49 - 62, Extract the duplicated MoonGuard struct and Drop implementation into tests/common/mod.rs, using common::sigkill for child cleanup. Remove the local definitions at tests/console_gateway_test.rs lines 49-62 and tests/scan_fanout_multishard.rs lines 72-85, then update both suites to use the shared common::MoonGuard.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/admin_auth_cors_ratelimit.rs`:
- Around line 46-51: Preserve the tests’ graceful-skip behavior by replacing
common::find_moon_binary() with an Option<PathBuf>-returning resolver in
tests/admin_auth_cors_ratelimit.rs lines 46-51,
tests/flush_cross_shard_scatter.rs lines 30-32, and
tests/info_memory_allocator_pagecache.rs line 32; retain the existing
!bin.exists() skip handling at each corresponding call site.
---
Nitpick comments:
In `@tests/console_gateway_test.rs`:
- Around line 49-62: Extract the duplicated MoonGuard struct and Drop
implementation into tests/common/mod.rs, using common::sigkill for child
cleanup. Remove the local definitions at tests/console_gateway_test.rs lines
49-62 and tests/scan_fanout_multishard.rs lines 72-85, then update both suites
to use the shared common::MoonGuard.
In `@tests/pubsub_kv_ordering.rs`:
- Around line 29-37: Extract the duplicated moon_binary resolver into shared
common::find_moon_binary_opt() -> Option<PathBuf>, preserving its existing
CARGO_BIN_EXE_moon lookup and fallback behavior. Update
tests/pubsub_kv_ordering.rs:29-37, tests/pubsub_multi_channel_acl.rs:26-34,
tests/sharded_multi_exec_durability.rs:36-44,
tests/sharded_multi_exec_locality.rs:37-45, and
tests/sharded_multi_exec_routing.rs:31-39 to call the shared helper instead of
maintaining local copies.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 731014d6-5f3f-41f4-aae8-94e9cee7db3c
📒 Files selected for processing (37)
CHANGELOG.mdtests/admin_auth_cors_ratelimit.rstests/allocator_mimalloc_smoke.rstests/aof_fsync_err_subscribe_ordering.rstests/aof_multidb_kill9.rstests/aof_toplevel_multishard_refusal.rstests/bgsave_startup_race.rstests/cold_shadow_overwrite_resurrection.rstests/console_gateway_test.rstests/crash_matrix_per_shard_aof.rstests/crash_matrix_per_shard_bgrewriteaof.rstests/crash_recovery_cold_del_resurrection.rstests/crash_recovery_disk_offload_no_aof.rstests/crash_recovery_graph_durability.rstests/crash_recovery_orphan_sweep_readiness.rstests/crash_recovery_wal_recycle_legacy.rstests/flush_cross_shard_scatter.rstests/info_memory_allocator_pagecache.rstests/memory_prometheus_kinds.rstests/perf_v0112_arenas_cap.rstests/pubsub_kv_ordering.rstests/pubsub_multi_channel_acl.rstests/replication_graph.rstests/replication_hardening.rstests/replication_mq.rstests/replication_multishard.rstests/replication_planes.rstests/replication_readonly_eval.rstests/replication_readonly_ws_mq.rstests/replication_streaming.rstests/replication_ttl_semantics.rstests/replication_ws.rstests/scan_fanout_multishard.rstests/sharded_multi_exec_durability.rstests/sharded_multi_exec_locality.rstests/sharded_multi_exec_routing.rstests/wal_group_commit.rs
| // MOON_BIN -> CARGO_BIN_EXE_moon (cargo guarantees this exists for any | ||
| // test binary that references it) -> target/{release,debug} — see | ||
| // `common::find_moon_binary`. The bare `target/release/moon` guess this | ||
| // used to return unconditionally could silently pick a stale binary of | ||
| // unknown provenance on a shared checkout. | ||
| common::find_moon_binary() |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Dead code and broken graceful skip due to find_moon_binary() panicking.
common::find_moon_binary() panics if a binary is not found and only returns a verified existing path. This renders the downstream !bin.exists() checks unreachable, transforming the previous graceful-skip behavior into a test panic. If these suites were intended to keep their graceful skip contract, they should use an Option<PathBuf> resolver. If the panic is now desired, the dead code blocks should be removed.
tests/admin_auth_cors_ratelimit.rs#L46-L51: The switch tocommon::find_moon_binary()renders the!bin.exists()check at Line 90 dead code. Switch to anOption<PathBuf>resolver or remove the dead block.tests/flush_cross_shard_scatter.rs#L30-L32: The switch renders the!bin.exists()check at Line 55 dead code. Switch to anOption<PathBuf>resolver or remove the dead block.tests/info_memory_allocator_pagecache.rs#L32-L32: The switch renders the!bin.exists()check at Line 58 dead code. Switch to anOption<PathBuf>resolver or remove the dead block.
📍 Affects 3 files
tests/admin_auth_cors_ratelimit.rs#L46-L51(this comment)tests/flush_cross_shard_scatter.rs#L30-L32tests/info_memory_allocator_pagecache.rs#L32-L32
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/admin_auth_cors_ratelimit.rs` around lines 46 - 51, Preserve the tests’
graceful-skip behavior by replacing common::find_moon_binary() with an
Option<PathBuf>-returning resolver in tests/admin_auth_cors_ratelimit.rs lines
46-51, tests/flush_cross_shard_scatter.rs lines 30-32, and
tests/info_memory_allocator_pagecache.rs line 32; retain the existing
!bin.exists() skip handling at each corresponding call site.
Summary
Completes the harness-hygiene follow-up noted in #374 / issue #366: the incident chain (leaked test child + stale binary of unknown provenance) had two enabling patterns spread across
tests/, both now swept.Class A — binary resolution (33 suites)
Suites resolved the moon server binary via a bare
./target/release/moon, aCARGO_MANIFEST_DIR-relative guess, or a localfind_moon_binary()copy that never checkedCARGO_BIN_EXE_moon— on a shared checkout that can silently run a stale binary instead of the one cargo just built. All migrated tocommon::find_moon_binary()(MOON_BIN→CARGO_BIN_EXE_moon→ target fallbacks). The 5 suites with a documented "skip gracefully when unbuilt"Option<PathBuf>contract keep their own resolver, with theCARGO_BIN_EXE_moontier inserted ahead of the stale-path guess.Class B — kill-on-drop guards (6 suites + 1 warning fix)
console_gateway_test,scan_fanout_multishard,allocator_mimalloc_smoke,perf_v0112_arenas_cap,replication_readonly_eval,replication_readonly_ws_mqheld a bareChildacross manyassert!/.expect()calls with cleanup only at function end — a mid-test panic orphaned the server, the exact shape behind the #366 667%-CPU incident. All now use theMoonGuardkill-on-drop pattern fromtests/bgsave_startup_race.rs(whose own leftoverunused_mutwarning is also fixed here).Complex multi-restart harnesses (crash-recovery kill-9 cycles, jepsen_lite, instance_lock, sigterm_shutdown, …) were deliberately left untouched; already-correct suites left as-is. Full inventory in the commit message.
Verification
cargo check --profile release-fast --testsgreen under default features,runtime-tokio,jemalloc(CI parity), andconsole,graph,text-index(covers every touched file's cfg-gate).cargo test --profile release-fast --test perf_v0112_arenas_cap— 2/2 passed.cargo fmt --checkclean.refs #366
Summary by CodeRabbit
Bug Fixes
Documentation