mirror of https://github.com/openclaw/openclaw.git
fix: harden zai and ssh helper coverage
This commit is contained in:
parent
da2f85ae2b
commit
54728c60d5
|
|
@ -25,6 +25,20 @@ describe("fetchZaiUsage", () => {
|
|||
expect(result.windows).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("falls back to a generic API error for blank unsuccessful messages", async () => {
|
||||
const mockFetch = createProviderUsageFetch(async () =>
|
||||
makeResponse(200, {
|
||||
success: false,
|
||||
code: 500,
|
||||
msg: " ",
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await fetchZaiUsage("key", 5000, mockFetch);
|
||||
expect(result.error).toBe("API error");
|
||||
expect(result.windows).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("parses token and monthly windows with reset times", async () => {
|
||||
const tokenReset = "2026-01-08T00:00:00Z";
|
||||
const minuteReset = "2026-01-08T00:30:00Z";
|
||||
|
|
@ -83,4 +97,47 @@ describe("fetchZaiUsage", () => {
|
|||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("clamps invalid percentages and falls back to alternate plan fields", async () => {
|
||||
const mockFetch = createProviderUsageFetch(async () =>
|
||||
makeResponse(200, {
|
||||
success: true,
|
||||
code: 200,
|
||||
data: {
|
||||
plan: "Pro",
|
||||
limits: [
|
||||
{
|
||||
type: "TOKENS_LIMIT",
|
||||
percentage: -5,
|
||||
unit: 99,
|
||||
},
|
||||
{
|
||||
type: "TIME_LIMIT",
|
||||
percentage: 140,
|
||||
},
|
||||
{
|
||||
type: "OTHER_LIMIT",
|
||||
percentage: 50,
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await fetchZaiUsage("key", 5000, mockFetch);
|
||||
|
||||
expect(result.plan).toBe("Pro");
|
||||
expect(result.windows).toEqual([
|
||||
{
|
||||
label: "Tokens (Limit)",
|
||||
usedPercent: 0,
|
||||
resetAt: undefined,
|
||||
},
|
||||
{
|
||||
label: "Monthly",
|
||||
usedPercent: 100,
|
||||
resetAt: undefined,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -46,11 +46,12 @@ export async function fetchZaiUsage(
|
|||
|
||||
const data = (await res.json()) as ZaiUsageResponse;
|
||||
if (!data.success || data.code !== 200) {
|
||||
const errorMessage = typeof data.msg === "string" ? data.msg.trim() : "";
|
||||
return {
|
||||
provider: "zai",
|
||||
displayName: PROVIDER_LABELS.zai,
|
||||
windows: [],
|
||||
error: data.msg || "API error",
|
||||
error: errorMessage || "API error",
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,17 @@ describe("ssh-config", () => {
|
|||
expect(parsed.identityFiles).toEqual(["/tmp/id"]);
|
||||
});
|
||||
|
||||
it("ignores invalid ports and blank lines in ssh -G output", () => {
|
||||
const parsed = parseSshConfigOutput(
|
||||
"user bob\nhostname example.com\nport not-a-number\nidentityfile none\nidentityfile \n",
|
||||
);
|
||||
|
||||
expect(parsed.user).toBe("bob");
|
||||
expect(parsed.host).toBe("example.com");
|
||||
expect(parsed.port).toBeUndefined();
|
||||
expect(parsed.identityFiles).toEqual([]);
|
||||
});
|
||||
|
||||
it("resolves ssh config via ssh -G", async () => {
|
||||
const config = await resolveSshConfig({ user: "me", host: "alias", port: 22 });
|
||||
expect(config?.user).toBe("steipete");
|
||||
|
|
@ -68,6 +79,16 @@ describe("ssh-config", () => {
|
|||
expect(args?.slice(-2)).toEqual(["--", "me@alias"]);
|
||||
});
|
||||
|
||||
it("adds non-default port and trimmed identity arguments", async () => {
|
||||
await resolveSshConfig(
|
||||
{ user: "me", host: "alias", port: 2022 },
|
||||
{ identity: " /tmp/custom_id " },
|
||||
);
|
||||
|
||||
const args = spawnMock.mock.calls.at(-1)?.[1] as string[] | undefined;
|
||||
expect(args).toEqual(["-G", "-p", "2022", "-i", "/tmp/custom_id", "--", "me@alias"]);
|
||||
});
|
||||
|
||||
it("returns null when ssh -G fails", async () => {
|
||||
spawnMock.mockImplementationOnce(
|
||||
(_command: string, _args: readonly string[], _options: SpawnOptions): ChildProcess => {
|
||||
|
|
@ -82,4 +103,18 @@ describe("ssh-config", () => {
|
|||
const config = await resolveSshConfig({ user: "me", host: "bad-host", port: 22 });
|
||||
expect(config).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null when the ssh process emits an error", async () => {
|
||||
spawnMock.mockImplementationOnce(
|
||||
(_command: string, _args: readonly string[], _options: SpawnOptions): ChildProcess => {
|
||||
const { child } = createMockSpawnChild();
|
||||
process.nextTick(() => {
|
||||
child.emit("error", new Error("spawn boom"));
|
||||
});
|
||||
return child as unknown as ChildProcess;
|
||||
},
|
||||
);
|
||||
|
||||
await expect(resolveSshConfig({ user: "me", host: "bad-host", port: 22 })).resolves.toBeNull();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue