Skip to content

Commit 338dd2f

Browse files
committed
merge(main): incorporate terminal test fix
2 parents 6b8fc44 + 2d03922 commit 338dd2f

23 files changed

Lines changed: 844 additions & 195 deletions

.github/workflows/codebase-growth-guardrails.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ jobs:
140140
set -euo pipefail
141141
node --experimental-strip-types tools/growth-guardrails/test-conditionals.mts
142142
143-
- name: Require changed test files not to add table-test candidate loops
143+
- name: Require changed test files not to increase test-loop counts
144144
env:
145145
GH_TOKEN: ${{ github.token }}
146146
PR_NUMBER: ${{ github.event.pull_request.number }}

nemoclaw/src/onboard/config.test.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -105,24 +105,25 @@ describe("onboard/config", () => {
105105
expect(describeOnboardProvider(config)).toBe("My Custom Provider");
106106
});
107107

108-
const endpointCases: [EndpointType, string][] = [
109-
["build", "NVIDIA Endpoints"],
110-
["openai", "OpenAI"],
111-
["anthropic", "Anthropic"],
112-
["gemini", "Google Gemini"],
113-
["ollama", "Local Ollama"],
114-
["vllm", "Local vLLM"],
115-
["nim-local", "Local NVIDIA NIM"],
116-
["ncp", "NVIDIA Cloud Partner"],
117-
["custom", "Other OpenAI-compatible endpoint"],
108+
const endpointCases: Array<{ endpointType: EndpointType; expected: string }> = [
109+
{ endpointType: "build", expected: "NVIDIA Endpoints" },
110+
{ endpointType: "openai", expected: "OpenAI" },
111+
{ endpointType: "anthropic", expected: "Anthropic" },
112+
{ endpointType: "gemini", expected: "Google Gemini" },
113+
{ endpointType: "ollama", expected: "Local Ollama" },
114+
{ endpointType: "vllm", expected: "Local vLLM" },
115+
{ endpointType: "nim-local", expected: "Local NVIDIA NIM" },
116+
{ endpointType: "ncp", expected: "NVIDIA Cloud Partner" },
117+
{ endpointType: "custom", expected: "Other OpenAI-compatible endpoint" },
118118
];
119119

120-
for (const [endpointType, expected] of endpointCases) {
121-
it(`returns "${expected}" for endpoint type "${endpointType}"`, () => {
120+
it.each(endpointCases)(
121+
'returns "$expected" for endpoint type "$endpointType"',
122+
({ endpointType, expected }) => {
122123
const config = makeConfig({ endpointType, providerLabel: undefined });
123124
expect(describeOnboardProvider(config)).toBe(expected);
124-
});
125-
}
125+
},
126+
);
126127

127128
it("returns Unknown for unsupported endpoint types", () => {
128129
const config = makeConfig({

scripts/growth-guardrails/find-test-loops.mts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
33
// SPDX-License-Identifier: Apache-2.0
44
//
5-
// Finds `for` loops that make test cases or generated test definitions
6-
// iterative. Independent rows should use it.each or test.each so each failure
7-
// identifies one behavior. Required iteration can stay in a named helper
8-
// outside the test callback.
5+
// Finds `for` loops inside test callbacks and loops that generate test
6+
// definitions. Required iteration can stay in a named helper outside the test
7+
// callback. Independent rows should use it.each or test.each so each failure
8+
// identifies one behavior.
99

1010
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
1111
import path from "node:path";
@@ -264,14 +264,14 @@ function formatContext(occurrence: TestLoopOccurrence): string {
264264

265265
export function formatReport(report: TestLoopReport, options: Pick<CliOptions, "top">): string {
266266
const lines = [
267-
`Scanned ${report.summary.scannedFiles} test files; found ${report.summary.loopCount} table-test candidate loop(s) in ${report.summary.filesWithLoops} file(s).`,
267+
`Scanned ${report.summary.scannedFiles} test files; found ${report.summary.loopCount} test loop(s) in ${report.summary.filesWithLoops} file(s).`,
268268
"",
269269
"Top files by loop count:",
270270
];
271271
for (const file of report.files.slice(0, options.top)) {
272272
lines.push(`- ${file.file}: loops=${file.count}`);
273273
}
274-
lines.push("", "Table-test candidate loops:");
274+
lines.push("", "Test loops:");
275275
for (const occurrence of report.occurrences.slice(0, options.top)) {
276276
lines.push(
277277
`- ${occurrence.file}:${occurrence.line}:${occurrence.column} [${formatContext(occurrence)}] ${occurrence.kind}`,

src/lib/actions/sandbox/connect-autopair-budget.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
// so tests can import and assert the invariant on the real values without
77
// pulling in connect.ts's heavy transitive requires (#4504).
88

9-
export const CONNECT_AUTO_PAIR_MAX_APPROVALS = 1;
9+
// Fresh OpenClaw finalization can observe the initial CLI pairing request and
10+
// its immediately following operator.write upgrade in the same pass. Keep the
11+
// budget at those two bounded transitions so neither request is left pending.
12+
export const CONNECT_AUTO_PAIR_MAX_APPROVALS = 2;
1013
// `openclaw devices list` budget (seconds), interpolated into the in-sandbox
1114
// script so the invariant below is asserted on real values, not source text.
1215
// A cold OpenClaw 2026.6.10 CLI can take just over 2s to load its runtime
@@ -30,4 +33,4 @@ export const CONNECT_AUTO_PAIR_POST_TIMEOUT_OBSERVE_S = 4;
3033
// sources the proxy environment and launches Python. Keep 10s beyond the longer
3134
// inner path so the outer timer cannot terminate a legitimate approval before
3235
// its fixed receipt is returned.
33-
export const CONNECT_AUTO_PAIR_TIMEOUT_MS = 25_000;
36+
export const CONNECT_AUTO_PAIR_TIMEOUT_MS = 35_000;

src/lib/actions/sandbox/host-aliases.test.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ function expectHostAliasError(action: () => void): HostAliasesCommandError {
4040
}
4141

4242
describe("host alias legacy gateway support checks", () => {
43-
for (const driver of ["docker", "vm"] as const) {
44-
it(`rejects ${driver} driver sandboxes before probing Docker`, () => {
43+
it.each(["docker", "vm"] as const)(
44+
"rejects %s driver sandboxes before probing Docker",
45+
(driver) => {
4546
const probeLegacyGatewayContainer = vi.fn(() => ({ state: "present" as const }));
4647

4748
const error = expectHostAliasError(() =>
@@ -56,8 +57,8 @@ describe("host alias legacy gateway support checks", () => {
5657
);
5758
expect(error.message).toContain(`which the ${driver} driver does not run`);
5859
expect(probeLegacyGatewayContainer).not.toHaveBeenCalled();
59-
});
60-
}
60+
},
61+
);
6162

6263
it("reports a missing legacy gateway distinctly from Docker probe failures", () => {
6364
const error = expectHostAliasError(() =>

src/lib/messaging/channels/slack/hooks/status-health.test.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@ describe("slack.statusHealth hook", () => {
116116
expect(execute).not.toHaveBeenCalled();
117117
});
118118

119-
for (const [name, account, inputs, expected, signal] of [
119+
it.each([
120120
[
121-
"classifies unavailable Slack credentials as terminal (#7383)",
121+
"unavailable Slack credentials",
122122
{
123123
running: false,
124124
connected: false,
@@ -130,14 +130,15 @@ describe("slack.statusHealth hook", () => {
130130
{ label: "Account probe", severity: "fail" },
131131
],
132132
[
133-
"classifies a Slack plugin probe failure as terminal (#7383)",
133+
"a Slack plugin probe failure",
134134
{ probe: { ok: false, error: "plugin failed to load" } },
135135
{},
136136
["terminal", "plugin", "plugin_probe_failed", false],
137137
{ label: "Account probe", severity: "warn" },
138138
],
139-
] as const) {
140-
it(name, () => {
139+
] as const)(
140+
"classifies %s as terminal (#7383)",
141+
(_condition, account, inputs, expected, signal) => {
141142
const [state, category, reason, retryable] = expected;
142143
const report = runProbe(account, inputs).report;
143144
expect(report.readiness).toMatchObject({
@@ -147,8 +148,8 @@ describe("slack.statusHealth hook", () => {
147148
retryable,
148149
} satisfies Partial<ChannelReadiness>);
149150
expect(report.signals).toContainEqual(expect.objectContaining(signal));
150-
});
151-
}
151+
},
152+
);
152153

153154
it("returns a null transition time for an out-of-range Slack timestamp (#7383)", () => {
154155
expect(

src/lib/onboard/vllm-menu.test.ts

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,26 +36,24 @@ describe("buildVllmMenuEntries", () => {
3636
assert.match(entries[0].label, /running/);
3737
});
3838

39-
for (const [platform, hostLabel] of [
40-
["spark", "Spark"],
41-
["station", "Station"],
42-
] as const) {
43-
it(`does not mark the running entry experimental on DGX ${hostLabel}`, () => {
44-
const entries = buildVllmMenuEntries({
45-
vllmRunning: true,
46-
vllmProfile: null,
47-
experimental: false,
48-
platform,
49-
hasVllmImage: false,
50-
log: () => {},
51-
env: {},
52-
});
53-
assert.equal(entries.length, 1);
54-
assert.equal(entries[0].key, "vllm");
55-
assert.doesNotMatch(entries[0].label, /experimental/);
56-
assert.match(entries[0].label, /running/);
39+
it.each([
40+
{ platform: "spark", hostLabel: "Spark" },
41+
{ platform: "station", hostLabel: "Station" },
42+
] as const)("does not mark the running entry experimental on DGX $hostLabel", ({ platform }) => {
43+
const entries = buildVllmMenuEntries({
44+
vllmRunning: true,
45+
vllmProfile: null,
46+
experimental: false,
47+
platform,
48+
hasVllmImage: false,
49+
log: () => {},
50+
env: {},
5751
});
58-
}
52+
assert.equal(entries.length, 1);
53+
assert.equal(entries[0].key, "vllm");
54+
assert.doesNotMatch(entries[0].label, /experimental/);
55+
assert.match(entries[0].label, /running/);
56+
});
5957

6058
it("returns the install entry when a profile matches and EXPERIMENTAL is set", () => {
6159
const entries = buildVllmMenuEntries({

src/lib/openshell-sandbox-list.test.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -76,22 +76,20 @@ describe("sandbox list gateway preflight and recovery (#6237)", () => {
7676
vi.restoreAllMocks();
7777
});
7878

79-
for (const [name, issue] of [
80-
["gateway image drift", imageDriftIssue],
81-
["host-process gateway drift", hostProcessDriftIssue],
82-
] as const) {
83-
it(`exits before querying sandbox state for ${name}`, async () => {
84-
mocks.detectPreflightIssue.mockReturnValueOnce(issue);
85-
86-
await expect(captureSandboxListWithGatewayPreflightOrExit(context)).rejects.toThrow(
87-
"process.exit(1)",
88-
);
89-
90-
expect(mocks.printIssue).toHaveBeenCalledWith(issue, context);
91-
expect(mocks.captureOpenshell).not.toHaveBeenCalled();
92-
expect(mocks.recoverNamedGatewayRuntime).not.toHaveBeenCalled();
93-
});
94-
}
79+
it.each([
80+
{ name: "gateway image drift", issue: imageDriftIssue },
81+
{ name: "host-process gateway drift", issue: hostProcessDriftIssue },
82+
])("exits before querying sandbox state for $name", async ({ issue }) => {
83+
mocks.detectPreflightIssue.mockReturnValueOnce(issue);
84+
85+
await expect(captureSandboxListWithGatewayPreflightOrExit(context)).rejects.toThrow(
86+
"process.exit(1)",
87+
);
88+
89+
expect(mocks.printIssue).toHaveBeenCalledWith(issue, context);
90+
expect(mocks.captureOpenshell).not.toHaveBeenCalled();
91+
expect(mocks.recoverNamedGatewayRuntime).not.toHaveBeenCalled();
92+
});
9593

9694
it("returns the successful sandbox list without gateway recovery", async () => {
9795
const result = await captureSandboxListWithGatewayPreflightOrExit(context);

src/lib/policy/host-redaction.test.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,9 @@ describe("isInternalHost", () => {
8888
"w.localdomain",
8989
];
9090

91-
for (const host of internal) {
92-
it(`treats ${host} as internal`, () => {
93-
expect(isInternalHost(host)).toBe(true);
94-
});
95-
}
91+
it.each(internal)("treats %s as internal", (host) => {
92+
expect(isInternalHost(host)).toBe(true);
93+
});
9694

9795
const external = [
9896
"api.slack.com",
@@ -107,11 +105,9 @@ describe("isInternalHost", () => {
107105
"fec0::1",
108106
"2001:db8::1",
109107
];
110-
for (const host of external) {
111-
it(`treats ${host} as external`, () => {
112-
expect(isInternalHost(host)).toBe(false);
113-
});
114-
}
108+
it.each(external)("treats %s as external", (host) => {
109+
expect(isInternalHost(host)).toBe(false);
110+
});
115111
});
116112

117113
describe("hostStemsFromEndpoints", () => {

src/lib/sandbox/hermes-upstream-header.parity.test.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,11 @@ const FIXTURES: Array<{ name: string; config: Record<string, unknown> }> = [
5050
];
5151

5252
describe("buildHermesUpstreamHeader parity", () => {
53-
for (const fixture of FIXTURES) {
54-
it(`agent and host helpers produce identical output for: ${fixture.name}`, () => {
55-
const agent = buildAgentHeader(fixture.config);
56-
const host = buildHostHeader(fixture.config);
57-
expect(host).toBe(agent);
58-
});
59-
}
53+
it.each(FIXTURES)("agent and host helpers produce identical output for: $name", ({ config }) => {
54+
const agent = buildAgentHeader(config);
55+
const host = buildHostHeader(config);
56+
expect(host).toBe(agent);
57+
});
6058

6159
it("strips newlines and control characters so the comment cannot escape into YAML", () => {
6260
const malicious = {

0 commit comments

Comments
 (0)