test(remote-questions): add regression tests for race model (#3810)
Validates the race routing logic: raceRemoteAndLocal helper exists, routing checks both hasRemote and ctx.hasUI, remote timeouts are treated as non-wins, AbortController cancels the loser, and isRemoteConfigured is exported from manager.ts.
This commit is contained in:
parent
dadb0b136e
commit
c1a68a48a9
1 changed files with 98 additions and 0 deletions
|
|
@ -760,6 +760,104 @@ test("ask-user-questions source-level: tryRemoteQuestions is called before the h
|
|||
);
|
||||
});
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// Race model tests (#3810) — local TUI races against remote channel
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
test("ask-user-questions source-level: raceRemoteAndLocal function exists", () => {
|
||||
const src = readFileSync(
|
||||
join(__dirname, "..", "..", "ask-user-questions.ts"),
|
||||
"utf-8",
|
||||
);
|
||||
assert.ok(
|
||||
src.includes("async function raceRemoteAndLocal("),
|
||||
"raceRemoteAndLocal helper should exist for racing local TUI against remote channel",
|
||||
);
|
||||
});
|
||||
|
||||
test("ask-user-questions source-level: race path uses isRemoteConfigured for routing", () => {
|
||||
const src = readFileSync(
|
||||
join(__dirname, "..", "..", "ask-user-questions.ts"),
|
||||
"utf-8",
|
||||
);
|
||||
assert.ok(
|
||||
src.includes("isRemoteConfigured()"),
|
||||
"execute() should call isRemoteConfigured() for lightweight routing decision",
|
||||
);
|
||||
});
|
||||
|
||||
test("ask-user-questions source-level: race path checks both hasRemote and ctx.hasUI", () => {
|
||||
// Regression: #3810 — the race should only activate when BOTH remote and local UI
|
||||
// are available. Headless mode should still use remote-only, and no-remote should
|
||||
// use local-only.
|
||||
const src = readFileSync(
|
||||
join(__dirname, "..", "..", "ask-user-questions.ts"),
|
||||
"utf-8",
|
||||
);
|
||||
assert.ok(
|
||||
src.includes("hasRemote && ctx.hasUI"),
|
||||
"Race path should require both remote configured and local UI available",
|
||||
);
|
||||
assert.ok(
|
||||
src.includes("hasRemote && !ctx.hasUI"),
|
||||
"Headless path should handle remote-only when no local UI",
|
||||
);
|
||||
});
|
||||
|
||||
test("ask-user-questions source-level: race treats remote timeout as non-win", () => {
|
||||
// Regression: the whole point of the race is that a remote timeout should NOT
|
||||
// block the local TUI. The race helper must filter out timed_out results.
|
||||
const src = readFileSync(
|
||||
join(__dirname, "..", "..", "ask-user-questions.ts"),
|
||||
"utf-8",
|
||||
);
|
||||
const raceFnStart = src.indexOf("async function raceRemoteAndLocal(");
|
||||
const raceFnEnd = src.indexOf("\n}", raceFnStart);
|
||||
const raceFnBody = src.slice(raceFnStart, raceFnEnd);
|
||||
assert.ok(
|
||||
raceFnBody.includes("timed_out"),
|
||||
"raceRemoteAndLocal should check for timed_out in remote results",
|
||||
);
|
||||
assert.ok(
|
||||
raceFnBody.includes("details?.error"),
|
||||
"raceRemoteAndLocal should check for error in remote results",
|
||||
);
|
||||
});
|
||||
|
||||
test("ask-user-questions source-level: race uses AbortController to cancel loser", () => {
|
||||
const src = readFileSync(
|
||||
join(__dirname, "..", "..", "ask-user-questions.ts"),
|
||||
"utf-8",
|
||||
);
|
||||
assert.ok(
|
||||
src.includes("new AbortController()"),
|
||||
"Race path should create an AbortController for cancellation",
|
||||
);
|
||||
assert.ok(
|
||||
src.includes("controller.abort()"),
|
||||
"raceRemoteAndLocal should abort the controller to cancel the losing side",
|
||||
);
|
||||
});
|
||||
|
||||
test("manager source-level: isRemoteConfigured export exists", () => {
|
||||
const src = readFileSync(
|
||||
join(__dirname, "..", "..", "remote-questions", "manager.ts"),
|
||||
"utf-8",
|
||||
);
|
||||
assert.ok(
|
||||
src.includes("export function isRemoteConfigured()"),
|
||||
"manager.ts should export isRemoteConfigured for lightweight config checking",
|
||||
);
|
||||
// Must delegate to resolveRemoteConfig — no separate config parsing
|
||||
const fnStart = src.indexOf("export function isRemoteConfigured()");
|
||||
const fnEnd = src.indexOf("\n}", fnStart);
|
||||
const fnBody = src.slice(fnStart, fnEnd);
|
||||
assert.ok(
|
||||
fnBody.includes("resolveRemoteConfig()"),
|
||||
"isRemoteConfigured should delegate to resolveRemoteConfig",
|
||||
);
|
||||
});
|
||||
|
||||
test("config source-level: removeProviderToken uses auth.remove not auth.set with empty key", () => {
|
||||
const commandSrc = readFileSync(
|
||||
join(__dirname, "..", "..", "remote-questions", "remote-command.ts"),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue