test(core): trim redundant setup and tighten waits

This commit is contained in:
Peter Steinberger
2026-02-24 00:31:36 +00:00
parent f58c1ef34e
commit 663f784e4e
6 changed files with 76 additions and 73 deletions

View File

@@ -123,7 +123,7 @@ describe("daemon-cli coverage", () => {
expect(callGateway).toHaveBeenCalledWith(expect.objectContaining({ method: "status" }));
expect(findExtraGatewayServices).toHaveBeenCalled();
expect(inspectPortUsage).toHaveBeenCalled();
}, 20_000);
});
it("derives probe URL from service args + env (json)", async () => {
resetRuntimeCapture();
@@ -162,7 +162,7 @@ describe("daemon-cli coverage", () => {
expect(parsed.config?.mismatch).toBe(true);
expect(parsed.rpc?.url).toBe("ws://127.0.0.1:19001");
expect(parsed.rpc?.ok).toBe(true);
}, 20_000);
});
it("passes deep scan flag for daemon status", async () => {
findExtraGatewayServices.mockClear();

View File

@@ -143,9 +143,8 @@ describe("gateway-cli coverage", () => {
expect(discoverGatewayBeacons).toHaveBeenCalledTimes(1);
const out = runtimeLogs.join("\n");
for (const text of ['"beacons"', '"wsUrl"', "ws://"]) {
expect(out).toContain(text);
}
expect(out).toContain('"beacons"');
expect(out).toContain("ws://");
});
it("validates gateway discover timeout", async () => {

View File

@@ -30,7 +30,7 @@ describe("doctor command", () => {
const stateNote = note.mock.calls.find((call) => call[1] === "State integrity");
expect(stateNote).toBeTruthy();
expect(String(stateNote?.[0])).toContain("CRITICAL");
}, 30_000);
});
it("warns about opencode provider overrides", async () => {
mockDoctorConfigSnapshot({

View File

@@ -66,7 +66,7 @@ async function removeDirWithRetry(dir: string): Promise<void> {
if (!isTransient || attempt === 4) {
throw error;
}
await delay(25 * (attempt + 1));
await delay(10 * (attempt + 1));
}
}
}
@@ -189,7 +189,7 @@ describe("onboard (non-interactive): provider auth", () => {
key: "sk-minimax-test",
});
});
}, 60_000);
});
it("supports MiniMax CN API endpoint auth choice", async () => {
await withOnboardEnv("openclaw-onboard-minimax-cn-", async (env) => {
@@ -208,7 +208,7 @@ describe("onboard (non-interactive): provider auth", () => {
key: "sk-minimax-test",
});
});
}, 60_000);
});
it("stores Z.AI API key and uses global baseUrl by default", async () => {
await withOnboardEnv("openclaw-onboard-zai-", async (env) => {
@@ -223,7 +223,7 @@ describe("onboard (non-interactive): provider auth", () => {
expect(cfg.agents?.defaults?.model?.primary).toBe("zai/glm-5");
await expectApiKeyProfile({ profileId: "zai:default", provider: "zai", key: "zai-test-key" });
});
}, 60_000);
});
it("supports Z.AI CN coding endpoint auth choice", async () => {
await withOnboardEnv("openclaw-onboard-zai-cn-", async (env) => {
@@ -236,7 +236,7 @@ describe("onboard (non-interactive): provider auth", () => {
"https://open.bigmodel.cn/api/coding/paas/v4",
);
});
}, 60_000);
});
it("stores xAI API key and sets default model", async () => {
await withOnboardEnv("openclaw-onboard-xai-", async (env) => {
@@ -251,7 +251,7 @@ describe("onboard (non-interactive): provider auth", () => {
expect(cfg.agents?.defaults?.model?.primary).toBe("xai/grok-4");
await expectApiKeyProfile({ profileId: "xai:default", provider: "xai", key: "xai-test-key" });
});
}, 60_000);
});
it("infers Mistral auth choice from --mistral-api-key and sets default model", async () => {
await withOnboardEnv("openclaw-onboard-mistral-infer-", async (env) => {
@@ -268,7 +268,7 @@ describe("onboard (non-interactive): provider auth", () => {
key: "mistral-test-key",
});
});
}, 60_000);
});
it("stores Volcano Engine API key and sets default model", async () => {
await withOnboardEnv("openclaw-onboard-volcengine-", async (env) => {
@@ -279,7 +279,7 @@ describe("onboard (non-interactive): provider auth", () => {
expect(cfg.agents?.defaults?.model?.primary).toBe("volcengine-plan/ark-code-latest");
});
}, 60_000);
});
it("infers BytePlus auth choice from --byteplus-api-key and sets default model", async () => {
await withOnboardEnv("openclaw-onboard-byteplus-infer-", async (env) => {
@@ -289,7 +289,7 @@ describe("onboard (non-interactive): provider auth", () => {
expect(cfg.agents?.defaults?.model?.primary).toBe("byteplus-plan/ark-code-latest");
});
}, 60_000);
});
it("stores Vercel AI Gateway API key and sets default model", async () => {
await withOnboardEnv("openclaw-onboard-ai-gateway-", async (env) => {
@@ -309,7 +309,7 @@ describe("onboard (non-interactive): provider auth", () => {
key: "gateway-test-key",
});
});
}, 60_000);
});
it("stores token auth profile", async () => {
await withOnboardEnv("openclaw-onboard-token-", async ({ configPath, runtime }) => {
@@ -336,7 +336,7 @@ describe("onboard (non-interactive): provider auth", () => {
expect(profile.token).toBe(cleanToken);
}
});
}, 60_000);
});
it("stores OpenAI API key and sets OpenAI default model", async () => {
await withOnboardEnv("openclaw-onboard-openai-", async (env) => {
@@ -347,7 +347,7 @@ describe("onboard (non-interactive): provider auth", () => {
expect(cfg.agents?.defaults?.model?.primary).toBe(OPENAI_DEFAULT_MODEL);
});
}, 60_000);
});
it("rejects vLLM auth choice in non-interactive mode", async () => {
await withOnboardEnv("openclaw-onboard-vllm-non-interactive-", async ({ runtime }) => {
@@ -358,7 +358,7 @@ describe("onboard (non-interactive): provider auth", () => {
}),
).rejects.toThrow('Auth choice "vllm" requires interactive mode.');
});
}, 60_000);
});
it("stores LiteLLM API key and sets default model", async () => {
await withOnboardEnv("openclaw-onboard-litellm-", async (env) => {
@@ -376,7 +376,7 @@ describe("onboard (non-interactive): provider auth", () => {
key: "litellm-test-key",
});
});
}, 60_000);
});
it.each([
{
@@ -391,37 +391,31 @@ describe("onboard (non-interactive): provider auth", () => {
prefix: "openclaw-onboard-cf-gateway-infer-",
options: {},
},
])(
"$name",
async ({ prefix, options }) => {
await withOnboardEnv(prefix, async ({ configPath, runtime }) => {
await runNonInteractiveOnboardingWithDefaults(runtime, {
cloudflareAiGatewayAccountId: "cf-account-id",
cloudflareAiGatewayGatewayId: "cf-gateway-id",
cloudflareAiGatewayApiKey: "cf-gateway-test-key",
skipSkills: true,
...options,
});
const cfg = await readJsonFile<ProviderAuthConfigSnapshot>(configPath);
expect(cfg.auth?.profiles?.["cloudflare-ai-gateway:default"]?.provider).toBe(
"cloudflare-ai-gateway",
);
expect(cfg.auth?.profiles?.["cloudflare-ai-gateway:default"]?.mode).toBe("api_key");
expect(cfg.agents?.defaults?.model?.primary).toBe(
"cloudflare-ai-gateway/claude-sonnet-4-5",
);
await expectApiKeyProfile({
profileId: "cloudflare-ai-gateway:default",
provider: "cloudflare-ai-gateway",
key: "cf-gateway-test-key",
metadata: { accountId: "cf-account-id", gatewayId: "cf-gateway-id" },
});
])("$name", async ({ prefix, options }) => {
await withOnboardEnv(prefix, async ({ configPath, runtime }) => {
await runNonInteractiveOnboardingWithDefaults(runtime, {
cloudflareAiGatewayAccountId: "cf-account-id",
cloudflareAiGatewayGatewayId: "cf-gateway-id",
cloudflareAiGatewayApiKey: "cf-gateway-test-key",
skipSkills: true,
...options,
});
},
60_000,
);
const cfg = await readJsonFile<ProviderAuthConfigSnapshot>(configPath);
expect(cfg.auth?.profiles?.["cloudflare-ai-gateway:default"]?.provider).toBe(
"cloudflare-ai-gateway",
);
expect(cfg.auth?.profiles?.["cloudflare-ai-gateway:default"]?.mode).toBe("api_key");
expect(cfg.agents?.defaults?.model?.primary).toBe("cloudflare-ai-gateway/claude-sonnet-4-5");
await expectApiKeyProfile({
profileId: "cloudflare-ai-gateway:default",
provider: "cloudflare-ai-gateway",
key: "cf-gateway-test-key",
metadata: { accountId: "cf-account-id", gatewayId: "cf-gateway-id" },
});
});
});
it("infers Together auth choice from --together-api-key and sets default model", async () => {
await withOnboardEnv("openclaw-onboard-together-infer-", async (env) => {
@@ -438,7 +432,7 @@ describe("onboard (non-interactive): provider auth", () => {
key: "together-test-key",
});
});
}, 60_000);
});
it("infers QIANFAN auth choice from --qianfan-api-key and sets default model", async () => {
await withOnboardEnv("openclaw-onboard-qianfan-infer-", async (env) => {
@@ -455,7 +449,7 @@ describe("onboard (non-interactive): provider auth", () => {
key: "qianfan-test-key",
});
});
}, 60_000);
});
it("configures a custom provider from non-interactive flags", async () => {
await withOnboardEnv("openclaw-onboard-custom-provider-", async ({ configPath, runtime }) => {
@@ -477,7 +471,7 @@ describe("onboard (non-interactive): provider auth", () => {
expect(provider?.models?.some((model) => model.id === "foo-large")).toBe(true);
expect(cfg.agents?.defaults?.model?.primary).toBe("custom-llm-example-com/foo-large");
});
}, 60_000);
});
it("infers custom provider auth choice from custom flags", async () => {
await withOnboardEnv(
@@ -501,7 +495,7 @@ describe("onboard (non-interactive): provider auth", () => {
expect(cfg.agents?.defaults?.model?.primary).toBe("custom-models-custom-local/local-large");
},
);
}, 60_000);
});
it("uses CUSTOM_API_KEY env fallback for non-interactive custom provider auth", async () => {
await withOnboardEnv(
@@ -512,7 +506,7 @@ describe("onboard (non-interactive): provider auth", () => {
expect(await readCustomLocalProviderApiKey(configPath)).toBe("custom-env-key");
},
);
}, 60_000);
});
it("uses matching profile fallback for non-interactive custom provider auth", async () => {
await withOnboardEnv(
@@ -530,7 +524,7 @@ describe("onboard (non-interactive): provider auth", () => {
expect(await readCustomLocalProviderApiKey(configPath)).toBe("custom-profile-key");
},
);
}, 60_000);
});
it("fails custom provider auth when compatibility is invalid", async () => {
await withOnboardEnv(
@@ -547,7 +541,7 @@ describe("onboard (non-interactive): provider auth", () => {
).rejects.toThrow('Invalid --custom-compatibility (use "openai" or "anthropic").');
},
);
}, 60_000);
});
it("fails custom provider auth when explicit provider id is invalid", async () => {
await withOnboardEnv("openclaw-onboard-custom-provider-invalid-id-", async ({ runtime }) => {
@@ -563,7 +557,7 @@ describe("onboard (non-interactive): provider auth", () => {
"Invalid custom provider config: Custom provider ID must include letters, numbers, or hyphens.",
);
});
}, 60_000);
});
it("fails inferred custom auth when required flags are incomplete", async () => {
await withOnboardEnv(
@@ -577,5 +571,5 @@ describe("onboard (non-interactive): provider auth", () => {
).rejects.toThrow('Auth choice "custom-api-key" requires a base URL and model ID.');
},
);
}, 60_000);
});
});

