mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-22 06:42:19 +03:00
test(plugin): wait for the v2 lazy-refresh tier instead of sleeping past it
`lazy refresh: [m1] then [m1,m2] reloads once; identical runs never reload`
waited for the plugin's asynchronous optional tier with a fixed `await sleep(5)`.
That is a race, not a wait: when the tier landed after the sleep, its reload was
still pending, so the next assertion counted it and read
AssertionError: an identical run never reloads
2 !== 1
The test file fails on every isolated run on the current release tip; it only
passed when the whole suite ran together and unrelated work happened to give the
tier enough slack.
Replaces both sleeps with a `settle()` helper that polls until the observed value
holds steady for three consecutive turns (5s ceiling), so the wait tracks the
work rather than the clock. The assertions are unchanged — this fixes how the
test waits, not what it checks.
The failure was invisible to the base-green sweep because
`.github/workflows/opencode-plugin-ci.yml` filters on
`paths: @omniroute/opencode-plugin*/**`, so the job only runs when the plugin
directories change and the nightly sweep never triggers it.
Isolated file: 6/6 runs green (was 0/6). Full v2 suite: 218/218. Build passes.
This commit is contained in:
@@ -6,6 +6,33 @@ interface CapturedCall {
|
||||
kind: "catalog" | "integration";
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until `read()` stops changing, then return the settled value.
|
||||
*
|
||||
* The plugin's optional tier lands asynchronously after a publish. Waiting for
|
||||
* it with a fixed `sleep(5)` raced the work: under load the tier arrived after
|
||||
* the sleep, so the *next* assertion counted its reload and read 2 where it
|
||||
* expected 1. Polling until the value holds steady for a few consecutive turns
|
||||
* ties the wait to the work instead of to the clock.
|
||||
*/
|
||||
async function settle<T>(read: () => T, quietTurns = 3, timeoutMs = 5000): Promise<T> {
|
||||
const { setTimeout: sleep } = await import("node:timers/promises");
|
||||
const deadline = Date.now() + timeoutMs;
|
||||
let last = read();
|
||||
let stable = 0;
|
||||
while (stable < quietTurns && Date.now() < deadline) {
|
||||
await sleep(5);
|
||||
const current = read();
|
||||
if (current === last) {
|
||||
stable += 1;
|
||||
} else {
|
||||
last = current;
|
||||
stable = 0;
|
||||
}
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
interface FakeCtx {
|
||||
options: Record<string, unknown>;
|
||||
catalog: {
|
||||
@@ -163,7 +190,6 @@ describe("plugin-v2 entrypoint", () => {
|
||||
const { mkdtempSync } = await import("node:fs");
|
||||
const { tmpdir } = await import("node:os");
|
||||
const { join } = await import("node:path");
|
||||
const { setTimeout: sleep } = await import("node:timers/promises");
|
||||
const dir = mkdtempSync(join(tmpdir(), "omniroute-lazy-"));
|
||||
const prevDataDir = process.env.OPENCODE_DATA_DIR;
|
||||
process.env.OPENCODE_DATA_DIR = dir;
|
||||
@@ -222,16 +248,15 @@ describe("plugin-v2 entrypoint", () => {
|
||||
await cb(draft);
|
||||
assert.equal(reloads, 0, "the first publish sets the baseline, it does not reload");
|
||||
assert.equal(modelsCall, 1);
|
||||
await sleep(5);
|
||||
// The optional tier lands after that first publish and brings combos and
|
||||
// the overlay with it — one reload, so the picker shows them without
|
||||
// waiting for the next refresh.
|
||||
const afterFirstUpgrade = reloads;
|
||||
const afterFirstUpgrade = await settle(() => reloads);
|
||||
assert.ok(afterFirstUpgrade <= 1, `at most one reload for the first upgrade, got ${reloads}`);
|
||||
await cb(draft);
|
||||
assert.equal(reloads, afterFirstUpgrade + 1, "a new model id reloads once");
|
||||
assert.equal(modelsCall, 2);
|
||||
await sleep(5);
|
||||
await settle(() => reloads);
|
||||
await cb(draft);
|
||||
assert.equal(reloads, afterFirstUpgrade + 1, "an identical run never reloads");
|
||||
assert.equal(modelsCall, 3);
|
||||
|
||||
Reference in New Issue
Block a user