| 1 | # Cluster integration tests |
| 2 | |
| 3 | This suite runs multi-runner clusters against shared PostgreSQL and MySQL |
| 4 | containers. It is excluded from the default test projects and only registered |
| 5 | when `EFFECT_CLUSTER_TESTS=1`. |
| 6 | |
| 7 | ```sh |
| 8 | EFFECT_CLUSTER_TESTS=1 pnpm test-cluster |
| 9 | ``` |
| 10 | |
| 11 | Docker must be running. Vitest global setup starts one `postgres:alpine` and one |
| 12 | `mysql:lts` container for the entire project. Every cluster uses a unique table |
| 13 | prefix, and every runner listens on an operating-system-assigned port. |
| 14 | |
| 15 | ## Harness |
| 16 | |
| 17 | `harness.ts` exposes: |
| 18 | |
| 19 | - `make({ backend, entities, lockMode, config })` to create a scoped cluster harness. |
| 20 | - `start(count, { assignedShardGroups, entities, runnerShardWeight })` to start in-process socket runners and a client over SchemaBinary, optionally overriding the entity layer for those runners. |
| 21 | - `stop(runner)` for graceful deregistration and shard handoff. |
| 22 | - `kill(runner)` for abrupt teardown without deregistration or explicit lock cleanup. |
| 23 | - `freeze(runner)` to suspend SQL heartbeats and lock refresh while leaving the runner's sockets and reserved SQL connection open. |
| 24 | - `faultLock(runner, mode)` to blackhole, stick, fail, stick while blocking release of, or clear faults on a runner's reserved lock connection. |
| 25 | - `cutSocket(runner, { peer, direction })` to close one inbound or outbound client/runner connection without stopping either endpoint. |
| 26 | - `insertMessage(row)` to inject a raw row into this cluster's prefixed message table. |
| 27 | - `waitUntil`, `waitForStableAssignments`, and `waitForEntityOwner` for deadline-based polling with cluster diagnostics on failure. |
| 28 | - `clientSharding` and `ownersOfShard` for direct shard ownership assertions. |
| 29 | - `messageCounts`, `unprocessedMessageCount`, `repliedMessageCount`, and `failedMessageCount` for storage assertions scoped to the cluster prefix. |
| 30 | |
| 31 | Advisory locks are owned by the reserved database session. A frozen advisory-lock |
| 32 | runner therefore keeps its locks until it is stopped or killed. Row-lock mode |
| 33 | uses expiry-driven takeover while frozen. |
| 34 | |
| 35 | ## Adding a test |
| 36 | |
| 37 | Add `*.test.ts` under this directory. Test files define entities and assertions; |
| 38 | all cluster startup, lifecycle, waiting, and storage inspection belongs in the |
| 39 | harness. Use the harness polling helpers instead of calling `Effect.sleep`. |