FN-6195: isolate and quarantine flaky db-corruption test
Stop the self-healing DB corruption test from leaking into unrelated tmpdir state while quarantining the known flake. - mock node:os tmpdir usage so the test runs inside a per-test sandbox and cleans it up after each case - add the flaky self-healing DB corruption test to the engine default exclude list - record the quarantine entry and failure context in scripts/lib/test-quarantine.json Files changed: .../__tests__/self-healing-db-corruption.test.ts | 22 ++++++++++++++++++++++ packages/engine/vitest.config.ts | 1 + scripts/lib/test-quarantine.json | 8 +++++++- 3 files changed, 30 insertions(+), 1 deletion(-) Fusion-Task-Id: FN-6195 Fusion-Task-Lineage: 60f7f6ca-d14d-42b4-b47e-0644a25e64ae
This commit is contained in:
@@ -1,8 +1,18 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import { EventEmitter } from "node:events";
|
import { EventEmitter } from "node:events";
|
||||||
|
import { mkdtempSync, rmSync } from "node:fs";
|
||||||
|
import { tmpdir } from "node:os";
|
||||||
|
import { join } from "node:path";
|
||||||
|
|
||||||
import type { Settings, TaskStore } from "@fusion/core";
|
import type { Settings, TaskStore } from "@fusion/core";
|
||||||
|
|
||||||
|
const osState = vi.hoisted(() => ({ tempRoot: "" }));
|
||||||
|
|
||||||
|
vi.mock("node:os", async () => {
|
||||||
|
const actual = await vi.importActual<typeof import("node:os")>("node:os");
|
||||||
|
return { ...actual, tmpdir: vi.fn(() => osState.tempRoot || actual.tmpdir()) };
|
||||||
|
});
|
||||||
|
|
||||||
import { SelfHealingManager } from "../self-healing.js";
|
import { SelfHealingManager } from "../self-healing.js";
|
||||||
import type { NotificationService } from "../notification/notification-service.js";
|
import type { NotificationService } from "../notification/notification-service.js";
|
||||||
import * as notifierModule from "../notifier.js";
|
import * as notifierModule from "../notifier.js";
|
||||||
@@ -97,8 +107,13 @@ function stubMaintenance(manager: SelfHealingManager) {
|
|||||||
vi.spyOn(manager, "archiveStaleDoneTasks").mockResolvedValue(0);
|
vi.spyOn(manager, "archiveStaleDoneTasks").mockResolvedValue(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RM = { recursive: true, force: true, maxRetries: 5, retryDelay: 50 } as const;
|
||||||
|
let sandboxRoot = "";
|
||||||
|
|
||||||
describe("FN-5284: self-healing DB corruption surfacing", () => {
|
describe("FN-5284: self-healing DB corruption surfacing", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
sandboxRoot = mkdtempSync(join(tmpdir(), "fusion-db-corruption-sandbox-"));
|
||||||
|
osState.tempRoot = sandboxRoot;
|
||||||
vi.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
vi.setSystemTime(new Date("2026-05-20T00:00:00.000Z"));
|
vi.setSystemTime(new Date("2026-05-20T00:00:00.000Z"));
|
||||||
vi.spyOn(notifierModule, "getActiveNotificationService").mockReturnValue(undefined);
|
vi.spyOn(notifierModule, "getActiveNotificationService").mockReturnValue(undefined);
|
||||||
@@ -108,6 +123,13 @@ describe("FN-5284: self-healing DB corruption surfacing", () => {
|
|||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vi.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
vi.useRealTimers();
|
vi.useRealTimers();
|
||||||
|
osState.tempRoot = "";
|
||||||
|
try {
|
||||||
|
rmSync(sandboxRoot, RM);
|
||||||
|
} catch {
|
||||||
|
// Best-effort cleanup only.
|
||||||
|
}
|
||||||
|
sandboxRoot = "";
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not dispatch or audit when the database is healthy", async () => {
|
it("does not dispatch or audit when the database is healthy", async () => {
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ export default defineConfig({
|
|||||||
include: ["src/**/*.test.ts"],
|
include: ["src/**/*.test.ts"],
|
||||||
exclude: [
|
exclude: [
|
||||||
"src/__tests__/reliability-interactions/**/*.test.ts",
|
"src/__tests__/reliability-interactions/**/*.test.ts",
|
||||||
|
"src/__tests__/self-healing-db-corruption.test.ts",
|
||||||
// Real-git heavy files run in the engine-slow project so local
|
// Real-git heavy files run in the engine-slow project so local
|
||||||
// `pnpm test` stays snappy. CI picks them up via `test:slow`
|
// `pnpm test` stays snappy. CI picks them up via `test:slow`
|
||||||
// / `test:all` invoked from the root `test:full` script.
|
// / `test:all` invoked from the root `test:full` script.
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
{
|
{
|
||||||
"$comment": "Flaky-test quarantine ledger (deletion ratchet — see AGENTS.md 'Flaky tests: quarantine on sight' and docs/testing.md 'Quarantine ledger and the deletion ratchet'). A test observed failing without a corresponding real bug is quarantined ON SIGHT: add an entry here AND a matching one-line `exclude` entry in that package's vitest config, in the same commit. Every entry needs a non-empty `reason` (link the failing run) and a `quarantinedAt` date — the entry expires 14 days later, at which point the test file is DELETED unless someone rescues it with evidence it catches real regressions plus a root-cause fix (never appeasement). There is deliberately no loader module and no automation around this file: it is a dated record, the vitest config exclude is the mechanism, and the sweep is policy executed by whoever touches the suite.",
|
"$comment": "Flaky-test quarantine ledger (deletion ratchet — see AGENTS.md 'Flaky tests: quarantine on sight' and docs/testing.md 'Quarantine ledger and the deletion ratchet'). A test observed failing without a corresponding real bug is quarantined ON SIGHT: add an entry here AND a matching one-line `exclude` entry in that package's vitest config, in the same commit. Every entry needs a non-empty `reason` (link the failing run) and a `quarantinedAt` date — the entry expires 14 days later, at which point the test file is DELETED unless someone rescues it with evidence it catches real regressions plus a root-cause fix (never appeasement). There is deliberately no loader module and no automation around this file: it is a dated record, the vitest config exclude is the mechanism, and the sweep is policy executed by whoever touches the suite.",
|
||||||
"entries": []
|
"entries": [
|
||||||
|
{
|
||||||
|
"file": "packages/engine/src/__tests__/self-healing-db-corruption.test.ts",
|
||||||
|
"reason": "FN-6195: observed flake when runMaintenance() scanned the real OS tmpdir and picked up stale fusion-ai-merge-* worktrees from unrelated tests, adding unexpected audit calls. Failing run: Fusion task FN-6195 agent verification log, 2026-06-10.",
|
||||||
|
"quarantinedAt": "2026-06-10"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user