View File

@@ -14,7 +14,7 @@ async function waitForPersistedSecret(configPath: string, expectedSecret: string
if (parsed.commands?.ownerDisplaySecret === expectedSecret) {
return;
}
await new Promise((resolve) => setTimeout(resolve, 25));
await new Promise((resolve) => setTimeout(resolve, 5));
}
throw new Error("timed out waiting for ownerDisplaySecret persistence");
}

View File

@@ -103,6 +103,7 @@ function expectNoFinding(res: SecurityAuditReport, checkId: string): void {
describe("security audit", () => {
let fixtureRoot = "";
let caseId = 0;
let channelSecurityStateDir = "";
const makeTmpDir = async (label: string) => {
const dir = path.join(fixtureRoot, `case-${caseId++}-${label}`);
@@ -110,14 +111,23 @@ describe("security audit", () => {
return dir;
};
const withStateDir = async (label: string, fn: (tmp: string) => Promise<void>) => {
const tmp = await makeTmpDir(label);
await fs.mkdir(path.join(tmp, "credentials"), { recursive: true, mode: 0o700 });
await withEnvAsync({ OPENCLAW_STATE_DIR: tmp }, async () => await fn(tmp));
const withChannelSecurityStateDir = async (fn: (tmp: string) => Promise<void>) => {
const credentialsDir = path.join(channelSecurityStateDir, "credentials");
await fs.rm(credentialsDir, { recursive: true, force: true });
await fs.mkdir(credentialsDir, { recursive: true, mode: 0o700 });
await withEnvAsync(
{ OPENCLAW_STATE_DIR: channelSecurityStateDir },
async () => await fn(channelSecurityStateDir),
);
};
beforeAll(async () => {
fixtureRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-security-audit-"));
channelSecurityStateDir = path.join(fixtureRoot, "channel-security");
await fs.mkdir(path.join(channelSecurityStateDir, "credentials"), {
recursive: true,
mode: 0o700,
});
});
afterAll(async () => {
@@ -1367,7 +1377,7 @@ describe("security audit", () => {
});
it("flags Discord native commands without a guild user allowlist", async () => {
await withStateDir("discord", async () => {
await withChannelSecurityStateDir(async () => {
const cfg: OpenClawConfig = {
channels: {
discord: {
@@ -1404,7 +1414,7 @@ describe("security audit", () => {
});
it("does not flag Discord slash commands when dm.allowFrom includes a Discord snowflake id", async () => {
await withStateDir("discord-allowfrom-snowflake", async () => {
await withChannelSecurityStateDir(async () => {
const cfg: OpenClawConfig = {
channels: {
discord: {
@@ -1441,7 +1451,7 @@ describe("security audit", () => {
});
it("warns when Discord allowlists contain name-based entries", async () => {
await withStateDir("discord-name-based-allowlist", async (tmp) => {
await withChannelSecurityStateDir(async (tmp) => {
await fs.writeFile(
path.join(tmp, "credentials", "discord-allowFrom.json"),
JSON.stringify({ version: 1, allowFrom: ["team.owner"] }),
@@ -1491,7 +1501,7 @@ describe("security audit", () => {
});
it("does not warn when Discord allowlists use ID-style entries only", async () => {
await withStateDir("discord-id-only-allowlist", async () => {
await withChannelSecurityStateDir(async () => {
const cfg: OpenClawConfig = {
channels: {
discord: {
@@ -1534,7 +1544,7 @@ describe("security audit", () => {
});
it("flags Discord slash commands when access-group enforcement is disabled and no users allowlist exists", async () => {
await withStateDir("discord-open", async () => {
await withChannelSecurityStateDir(async () => {
const cfg: OpenClawConfig = {
commands: { useAccessGroups: false },
channels: {
@@ -1572,7 +1582,7 @@ describe("security audit", () => {
});
it("flags Slack slash commands without a channel users allowlist", async () => {
await withStateDir("slack", async () => {
await withChannelSecurityStateDir(async () => {
const cfg: OpenClawConfig = {
channels: {
slack: {
@@ -1604,7 +1614,7 @@ describe("security audit", () => {
});
it("flags Slack slash commands when access-group enforcement is disabled", async () => {
await withStateDir("slack-open", async () => {
await withChannelSecurityStateDir(async () => {
const cfg: OpenClawConfig = {
commands: { useAccessGroups: false },
channels: {
@@ -1637,7 +1647,7 @@ describe("security audit", () => {
});
it("flags Telegram group commands without a sender allowlist", async () => {
await withStateDir("telegram", async () => {
await withChannelSecurityStateDir(async () => {
const cfg: OpenClawConfig = {
channels: {
telegram: {
@@ -1668,7 +1678,7 @@ describe("security audit", () => {
});
it("warns when Telegram allowFrom entries are non-numeric (legacy @username configs)", async () => {
await withStateDir("telegram-invalid-allowfrom", async () => {
await withChannelSecurityStateDir(async () => {
const cfg: OpenClawConfig = {
channels: {
telegram: {