Warn when live Vault reflection fails

This commit is contained in:
vorotamoroz
2026-09-05 02:10:52 +00:00
parent 5d251d1f92
commit e018cab039
3 changed files with 77 additions and 11 deletions
@@ -2,6 +2,13 @@ import { promiseWithResolvers } from "octagonal-wheels/promises";
import { reactiveSource } from "octagonal-wheels/dataobject/reactive";
import { describe, expect, it, vi } from "vitest";
import { VER, type EntryDoc } from "@vrtmrz/livesync-commonlib/compat/common/types";
import {
defaultLogger,
LOG_LEVEL_DEBUG,
LOG_LEVEL_NOTICE,
LOG_LEVEL_VERBOSE,
setGlobalLogFunction,
} from "octagonal-wheels/common/logger";
import { ReplicateResultProcessor } from "./ReplicateResultProcessor";
function note(id: string): PouchDB.Core.ExistingDocument<EntryDoc> {
@@ -21,12 +28,12 @@ function note(id: string): PouchDB.Core.ExistingDocument<EntryDoc> {
type SetupOptions = {
applicationReady?: boolean;
processSynchroniseResult?: (entry: unknown) => Promise<void>;
processSynchroniseResult?: (entry: unknown) => Promise<boolean>;
setSnapshot?: (key: string, value: unknown) => Promise<unknown>;
};
function setup(options: SetupOptions = {}) {
const processSynchroniseResult = vi.fn(options.processSynchroniseResult ?? (async () => undefined));
const processSynchroniseResult = vi.fn(options.processSynchroniseResult ?? (async () => true));
const setSnapshot = vi.fn(options.setSnapshot ?? (async () => undefined));
const runBoundedLocalApplicationActivity = vi.fn(async (task: () => Promise<void>) => await task());
const onCloseActiveReplication = vi.fn(async () => true);
@@ -120,7 +127,7 @@ describe("ReplicateResultProcessor", () => {
});
it("keeps one local application activity until every replicated document has been applied", async () => {
const applying = promiseWithResolvers<void>();
const applying = promiseWithResolvers<boolean>();
let activityFinished = false;
const { processor, processSynchroniseResult, runBoundedLocalApplicationActivity } = setup({
processSynchroniseResult: async () => applying.promise,
@@ -139,7 +146,7 @@ describe("ReplicateResultProcessor", () => {
});
expect(activityFinished).toBe(false);
applying.resolve();
applying.resolve(true);
await vi.waitFor(() => expect(activityFinished).toBe(true));
});
@@ -160,7 +167,7 @@ describe("ReplicateResultProcessor", () => {
});
it("releases and reacquires local application activity around processing suspension", async () => {
const applying = promiseWithResolvers<void>();
const applying = promiseWithResolvers<boolean>();
let completedActivities = 0;
const { processor, processSynchroniseResult, runBoundedLocalApplicationActivity } = setup({
processSynchroniseResult: async () => applying.promise,
@@ -178,7 +185,47 @@ describe("ReplicateResultProcessor", () => {
processor.resume();
await vi.waitFor(() => expect(runBoundedLocalApplicationActivity).toHaveBeenCalledTimes(2));
applying.resolve();
applying.resolve(true);
await vi.waitFor(() => expect(completedActivities).toBe(2));
});
it.each([
["returns false", async () => false, undefined],
["throws", async () => Promise.reject(new Error("File name too long")), "File name too long"],
])("reports when Vault reflection %s", async (_description, processSynchroniseResult, errorMessage) => {
const log = vi.fn((_message: unknown, _level?: number) => undefined);
setGlobalLogFunction(log);
try {
const { processor } = setup({ processSynchroniseResult });
processor.enqueueAll([note("unreflectable")]);
await vi.waitFor(() =>
expect(log).toHaveBeenCalledWith(
"Not all files could be synchronised. Check the affected files. Generate a report to review the detailed log.",
LOG_LEVEL_NOTICE,
undefined
)
);
expect(log).toHaveBeenCalledWith(
"[ReplicateResultProcessor] Live replication could not reflect unreflectable.md from the local database to the Vault; this path remains eligible for a later Vault scan.",
LOG_LEVEL_VERBOSE,
undefined
);
if (errorMessage !== undefined) {
expect(log).toHaveBeenCalledWith(
expect.objectContaining({ message: errorMessage }),
LOG_LEVEL_VERBOSE,
undefined
);
}
expect(log).not.toHaveBeenCalledWith(
expect.stringContaining("Processed: unreflectable.md"),
LOG_LEVEL_DEBUG,
undefined
);
} finally {
setGlobalLogFunction(defaultLogger);
}
});
});