mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-08-31 07:47:05 +00:00
Add safe Metadata document ID repair
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import type { DocumentID } from "@vrtmrz/livesync-commonlib/compat/common/types";
|
||||
import type {
|
||||
MetadataDocumentRepairRequest,
|
||||
MetadataDocumentRepairResult,
|
||||
} from "@vrtmrz/livesync-commonlib/compat/serviceFeatures/offlineScanner";
|
||||
import { executeMetadataIdentityRepair } from "./metadataIdentityRepair";
|
||||
|
||||
const request: MetadataDocumentRepairRequest = {
|
||||
actualDocumentId: "f:stale" as DocumentID,
|
||||
expectedDocumentId: "f:expected" as DocumentID,
|
||||
sourceRevision: "4-source",
|
||||
};
|
||||
|
||||
function createDependencies() {
|
||||
const events: string[] = [];
|
||||
return {
|
||||
events,
|
||||
confirm: vi.fn(async () => true),
|
||||
repair: vi.fn(async (): Promise<MetadataDocumentRepairResult> => {
|
||||
events.push("repair");
|
||||
return {
|
||||
status: "completed" as const,
|
||||
...request,
|
||||
targetCreated: true,
|
||||
};
|
||||
}),
|
||||
requestOrdinaryScan: vi.fn(async () => {
|
||||
events.push("scan");
|
||||
return true;
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
describe("executeMetadataIdentityRepair", () => {
|
||||
it("performs no mutation when the separate confirmation is cancelled", async () => {
|
||||
const dependencies = createDependencies();
|
||||
dependencies.confirm.mockResolvedValue(false);
|
||||
|
||||
await expect(executeMetadataIdentityRepair(request, dependencies)).resolves.toEqual({
|
||||
status: "cancelled",
|
||||
});
|
||||
expect(dependencies.repair).not.toHaveBeenCalled();
|
||||
expect(dependencies.requestOrdinaryScan).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("requests an ordinary scan only after Commonlib completes the exact repair", async () => {
|
||||
const dependencies = createDependencies();
|
||||
|
||||
await expect(executeMetadataIdentityRepair(request, dependencies)).resolves.toMatchObject({
|
||||
status: "repair-result",
|
||||
result: { status: "completed" },
|
||||
scanCompleted: true,
|
||||
});
|
||||
expect(dependencies.repair).toHaveBeenCalledWith(request);
|
||||
expect(dependencies.requestOrdinaryScan).toHaveBeenCalledOnce();
|
||||
expect(dependencies.repair.mock.invocationCallOrder[0]).toBeLessThan(
|
||||
dependencies.requestOrdinaryScan.mock.invocationCallOrder[0]
|
||||
);
|
||||
expect(dependencies.events).toEqual(["repair", "scan"]);
|
||||
});
|
||||
|
||||
it("keeps a completed repair distinct when the ordinary scan cannot start", async () => {
|
||||
const dependencies = createDependencies();
|
||||
dependencies.requestOrdinaryScan.mockResolvedValue(false);
|
||||
|
||||
await expect(executeMetadataIdentityRepair(request, dependencies)).resolves.toMatchObject({
|
||||
status: "repair-result",
|
||||
result: { status: "completed" },
|
||||
scanCompleted: false,
|
||||
});
|
||||
expect(dependencies.requestOrdinaryScan).toHaveBeenCalledOnce();
|
||||
expect(dependencies.events).toEqual(["repair"]);
|
||||
});
|
||||
|
||||
it("keeps a completed repair distinct when requesting the ordinary scan throws", async () => {
|
||||
const dependencies = createDependencies();
|
||||
const error = new Error("scan unavailable");
|
||||
dependencies.requestOrdinaryScan.mockRejectedValue(error);
|
||||
|
||||
await expect(executeMetadataIdentityRepair(request, dependencies)).resolves.toMatchObject({
|
||||
status: "repair-result",
|
||||
result: { status: "completed" },
|
||||
scanCompleted: false,
|
||||
scanError: error,
|
||||
});
|
||||
expect(dependencies.events).toEqual(["repair"]);
|
||||
});
|
||||
|
||||
it("does not scan after a stale, blocked, or failed repair result", async () => {
|
||||
for (const status of ["stale", "blocked", "failed"] as const) {
|
||||
const dependencies = createDependencies();
|
||||
dependencies.repair.mockResolvedValue({
|
||||
status,
|
||||
...request,
|
||||
targetCreated: false,
|
||||
});
|
||||
|
||||
await expect(executeMetadataIdentityRepair(request, dependencies)).resolves.toMatchObject({
|
||||
status: "repair-result",
|
||||
result: { status },
|
||||
scanCompleted: false,
|
||||
});
|
||||
expect(dependencies.requestOrdinaryScan).not.toHaveBeenCalled();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user