fix(aw-sync): use atomic counter in test tmp_db to fix parallel-test path collision - #655
Conversation
…est path collisions
Tests in sync_roundtrip run in parallel. Both test_push_does_not_reexport_synced_buckets
and test_own_data_does_not_return_via_peer call round_trip(), which calls datastore("a-local")
etc. with the same names. The old tmp_db() used SystemTime nanoseconds, which can collide
on macOS (lower clock resolution) — two parallel tests then share the same SQLite file and
race on migrations, producing "duplicate column name: data".
Replace the timestamp with a process-wide AtomicU64 counter. Each call to tmp_db() gets
a unique value regardless of when it runs, eliminating the race.
Greptile SummaryThe PR makes temporary SQLite paths unique both within a parallel test run and across separate runs.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains; the timestamp preserves cross-run uniqueness while the atomic counter guarantees uniqueness among parallel calls within one process. Important Files Changed
Reviews (2): Last reviewed commit: "fix(aw-sync): add timestamp to tmp_db pa..." | Re-trigger Greptile |
| // clock tick (seen on macOS where SystemTime resolution can be coarser than | ||
| // nanoseconds, causing path collisions and SQLite migration races). | ||
| static DB_COUNTER: AtomicU64 = AtomicU64::new(0); | ||
|
|
There was a problem hiding this comment.
|
CI is all green (format, clippy, ubuntu/mac/windows/android). Greptile gave this a 4/5 and flagged one non-blocking concern: the process-global |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #655 +/- ##
==========================================
+ Coverage 70.81% 78.31% +7.49%
==========================================
Files 51 65 +14
Lines 2916 5409 +2493
==========================================
+ Hits 2065 4236 +2171
- Misses 851 1173 +322 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Counter resets to 0 on each process invocation; combining it with a nanosecond timestamp means paths are unique across separate test runs even when the PID is reused, addressing the Greptile P2 concern. The counter still provides the within-run parallel-test guarantee. No new dependencies required.
|
@greptileai review |
|
CI-green and mergeable (Greptile 5/5) — waiting only on a maintainer click. This PR is ready to merge, but the bot has pull-only access to this repo and can't self-merge — surfacing it here so it isn't lost. The monitoring loop will stop re-flagging it now that this note is posted. |
…mestamp) The counter alone is unique within a process but not across runs: the tests never remove their temp dbs, so a PID reuse restarts the counter at 0 and can reopen a leftover file. Keeping the timestamp covers that. Makes the file byte-identical to ActivityWatch#655, which fixes the same macOS flake on master, so the two land in either order without a conflict.
Problem
test_push_does_not_reexport_synced_bucketsandtest_own_data_does_not_return_via_peerboth callround_trip(), which callsdatastore("a-local"),datastore("a-export"), etc. with the same names. Rust's test runner executes these tests in parallel.tmp_db()previously built its path from:On macOS,
SystemTime::now()can return the same nanosecond value for two calls that happen within the same clock tick (the OS timer resolution can be coarser than 1 ns). When that happens, both parallel tests try to open the same SQLite file. One test runs thev1→v2migration (adding thedatacolumn tobuckets) and the other hits it with the column already present, panicking:This caused an intermittent
BuildCI failure — first seen when the tests were added in #648, and again on master after #653.Fix
Add a process-wide
AtomicU64counter to the path, alongside the existing timestamp. The two components cover different collision dimensions and neither is sufficient alone:The counter fixes the parallel-test collision above. The timestamp is retained because the counter resets to 0 in each new process, so a later run that draws a recycled PID could otherwise reconstruct a path left behind in
temp_dir()by an earlier run — the cross-run case Greptile flagged on the first revision of this PR.tempfile::TempDirwould cover both dimensions unconditionally and self-clean; happy to switch to it if the maintainers prefer that over the added dependency.No functional change to the tests themselves.