import { readFileSync } from "node:fs";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";
import { createUsageState, runUsageFeed, type UsageCredential, type UsageResponse } from "../src/index.js";
import {
ALIBABA_CLI_TIMEOUT_MS,
ALIBABA_QUOTA_CONFIG_API,
ALIBABA_RESET_CARD_API,
ALIBABA_SUBSCRIPTION_API,
ALIBABA_USAGE_API,
alibabaCliArguments,
alibabaUsageFeed,
parseAlibabaQuotaConfig,
parseAlibabaUsage,
} from "../src/utils/usage/providers/alibaba.js";
const fixtures = resolve(
dirname(fileURLToPath(import.meta.url)),
"..",
"..",
"..",
"native",
"usage",
"tests",
"fixtures",
);
const fixture = (name: string): string => readFileSync(join(fixtures, name), "utf8");
const cliCredential: UsageCredential = { kind: "cli", config: { region: "intl-personal" }, email: "user@example.com" };
const sessionCredential: UsageCredential = {
kind: "session",
session: {
url: "https://bailian-singapore-cs.alibabacloud.com/data/api.json",
region: "ap-southeast-1",
secToken: "csrf-token",
headers: { cookie: "login_aliyunid=test" },
},
};
const cliAnswer = (status: number, body: string): UsageResponse[] => [{ status, body }];
/** The four console responses, in the order the feed asks for them. */
const consoleResponses: UsageResponse[] = [
{ status: 200, body: fixture("alibaba-usage.json") },
{ status: 200, body: fixture("alibaba-subscription.json") },
{ status: 200, body: fixture("alibaba-quota-config.json") },
{ status: 200, body: fixture("alibaba-reset-card_list.json") },
];
describe("alibaba feed: the bailian CLI first", () => {
it("asks the host for the official CLI, not for HTTP", () => {
const step = alibabaUsageFeed.advance(createUsageState(cliCredential, 0), []);
if (!("requests" in step)) throw new Error("expected requests");
expect(step.requests).toHaveLength(1);
const request = step.requests[0]!;
expect(request.kind).toBe("command");
if (request.kind !== "command") throw new Error("expected a command request");
expect(request.command).toBe("bl");
expect(request.args).toEqual(alibabaCliArguments("intl-personal"));
expect(request.args).toContain("ap-southeast-1");
expect(request.args).toContain("international");
expect(request.timeoutMs).toBe(ALIBABA_CLI_TIMEOUT_MS);
});
it("honours the region from the credential", () => {
expect(alibabaCliArguments("cn-personal")).toEqual([
"usage",
"token-plan",
"--console-region",
"cn-beijing",
"--console-site",
"domestic",
"--output",
"json",
]);
const step = alibabaUsageFeed.advance(
createUsageState({ kind: "cli", config: { region: "cn-personal" } }, 0),
[],
);
if (!("requests" in step) || step.requests[0]?.kind !== "command") throw new Error("expected a command request");
expect(step.requests[0].args).toContain("domestic");
});
it("reads the CLI's own output: a FRACTION to percent, epoch milliseconds kept as-is", () => {
const step = alibabaUsageFeed.advance(
createUsageState(cliCredential, 1_700_000_000_000),
cliAnswer(
0,
JSON.stringify({
per5HourPercentage: 0.5,
per1WeekPercentage: 0.83603712139856,
per1WeekResetTime: 1_790_021_160_000,
}),
),
);
if (!("report" in step)) throw new Error("expected a report");
expect(step.report.limits).toHaveLength(2);
expect(step.report.limits[0]).toMatchObject({
label: "Session",
usedPercent: 50,
windowLabel: "5h window",
status: "ok",
});
const weekly = step.report.limits[1]!;
expect(weekly.label).toBe("Weekly");
expect(weekly.usedPercent).toBeCloseTo(83.6037, 3);
expect(weekly.windowLabel).toBe("7d window");
// epoch MILLISECONDS already — nothing to convert, which is why the comment in the parser says so
expect(weekly.resetsAt).toBe(1_790_021_160_000);
expect(step.report.notes?.[0]).toContain("bailian CLI");
});
it("parses the console envelope with the same rule", () => {
const wrapped = parseAlibabaUsage(JSON.parse(fixture("alibaba-usage.json")));
expect(wrapped.limits[0]).toMatchObject({ label: "Weekly", windowLabel: "7d window" });
expect(wrapped.limits[0]!.usedPercent).toBeCloseTo(83.6037, 3);
});
it("reports a failing CLI when there is no session to fall back to", () => {
const step = alibabaUsageFeed.advance(createUsageState(cliCredential, 0), cliAnswer(1, "not signed in"));
if (!("report" in step)) throw new Error("expected a report");
expect(step.report.error).toContain("bailian CLI failed");
expect(step.report.notes?.[0]).toContain("session");
});
it("quotes a JSON error body's message and hint, not its braces", () => {
const step = alibabaUsageFeed.advance(
createUsageState(cliCredential, 0),
cliAnswer(
3,
JSON.stringify({
error: { code: 3, message: "No console access token found.", hint: "Run `bl auth login --console`." },
}),
),
);
if (!("report" in step)) throw new Error("expected a report");
expect(step.report.error).toContain("bailian CLI failed (exit 3)");
expect(step.report.error).toContain("No console access token found. Run `bl auth login --console`.");
});
it("does not quote a JSON body that carries no message", () => {
const step = alibabaUsageFeed.advance(createUsageState(cliCredential, 0), cliAnswer(3, '{"trace":"abc"}'));
if (!("report" in step)) throw new Error("expected a report");
expect(step.report.error).toBe("bailian CLI failed (exit 3)");
});
});
describe("alibaba feed: the console session fallback", () => {
it("falls back to the console when the host runs no commands", () => {
const step = alibabaUsageFeed.advance(createUsageState(sessionCredential, 0), cliAnswer(127, "no commands here"));
if (!("requests" in step)) throw new Error("expected the console requests");
const urls = step.requests.map((request) =>
request.kind === "http" ? new URL(request.url).searchParams.get("api") : request.command,
);
expect(urls).toEqual([
ALIBABA_USAGE_API,
ALIBABA_SUBSCRIPTION_API,
ALIBABA_QUOTA_CONFIG_API,
ALIBABA_RESET_CARD_API,
]);
for (const request of step.requests) {
if (request.kind !== "http") throw new Error("console calls are HTTP");
expect(request.method).toBe("POST");
expect(request.headers?.cookie).toBe("login_aliyunid=test");
expect(request.body).toContain("sec_token=csrf-token");
expect(request.body).toContain("region=ap-southeast-1");
}
});
it("falls back to the console when the CLI fails", () => {
const step = alibabaUsageFeed.advance(createUsageState(sessionCredential, 0), cliAnswer(1, "boom"));
expect("requests" in step && step.requests).toHaveLength(4);
});
it("omits an absent security token instead of failing on it", () => {
const withoutToken: UsageCredential = {
kind: "session",
session: {
url: "https://bailian-singapore-cs.alibabacloud.com/data/api.json",
region: "ap-southeast-1",
headers: {},
},
};
const step = alibabaUsageFeed.advance(createUsageState(withoutToken, 0), cliAnswer(127, ""));
if (!("requests" in step)) throw new Error("expected requests");
const first = step.requests[0]!;
if (first.kind !== "http") throw new Error("expected http");
expect(first.body).not.toContain("sec_token");
expect(first.body).toContain(`params=`);
});
it("says how to get a session when there is neither a CLI nor one captured", () => {
const step = alibabaUsageFeed.advance(createUsageState({ kind: "cli" }, 0), cliAnswer(127, ""));
if (!("report" in step)) throw new Error("expected a report");
expect(step.report.error).toContain("capture-alibaba-session.mjs");
});
it("reports the console answers: plan, remaining days, tier credits and reset cards", () => {
const step = alibabaUsageFeed.advance(createUsageState(sessionCredential, 0), consoleResponses);
if (!("report" in step)) throw new Error("expected a report");
expect(step.report.planType).toBe("pro");
expect(step.report.limits[0]!.windowLabel).toBe("7d window");
const notes = step.report.notes ?? [];
expect(notes.some((note) => note.includes("days remaining"))).toBe(true);
expect(notes.some((note) => note.includes("Token plan pro"))).toBe(true);
});
it("names the tier allowance from quota-config", () => {
const notes = parseAlibabaQuotaConfig(JSON.parse(fixture("alibaba-quota-config.json")), "pro");
expect(notes).toEqual(["Token plan pro: weekly 40000, 5h 12000 credits"]);
expect(parseAlibabaQuotaConfig({}, "pro")).toEqual([]);
});
});
describe("alibaba through the host loop", () => {
it("drives the CLI path with a host that runs commands", async () => {
const seen: string[] = [];
const report = await runUsageFeed(alibabaUsageFeed, cliCredential, {
nowMs: 1_700_000_000_000,
runCommand: async (request) => {
seen.push(`${request.command} ${request.args.join(" ")}`);
return {
status: 0,
body: JSON.stringify({ per1WeekPercentage: 0.25, per1WeekResetTime: 1_790_021_160_000 }),
};
},
});
expect(seen[0]).toContain("bl usage token-plan --console-region ap-southeast-1");
expect(report.limits[0]).toMatchObject({ label: "Weekly", usedPercent: 25 });
});
it("falls back through the loop when the host has no commands", async () => {
const urls: string[] = [];
const report = await runUsageFeed(alibabaUsageFeed, sessionCredential, {
fetchImpl: async (input) => {
urls.push(String(input));
const api = new URL(String(input)).searchParams.get("api");
const body =
api === ALIBABA_USAGE_API
? fixture("alibaba-usage.json")
: api === ALIBABA_SUBSCRIPTION_API
? fixture("alibaba-subscription.json")
: api === ALIBABA_QUOTA_CONFIG_API
? fixture("alibaba-quota-config.json")
: fixture("alibaba-reset-card_list.json");
return new Response(body, { status: 200 });
},
});
expect(urls).toHaveLength(4);
expect(report.planType).toBe("pro");
expect(report.error).toBeNull();
});
});