fix(FN-891): stabilize flaky restart integration test assertions
- Replace exact createKbAgent call-count assertions with behavioral checks (toHaveBeenCalled, toBeGreaterThanOrEqual) to avoid flakiness from retry-with-new-session internals - Add resume log entry assertions as stable behavioral guarantees for restart semantics - Add testing guidance section to README for writing deterministic executor tests
This commit is contained in:
@@ -399,6 +399,12 @@ pnpm --filter @fusion/core build # Regenerate dist/
|
||||
pnpm test # Verify downstream consumers
|
||||
```
|
||||
|
||||
### Writing Deterministic Executor Tests
|
||||
|
||||
The `TaskExecutor` implements retry-with-new-agent-session behavior: when an agent session completes without calling `task_done()`, the executor automatically creates a new session and retries. Tests that are **not** specifically validating retry semantics should avoid asserting exact `createKbAgent` call counts, as the count varies depending on whether the retry path is triggered.
|
||||
|
||||
**Prefer behavioral assertions** — verify that tasks are dispatched for execution, resume log entries are written, error handlers fire, and semaphore slots are released. These guarantees are stable regardless of how many internal agent sessions are created.
|
||||
|
||||
## Dashboard Features
|
||||
|
||||
### Interactive Terminal
|
||||
|
||||
@@ -194,8 +194,15 @@ describe("In-progress task resume after restart", () => {
|
||||
// Wait for async execute calls to complete
|
||||
await new Promise((r) => setTimeout(r, 50));
|
||||
|
||||
// createKbAgent called twice per task (initial + retry when agent finishes without task_done)
|
||||
expect(mockedCreateHaiAgent).toHaveBeenCalledTimes(4);
|
||||
// Each in-progress task should have been dispatched for execution.
|
||||
// We assert at least 2 agent creations (one per in-progress task) without
|
||||
// coupling to the internal retry-with-new-session count, which is an
|
||||
// implementation detail of the executor not relevant to restart semantics.
|
||||
expect(mockedCreateHaiAgent.mock.calls.length).toBeGreaterThanOrEqual(2);
|
||||
|
||||
// Both tasks should have received resume log entries (behavioral guarantee)
|
||||
expect(store.logEntry).toHaveBeenCalledWith("FN-001", "Resumed after engine restart");
|
||||
expect(store.logEntry).toHaveBeenCalledWith("FN-002", "Resumed after engine restart");
|
||||
});
|
||||
|
||||
it("resumed task reuses existing worktree — no git worktree add called", async () => {
|
||||
@@ -645,8 +652,13 @@ describe("Crash scenario edge cases", () => {
|
||||
await executor.resumeOrphaned();
|
||||
await new Promise((r) => setTimeout(r, 50));
|
||||
|
||||
// Agent should have been created again for the re-resume (twice: initial + retry without task_done)
|
||||
expect(mockedCreateHaiAgent).toHaveBeenCalledTimes(2);
|
||||
// Agent was created for the re-resume, proving the task was eligible.
|
||||
// We don't assert exact call count — the retry-with-new-session count is
|
||||
// an executor implementation detail, not a restart-resilience concern.
|
||||
expect(mockedCreateHaiAgent).toHaveBeenCalled();
|
||||
|
||||
// Re-resume should have logged again (behavioral guarantee)
|
||||
expect(store.logEntry).toHaveBeenCalledWith("FN-090", "Resumed after engine restart");
|
||||
});
|
||||
|
||||
it("engine killed during merge — git reset --merge cleanup, task stays in-review", async () => {
|
||||
|
||||
Reference in New Issue
Block a user