From e8c52b06b67d2d9e53d78084b292f985afb232d5 Mon Sep 17 00:00:00 2001 From: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> Date: Mon, 7 Sep 2026 16:19:50 -0300 Subject: [PATCH] test(plugin): wait for the v2 lazy-refresh tier instead of sleeping past it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `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. --- .../opencode-plugin-v2/tests/index.test.ts | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/@omniroute/opencode-plugin-v2/tests/index.test.ts b/@omniroute/opencode-plugin-v2/tests/index.test.ts index 83767c9851..0547eb8c2f 100644 --- a/@omniroute/opencode-plugin-v2/tests/index.test.ts +++ b/@omniroute/opencode-plugin-v2/tests/index.test.ts @@ -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(read: () => T, quietTurns = 3, timeoutMs = 5000): Promise { + 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; 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);