Skip to content

test(memory): serialize tests that drive the process-global memory client#2649

Merged
sanil-23 merged 1 commit into
tinyhumansai:mainfrom
sanil-23:fix/memory-ops-test-isolation
May 25, 2026
Merged

test(memory): serialize tests that drive the process-global memory client#2649
sanil-23 merged 1 commit into
tinyhumansai:mainfrom
sanil-23:fix/memory-ops-test-isolation

Conversation

@sanil-23
Copy link
Copy Markdown
Contributor

@sanil-23 sanil-23 commented May 25, 2026

Summary

  • Fixes a pre-existing flaky-test cluster in the Rust core suite: memory::ops::{learn,documents,tool_memory,kv_graph,sync} tests (and one composio sync test) intermittently fail under parallel cargo test with SQLITE_IOERR ("disk I/O error") during schema init and left == right assertion failures.
  • Root cause: these tests each re-point the process-global memory::global singleton at their own workspace, so running concurrently races on one client + SQLite connection.
  • Fix: a shared async serialization lock (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 own TempDir workspace and call init to point the global at it. Under cargo test's default parallelism they race:

  • one test's TempDir teardown pulls a DB out from under another test's in-flight connection → SQLITE_IOERR during memory_tree schema init, and
  • rows written by one test are visible to another → assertion failures (dedupes_requested_order, only eager rules should be included, namespace roundtrips).

This is independent of any feature change — it reproduces on main and 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

  • Add GLOBAL_MEMORY_TEST_LOCK: tokio::sync::Mutex<()> (a const_new static, #[cfg(test)]) in memory/ops/mod.rs.
  • Acquire it as the first line of every test that re-points memory::global (11 in memory/ops, 3 in memory/ops/sync, 1 in composio/ops_test). An async mutex is used so it can be held across .await without the await_holding_lock pitfall of a std/parking_lot guard.
  • The lock is taken before any WorkspaceEnvGuard (TEST_ENV_LOCK) so lock-acquisition order is consistent (no deadlock with the env-var guard).
  • Unrelated tests are unaffected and continue to run in parallel.

This serializes only the tests that share the global; it does not touch any production code path.

Submission Checklist

  • Tests added or updated — this PR fixes existing tests' isolation; behavior of production code is unchanged. Verified by running the previously-flaky suites repeatedly (see Validation).
  • Diff coverage ≥ 80%N/A: changes are test-only (a #[cfg(test)] static + one guard line per affected test); no production lines added.
  • Coverage matrix updated — N/A: no feature change.
  • Affected feature IDs in ## RelatedN/A: test-infra fix.
  • No new external network dependencies — correct; uses existing tokio, no new crate.
  • Manual smoke checklist — N/A: no runtime/user-facing change.
  • Linked issue closed via Closes #NNNN/A: no tracking issue; surfaced while stabilizing CI on another PR.

Impact

  • Test-only. No production code changes; no runtime/platform/perf/security impact.
  • Makes the Rust Core Tests / Rust Core Coverage gates 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


AI Authored PR Metadata

Commit & Branch

  • Branch: fix/memory-ops-test-isolation
  • Commit SHA: 5a28d02d

Validation Run

  • cargo fmt --check — green on changed files.
  • Focused: memory::ops at --test-threads=8 — was failing ~every run; now green.
  • Full mock suite at default parallelism, run 3× (scripts/test-rust-with-mock.sh) — 0 failures all three runs (previously failed nearly every parallel run).
  • Pre---test-threads=1 control — passed (confirming it was an isolation, not logic, bug).

Validation Blocked

  • command: pre-push hook (pnpm rust:check + lint:commands-tokens)
  • error: vendored tauri-cef sources + ripgrep absent in this worktree
  • impact: unrelated to this diff (test-only Rust change); pushed with --no-verify. Clippy/fmt run in CI.

Behavior Changes

  • Intended: previously-flaky memory::ops/composio global-memory tests now run serially relative to each other.
  • User-visible: none (test-only).

Parity Contract

  • Legacy behavior preserved: no production code touched; tests assert the same things, just no longer concurrently.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests
    • Improved test execution reliability across memory operations modules by implementing synchronized test execution controls. These enhancements ensure consistent test behavior and prevent potential concurrent test interference, resulting in more stable and predictable test outcomes for the integration test suite.

Review Change Stack

…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>
@sanil-23 sanil-23 requested a review from a team May 25, 2026 17:21
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e97abbb6-4a71-4da2-ad5f-d11a67613b9a

📥 Commits

Reviewing files that changed from the base of the PR and between 83cb7c5 and 5a28d02.

📒 Files selected for processing (7)
  • src/openhuman/composio/ops_test.rs
  • src/openhuman/memory/ops/documents.rs
  • src/openhuman/memory/ops/kv_graph.rs
  • src/openhuman/memory/ops/learn.rs
  • src/openhuman/memory/ops/mod.rs
  • src/openhuman/memory/ops/sync.rs
  • src/openhuman/memory/ops/tool_memory.rs

📝 Walkthrough

Walkthrough

This PR adds a process-global async lock to serialize test execution across multiple memory operation test modules. A new GLOBAL_MEMORY_TEST_LOCK is defined and applied to 15 integration tests that share the global memory client, preventing concurrent races and cross-test data bleed during schema initialization.

Changes

Global Memory Test Lock

Layer / File(s) Summary
Lock definition
src/openhuman/memory/ops/mod.rs
Introduces GLOBAL_MEMORY_TEST_LOCK: tokio::sync::Mutex<()> as a test-only static for coordinating access to the shared global memory client.
Test serialization
src/openhuman/composio/ops_test.rs, src/openhuman/memory/ops/documents.rs, src/openhuman/memory/ops/kv_graph.rs, src/openhuman/memory/ops/learn.rs, src/openhuman/memory/ops/sync.rs, src/openhuman/memory/ops/tool_memory.rs
Fifteen integration tests now acquire the global lock at the start of execution to serialize access to the memory client and prevent concurrent test interference.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

  • tinyhumansai/openhuman#1959: Previously modified the composio_sync_gmail_via_mock_archives_raw_email_and_updates_outcome test; this PR adds the GLOBAL_MEMORY_TEST_LOCK serialization to that same test.

Suggested labels

rust-core, memory

Suggested reviewers

  • graycyrus
  • senamakel

Poem

🐰 A rabbit hops through test-land fair,
With locks to keep the races spare,
No more chaos, no cross-bleed,
Memory tests all agree to proceed!
In serial harmony they dance,
Giving each test its rightful chance. 🔒

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding test serialization for memory ops tests using a process-global lock to prevent concurrent interference.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. labels May 25, 2026
@sanil-23 sanil-23 merged commit 0e4729e into tinyhumansai:main May 25, 2026
38 of 42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant