feat(FN-4701): add no-changes-finalized reliability interaction test
Adds reliability interaction test coverage for the `no-changes-finalized` outcome (FN-4701), covering the benign case where verification-only done tasks complete with no owned commits or surviving branch. Fusion-Task-Id: FN-4701
This commit is contained in:
committed by
gsxdsm
parent
06810e44e6
commit
296203443b
@@ -17,6 +17,7 @@ export type ReliabilityFixture = {
|
||||
store: TaskStore;
|
||||
task: Task;
|
||||
settings: Settings;
|
||||
manager: SelfHealingManager;
|
||||
cleanup: () => Promise<void>;
|
||||
writeAndCommit: (file: string, content: string, message: string) => Promise<string>;
|
||||
createBranch: (branch: string) => Promise<void>;
|
||||
@@ -26,6 +27,7 @@ export type ReliabilityFixture = {
|
||||
recoverAlreadyMergedReviewTasks: () => Promise<number>;
|
||||
recoverMisclassifiedFailures: () => Promise<number>;
|
||||
clearStaleBlockedBy: () => Promise<number>;
|
||||
reconcileDoneTaskIntegrity: () => Promise<number>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -76,7 +78,9 @@ export async function makeReliabilityFixture(input: {
|
||||
store,
|
||||
task,
|
||||
settings,
|
||||
manager,
|
||||
cleanup: async () => {
|
||||
manager.stop();
|
||||
store.close();
|
||||
await rm(rootDir, { recursive: true, force: true });
|
||||
},
|
||||
@@ -99,6 +103,7 @@ export async function makeReliabilityFixture(input: {
|
||||
recoverAlreadyMergedReviewTasks: async () => manager.recoverAlreadyMergedReviewTasks(),
|
||||
recoverMisclassifiedFailures: async () => manager.recoverMisclassifiedFailures(),
|
||||
clearStaleBlockedBy: async () => manager.clearStaleBlockedBy(),
|
||||
reconcileDoneTaskIntegrity: async () => manager.reconcileDoneTaskIntegrity(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { classifyOwnedLandedEvidence } from "../../merger.js";
|
||||
import { makeReliabilityFixture, hasGit } from "./_helpers.js";
|
||||
|
||||
describe("no-changes-finalized reliability interactions (real git)", () => {
|
||||
it.skipIf(!hasGit)("reconciles verification-only done task without unproven warning", async () => {
|
||||
const fixture = await makeReliabilityFixture({
|
||||
taskId: "FN-4701-RI",
|
||||
task: {
|
||||
column: "done",
|
||||
branch: undefined,
|
||||
baseCommitSha: undefined,
|
||||
mergeDetails: {},
|
||||
modifiedFiles: ["docs/some-note.md"],
|
||||
},
|
||||
});
|
||||
|
||||
const { rootDir, task, store } = fixture;
|
||||
await store.moveTask(task.id, "done");
|
||||
await store.updateTask(task.id, {
|
||||
branch: undefined,
|
||||
baseCommitSha: undefined,
|
||||
mergeDetails: {},
|
||||
modifiedFiles: ["docs/some-note.md"],
|
||||
});
|
||||
const seededTask = (await store.getTask(task.id))!;
|
||||
|
||||
const logSpy = vi.spyOn(store, "logEntry");
|
||||
const updateSpy = vi.spyOn(store, "updateTask");
|
||||
const auditSpy = vi.spyOn(store, "recordRunAuditEvent");
|
||||
|
||||
try {
|
||||
const classification = await classifyOwnedLandedEvidence(rootDir, seededTask, { mergeTargetBranch: "main" });
|
||||
expect(classification.kind).toBe("no-changes-finalized");
|
||||
expect(classification).toMatchObject({
|
||||
baseRef: "main",
|
||||
details: {
|
||||
branchExists: false,
|
||||
aheadCount: null,
|
||||
baseReachableFromTarget: false,
|
||||
},
|
||||
});
|
||||
|
||||
const reconciled = await fixture.selfHeal.reconcileDoneTaskIntegrity();
|
||||
expect(reconciled).toBeGreaterThanOrEqual(1);
|
||||
|
||||
const taskLogCalls = logSpy.mock.calls.filter((call) => call[0] === seededTask.id);
|
||||
expect(taskLogCalls.some((call) => /done-task finalize evidence is unproven/.test(String(call[1] ?? "")))).toBe(false);
|
||||
|
||||
expect(updateSpy).toHaveBeenCalledWith(seededTask.id, expect.objectContaining({
|
||||
modifiedFiles: [],
|
||||
mergeDetails: expect.objectContaining({
|
||||
mergeConfirmed: true,
|
||||
noOpMerge: true,
|
||||
noOpReason: "verification-only finalize: no branch and no owned commits",
|
||||
landedFiles: [],
|
||||
}),
|
||||
}));
|
||||
|
||||
expect(
|
||||
auditSpy.mock.calls.some(([event]) =>
|
||||
(event as any)?.mutationType === "task:integrity-reconcile-modified-files" &&
|
||||
(event as any)?.metadata?.reason === "verification-only-finalize"
|
||||
),
|
||||
).toBe(true);
|
||||
|
||||
const finalizeWarned = (fixture.manager as unknown as { finalizeUnprovenWarned: Set<string> }).finalizeUnprovenWarned;
|
||||
expect(finalizeWarned.has(seededTask.id)).toBe(false);
|
||||
|
||||
await fixture.selfHeal.reconcileDoneTaskIntegrity();
|
||||
const taskLogCallsAfterSecondRun = logSpy.mock.calls.filter((call) => call[0] === seededTask.id);
|
||||
expect(
|
||||
taskLogCallsAfterSecondRun.some((call) => /done-task finalize evidence is unproven/.test(String(call[1] ?? ""))),
|
||||
).toBe(false);
|
||||
} finally {
|
||||
await fixture.cleanup();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user