Module Package Release / publish-packages (push) Successful in 13s
Release v0.1.46. Coordinated integrity review: GovOPlaN/govoplan-core#298.
83 lines
3.7 KiB
TypeScript
83 lines
3.7 KiB
TypeScript
import { importModuleWithRetry } from "../src/platform/moduleLoading";
|
|
import { createModuleRefresh } from "../src/platform/moduleRefresh";
|
|
|
|
function assert(condition: unknown, message: string): asserts condition {
|
|
if (!condition) throw new Error(message);
|
|
}
|
|
|
|
async function verifyModuleImportRetry() {
|
|
let attempts = 0;
|
|
let pauses = 0;
|
|
const module = { id: "files", uiCapabilities: { "files.fileExplorer": {} } };
|
|
const imported = await importModuleWithRetry(async () => {
|
|
attempts += 1;
|
|
if (attempts === 1) throw new TypeError("Synthetic transient import failure");
|
|
return module;
|
|
}, async () => { pauses += 1; });
|
|
assert(imported === module, "a second successful import preserves the real module descriptor");
|
|
assert(attempts === 2 && pauses === 1, "a transient failure gets exactly one bounded retry");
|
|
|
|
attempts = 0;
|
|
pauses = 0;
|
|
const terminal = new TypeError("Synthetic final import failure");
|
|
let observed: unknown;
|
|
try {
|
|
await importModuleWithRetry(async () => { attempts += 1; throw terminal; }, async () => { pauses += 1; });
|
|
} catch (error) { observed = error; }
|
|
assert(observed === terminal, "a final failure must be reported, never replaced by an empty or fake module");
|
|
assert(attempts === 2 && pauses === 1, "permanent failure cannot start an unbounded retry loop");
|
|
|
|
attempts = 0;
|
|
pauses = 0;
|
|
await importModuleWithRetry(async () => { attempts += 1; return module; }, async () => { pauses += 1; });
|
|
assert(attempts === 1 && pauses === 0, "healthy imports do not pause or repeat");
|
|
console.log("Module import retry tests passed.");
|
|
}
|
|
|
|
void verifyModuleImportRetry().catch((error) => { throw error; });
|
|
|
|
async function verifyModuleRefresh() {
|
|
const requests: Array<{ resolve: (value: number) => void; reject: (error: unknown) => void }> = [];
|
|
const accepted: number[] = [];
|
|
const errors: unknown[] = [];
|
|
let time = 0;
|
|
const refresh = createModuleRefresh({
|
|
load: () => new Promise<number>((resolve, reject) => requests.push({ resolve, reject })),
|
|
accept: (value) => accepted.push(value), reject: (error) => errors.push(error), now: () => time
|
|
});
|
|
const settle = async () => { await Promise.resolve(); await Promise.resolve(); };
|
|
refresh.invalidate();
|
|
refresh.invalidate();
|
|
refresh.invalidate();
|
|
assert(requests.length === 1, "mutation bursts cannot start overlapping requests");
|
|
requests[0].resolve(0);
|
|
await settle();
|
|
assert(accepted.length === 0 && Number(requests.length) === 2, "obsolete success is ignored and invalidation gets one trailing read");
|
|
refresh.invalidate();
|
|
requests[1].reject(new Error("obsolete"));
|
|
await settle();
|
|
assert(errors.length === 0 && Number(requests.length) === 3, "obsolete error cannot clear the current catalogue or drop invalidation");
|
|
requests[2].resolve(2);
|
|
await settle();
|
|
assert(accepted.join() === "2", "only the current generation publishes");
|
|
refresh.refreshVisible(true);
|
|
time = 6_000;
|
|
refresh.refreshVisible(false);
|
|
assert(Number(requests.length) === 3, "focus throttle and hidden-document checks remain");
|
|
refresh.refreshVisible(true);
|
|
assert(Number(requests.length) === 4, "visible focus refresh remains available after the throttle");
|
|
requests[3].reject("current failure");
|
|
await settle();
|
|
assert(errors.join() === "current failure", "current errors retain fail-closed handling without automatic retries");
|
|
refresh.invalidate();
|
|
refresh.invalidate();
|
|
refresh.dispose();
|
|
requests[4].resolve(4);
|
|
await settle();
|
|
refresh.invalidate();
|
|
assert(Number(requests.length) === 5 && accepted.join() === "2", "authority change/unmount discards both old response and queued work");
|
|
console.log("Module refresh coalescing and generation tests passed.");
|
|
}
|
|
|
|
void verifyModuleRefresh().catch((error) => { throw error; });
|