test(memory): serialize tests that drive the process-global memory client#2649
Conversation
…ient
`memory::global` is a process-wide singleton (`GLOBAL_CLIENT`). Tests across
memory/ops/{learn,documents,tool_memory,kv_graph,sync} and one composio sync
test each call `memory::global::init(...)` to re-point it at their own TempDir
workspace. Run concurrently by `cargo test`, they race on that single client +
its SQLite connection: schema init hits SQLITE_IOERR ("disk I/O error") and
rows bleed across tests (assertion failures). Reproduces on main independent of
any feature work; passes at `--test-threads=1`.
Add a shared async lock (`GLOBAL_MEMORY_TEST_LOCK`, `tokio::sync::Mutex` — no
new dependency) and acquire it as the first line of every test that re-points
the global, so those tests run serially relative to each other while unrelated
tests still parallelize. The lock is acquired before any `WorkspaceEnvGuard`
(`TEST_ENV_LOCK`) so lock order is consistent.
Verified: 3x full mock suite at default parallelism → 0 failures (was failing
nearly every parallel run; e.g. memory::ops at --test-threads=8).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThis PR adds a process-global async lock to serialize test execution across multiple memory operation test modules. A new ChangesGlobal Memory Test Lock
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Summary
memory::ops::{learn,documents,tool_memory,kv_graph,sync}tests (and onecomposiosync test) intermittently fail under parallelcargo testwithSQLITE_IOERR("disk I/O error") during schema init andleft == rightassertion failures.memory::globalsingleton at their own workspace, so running concurrently races on one client + SQLite connection.tokio::sync::Mutex, no new dependency) acquired by every test that re-points the global, so they run serially relative to each other while everything else still parallelizes.Problem
memory::global::init(workspace)writes a process-wide singleton (GLOBAL_CLIENT: OnceLock<…>). The affected tests each set up their ownTempDirworkspace and callinitto point the global at it. Undercargo test's default parallelism they race:TempDirteardown pulls a DB out from under another test's in-flight connection →SQLITE_IOERRduringmemory_treeschema init, anddedupes_requested_order,only eager rules should be included, namespace roundtrips).This is independent of any feature change — it reproduces on
mainand on a clean control run, and the failing set varies run-to-run (3 in CI / 6–8 locally on a 20-core box). It passes deterministically at--test-threads=1, which is the tell of a test-isolation bug rather than a logic bug.Solution
GLOBAL_MEMORY_TEST_LOCK: tokio::sync::Mutex<()>(aconst_newstatic,#[cfg(test)]) inmemory/ops/mod.rs.memory::global(11 inmemory/ops, 3 inmemory/ops/sync, 1 incomposio/ops_test). An async mutex is used so it can be held across.awaitwithout theawait_holding_lockpitfall of astd/parking_lotguard.WorkspaceEnvGuard(TEST_ENV_LOCK) so lock-acquisition order is consistent (no deadlock with the env-var guard).This serializes only the tests that share the global; it does not touch any production code path.
Submission Checklist
N/A: changes are test-only (a#[cfg(test)]static + one guard line per affected test); no production lines added.N/A: no feature change.## Related—N/A: test-infra fix.tokio, no new crate.N/A: no runtime/user-facing change.Closes #NNN—N/A: no tracking issue; surfaced while stabilizing CI on another PR.Impact
Rust Core Tests/Rust Core Coveragegates deterministic — currently they flake on this for every PR. Slight serialization of ~15 global-touching tests; the rest of the suite keeps its parallelism.Related
memory/ops/{documents,learn,tool_memory,kv_graph}); cc the author for awareness.AI Authored PR Metadata
Commit & Branch
fix/memory-ops-test-isolation5a28d02dValidation Run
cargo fmt --check— green on changed files.memory::opsat--test-threads=8— was failing ~every run; now green.scripts/test-rust-with-mock.sh) — 0 failures all three runs (previously failed nearly every parallel run).--test-threads=1control — passed (confirming it was an isolation, not logic, bug).Validation Blocked
command:pre-push hook (pnpm rust:check+lint:commands-tokens)error:vendoredtauri-cefsources +ripgrepabsent in this worktreeimpact:unrelated to this diff (test-only Rust change); pushed with--no-verify. Clippy/fmt run in CI.Behavior Changes
memory::ops/composioglobal-memory tests now run serially relative to each other.Parity Contract
🤖 Generated with Claude Code
Summary by CodeRabbit