71 lines
4.1 KiB
Markdown
71 lines
4.1 KiB
Markdown
# Seeded sync workloads
|
|
|
|
The fuzzer runs three real clients against an isolated real server. It shares the
|
|
scripted suite's filesystem adapter and canonical-state checks. Polling is disabled
|
|
so it cannot repair missing notifications; separate fake-clock tests cover polling.
|
|
|
|
From `frontend`, after building the server:
|
|
|
|
```sh
|
|
npm run build --workspace sync-client --workspace deterministic-tests --workspace test-client
|
|
node test-client/dist/cli.js --seed 42 --iterations 25
|
|
node test-client/dist/cli.js --replay /path/to/trace-42.json
|
|
```
|
|
|
|
Each invocation owns its server and database. `--artifacts` selects the output
|
|
directory. The trace is written before execution; results retain exercised request
|
|
and crash checkpoints, response types and coverage counts. Failures also retain
|
|
metadata, visible/durable disk images and CAS requests before cleanup.
|
|
|
|
## Workload and oracle
|
|
|
|
Version 2 traces contain an editor-intent program and its compiled steps.
|
|
`model.ts` independently interprets that intent into complete expected file sets:
|
|
exact bytes, paths and persistent identity keys. It imports no production merge
|
|
implementation and never adopts observed output as the expected state. Deleted
|
|
identity keys remain reserved. Concurrent text cases specify exact allowed results;
|
|
binary conflicts specify the documented first-committed winner.
|
|
|
|
Each epoch composes arbitrary creates, replacements, range deletions, renames,
|
|
swaps and immediate delete/recreate operations before synchronization. Conflict
|
|
copies stay in the document pool and are subsequently edited, renamed and deleted.
|
|
Sixteen fault/concurrency families run in seeded shuffled cycles, including:
|
|
|
|
- Three writers editing separated fields and two writers making overlapping edits.
|
|
- Forced stale-base races: hold a content CAS while another writer commits, rename
|
|
the local file, then require a new `StaleBase` response and the exact merged bytes.
|
|
- Online primitive histories and offline batches, delayed editor notifications,
|
|
and failures before or after durable metadata saves.
|
|
- Requests held before send or after receipt while further writes/renames occur;
|
|
dropped create, content and manifest requests with exact retry checks.
|
|
- Abrupt worker termination after accepted CAS responses, at metadata-save
|
|
boundaries, and during remote file installation, followed by user edits and
|
|
recovery. Some histories also kill and restart the server.
|
|
|
|
Inputs include empty text, invalid UTF-8 bytes, Unicode, combining characters,
|
|
emoji, BOMs, CRLFs, size/cache boundaries, long filenames, case/normalization
|
|
aliases and file/directory conflicts. Initial inventories include 70 and 130
|
|
documents to exercise paginated catchup; caches range from zero to 64 KiB.
|
|
Every checkpoint checks the full expected state on all replicas and the server.
|
|
Full-state checks also repeat after delayed events and crash recovery.
|
|
|
|
## Campaigns, replay and reduction
|
|
|
|
`scripts/e2e.sh` replays every checked-in `corpus/*.json` trace before fresh random
|
|
seeds. `E2E_SEED` pins a campaign; without it the runner prints and saves a fresh
|
|
uint32 seed range. Scheduled CI runs use 100 rounds per worker. The aggregate
|
|
`coverage.json` reports actions, CAS responses/payloads and exercised fault
|
|
boundaries. These are behavioral counters, not source branch-coverage percentages.
|
|
|
|
On failure, the CLI automatically tries to remove epochs and individual actions,
|
|
recompiling every expected state from the remaining intent. Dependency-invalid
|
|
histories are skipped. A reduction must reproduce the same failure twice before
|
|
acceptance. `--shrink-attempts` controls the budget (default 32); `--no-shrink`
|
|
retains just the original reproducer. Replay `minimized-<seed>.json`, fix the bug,
|
|
and commit that concrete program to `corpus/`. Version 1 action traces still replay.
|
|
|
|
Request gates and crash targets are replayed and must actually fire. UUID-derived
|
|
paths use symbolic identity keys. Seeds do not control OS or server scheduling,
|
|
and replay does not reuse production UUIDs. This is broader bug discovery, not a
|
|
proof of all possible interleavings or correctness. See the
|
|
[full harness documentation](../deterministic-tests/README.md).
|