Files
pikasTech-HWLAB/internal/cloud/user-billing-client.test.ts
2026-06-20 08:37:56 +08:00

82 lines
3.4 KiB
TypeScript

import assert from "node:assert/strict";
import { test } from "bun:test";
import { createUserBillingClient } from "./user-billing-client.ts";
test("user-billing login retries transient dependency failures only", async () => {
const calls = [];
const client = createUserBillingClient({
env: {
HWLAB_USER_BILLING_URL: "http://user-billing.test",
HWLAB_USER_BILLING_LOGIN_RETRY_ATTEMPTS: "2",
HWLAB_USER_BILLING_LOGIN_RETRY_DELAY_MS: "1"
},
fetchImpl: async (url, init) => {
calls.push({ url: String(url), method: init?.method });
if (calls.length === 1) throw new Error("The operation timed out.");
return new Response(JSON.stringify({ token: "hws_retry_ok", tokenType: "Bearer" }), { status: 200, headers: { "content-type": "application/json" } });
}
});
const result = await client.login({ username: "admin", password: "redacted" });
assert.equal(result.ok, true);
assert.equal(result.retryCount, 1);
assert.equal(result.transientObserved, true);
assert.equal(calls.length, 2);
const authFailures = [];
const invalidClient = createUserBillingClient({
env: {
HWLAB_USER_BILLING_URL: "http://user-billing.test",
HWLAB_USER_BILLING_LOGIN_RETRY_ATTEMPTS: "2",
HWLAB_USER_BILLING_LOGIN_RETRY_DELAY_MS: "1"
},
fetchImpl: async (url, init) => {
authFailures.push({ url: String(url), method: init?.method });
return new Response(JSON.stringify({ error: { code: "invalid_credentials", message: "invalid email, username or password" } }), { status: 401, headers: { "content-type": "application/json" } });
}
});
const invalid = await invalidClient.login({ username: "admin", password: "wrong" });
assert.equal(invalid.ok, false);
assert.equal(invalid.status, 401);
assert.equal(invalid.error.code, "invalid_credentials");
assert.equal(authFailures.length, 1);
const unexpectedCalls = [];
const unconfiguredClient = createUserBillingClient({
env: {
HWLAB_USER_BILLING_LOGIN_RETRY_ATTEMPTS: "2",
HWLAB_USER_BILLING_LOGIN_RETRY_DELAY_MS: "1"
},
fetchImpl: async (url, init) => {
unexpectedCalls.push({ url: String(url), method: init?.method });
throw new Error("fetch should not run without a user-billing URL");
}
});
const unconfigured = await unconfiguredClient.login({ username: "admin", password: "redacted" });
assert.equal(unconfigured.ok, false);
assert.equal(unconfigured.status, 503);
assert.equal(unconfigured.error.code, "user_billing_not_configured");
assert.equal(unconfigured.retryable, undefined);
assert.equal(unexpectedCalls.length, 0);
});
test("user-billing login propagates traceparent to dependency requests", async () => {
const traceparent = "00-11111111111111111111111111111111-2222222222222222-01";
const calls = [];
const client = createUserBillingClient({
env: { HWLAB_USER_BILLING_URL: "http://user-billing.test" },
fetchImpl: async (url, init) => {
calls.push({ url: String(url), traceparent: init?.headers?.traceparent });
return new Response(JSON.stringify({ token: "hws_trace_ok", tokenType: "Bearer" }), { status: 200, headers: { "content-type": "application/json" } });
}
});
const result = await client.login({ username: "admin", password: "redacted" }, { traceparent });
assert.equal(result.ok, true);
assert.equal(calls.length, 1);
assert.equal(calls[0].traceparent, traceparent);
});