



























@@ -17,6 +17,29 @@ function createTokenProviderFactory(tokenProvider: () => Promise<string>) {
1717return vi.fn(() => tokenProvider);
1818}
191920+type MockWithCalls = {
21+mock: { calls: unknown[][] };
22+};
23+24+function objectArgAt(
25+mock: MockWithCalls,
26+callIndex: number,
27+argIndex: number,
28+): Record<string, unknown> {
29+const value = mock.mock.calls[callIndex]?.[argIndex];
30+if (value === undefined || value === null || typeof value !== "object" || Array.isArray(value)) {
31+throw new Error(`expected call ${callIndex} argument ${argIndex} to be an object`);
32+}
33+return value as Record<string, unknown>;
34+}
35+36+function recordField(value: unknown, field: string): Record<string, unknown> {
37+if (value === undefined || value === null || typeof value !== "object" || Array.isArray(value)) {
38+throw new Error(`expected ${field} to be an object`);
39+}
40+return value as Record<string, unknown>;
41+}
42+2043describe("bedrock mantle discovery", () => {
2144const originalEnv = process.env;
2245@@ -212,29 +235,19 @@ describe("bedrock mantle discovery", () => {
212235213236expect(models).toHaveLength(3);
214237// Models should be sorted alphabetically by id
215-expect(models[0]).toMatchObject({
216-id: "anthropic.claude-sonnet-4-6",
217-name: "anthropic.claude-sonnet-4-6",
218-reasoning: false,
219-input: ["text"],
220-});
221-expect(models[1]).toMatchObject({
222-id: "mistral.devstral-2-123b",
223-reasoning: false,
224-});
225-expect(models[2]).toMatchObject({
226-id: "openai.gpt-oss-120b",
227-reasoning: true, // GPT-OSS 120B supports reasoning
228-});
238+expect(models[0]?.id).toBe("anthropic.claude-sonnet-4-6");
239+expect(models[0]?.name).toBe("anthropic.claude-sonnet-4-6");
240+expect(models[0]?.reasoning).toBe(false);
241+expect(models[0]?.input).toEqual(["text"]);
242+expect(models[1]?.id).toBe("mistral.devstral-2-123b");
243+expect(models[1]?.reasoning).toBe(false);
244+expect(models[2]?.id).toBe("openai.gpt-oss-120b");
245+expect(models[2]?.reasoning).toBe(true); // GPT-OSS 120B supports reasoning
229246230247// Verify correct endpoint and auth header
231-expect(mockFetch).toHaveBeenCalledWith(
232-"https://bedrock-mantle.us-east-1.api.aws/v1/models",
233-expect.objectContaining({
234-headers: expect.objectContaining({
235-Authorization: "Bearer test-token",
236-}),
237-}),
248+expect(mockFetch.mock.calls[0]?.[0]).toBe("https://bedrock-mantle.us-east-1.api.aws/v1/models");
249+expect(recordField(objectArgAt(mockFetch, 0, 1).headers, "headers").Authorization).toBe(
250+"Bearer test-token",
238251);
239252});
240253@@ -414,22 +427,15 @@ describe("bedrock mantle discovery", () => {
414427fetchFn: mockFetch as unknown as typeof fetch,
415428});
416429417-expect(provider).toMatchObject({
418-baseUrl: "https://bedrock-mantle.us-east-1.api.aws/v1",
419-api: "openai-completions",
420-auth: "api-key",
421-apiKey: "env:AWS_BEARER_TOKEN_BEDROCK",
422-});
430+expect(provider?.baseUrl).toBe("https://bedrock-mantle.us-east-1.api.aws/v1");
431+expect(provider?.api).toBe("openai-completions");
432+expect(provider?.auth).toBe("api-key");
433+expect(provider?.apiKey).toBe("env:AWS_BEARER_TOKEN_BEDROCK");
423434expect(provider?.models).toHaveLength(2);
424-expect(
425-provider?.models?.find((model) => model.id === "anthropic.claude-opus-4-7"),
426-).toMatchObject({
427-api: "anthropic-messages",
428-reasoning: false,
429-});
430-expect(
431-provider?.models?.find((model) => model.id === "anthropic.claude-opus-4-7"),
432-).not.toHaveProperty("baseUrl");
435+const opus = provider?.models?.find((model) => model.id === "anthropic.claude-opus-4-7");
436+expect(opus?.api).toBe("anthropic-messages");
437+expect(opus?.reasoning).toBe(false);
438+expect(opus).not.toHaveProperty("baseUrl");
433439});
434440435441it("returns null when no auth is available", async () => {
@@ -464,15 +470,11 @@ describe("bedrock mantle discovery", () => {
464470 tokenProviderFactory,
465471});
466472467-expect(provider).toMatchObject({ apiKey: MANTLE_IAM_TOKEN_MARKER });
473+expect(provider?.apiKey).toBe(MANTLE_IAM_TOKEN_MARKER);
468474expect(tokenProvider).toHaveBeenCalledTimes(1);
469-expect(mockFetch).toHaveBeenCalledWith(
470-"https://bedrock-mantle.us-east-1.api.aws/v1/models",
471-expect.objectContaining({
472-headers: expect.objectContaining({
473-Authorization: "Bearer bedrock-api-key-iam",
474-}),
475-}),
475+expect(mockFetch.mock.calls[0]?.[0]).toBe("https://bedrock-mantle.us-east-1.api.aws/v1/models");
476+expect(recordField(objectArgAt(mockFetch, 0, 1).headers, "headers").Authorization).toBe(
477+"Bearer bedrock-api-key-iam",
476478);
477479});
478480@@ -486,39 +488,33 @@ describe("bedrock mantle discovery", () => {
486488 tokenProviderFactory,
487489});
488490489-await expect(
490-resolveMantleRuntimeBearerToken({
491-apiKey: MANTLE_IAM_TOKEN_MARKER,
492-env: {
493-AWS_REGION: "us-east-1",
494-} as NodeJS.ProcessEnv,
495-now: () => 2000,
496- tokenProviderFactory,
497-}),
498-).resolves.toMatchObject({
499-apiKey: "bedrock-api-key-runtime",
500-expiresAt: 1000 + 7200_000,
491+const resolved = await resolveMantleRuntimeBearerToken({
492+apiKey: MANTLE_IAM_TOKEN_MARKER,
493+env: {
494+AWS_REGION: "us-east-1",
495+} as NodeJS.ProcessEnv,
496+now: () => 2000,
497+ tokenProviderFactory,
501498});
499+expect(resolved?.apiKey).toBe("bedrock-api-key-runtime");
500+expect(resolved?.expiresAt).toBe(1000 + 7200_000);
502501expect(tokenProvider).toHaveBeenCalledTimes(1);
503502});
504503505504it("generates a fresh Mantle runtime IAM token when the cache is cold", async () => {
506505const tokenProvider = vi.fn(async () => "bedrock-api-key-fresh"); // pragma: allowlist secret
507506const tokenProviderFactory = createTokenProviderFactory(tokenProvider);
508507509-await expect(
510-resolveMantleRuntimeBearerToken({
511-apiKey: MANTLE_IAM_TOKEN_MARKER,
512-env: {
513-AWS_REGION: "us-east-1",
514-} as NodeJS.ProcessEnv,
515-now: () => 5000,
516- tokenProviderFactory,
517-}),
518-).resolves.toMatchObject({
519-apiKey: "bedrock-api-key-fresh",
520-expiresAt: 5000 + 7200_000,
508+const resolved = await resolveMantleRuntimeBearerToken({
509+apiKey: MANTLE_IAM_TOKEN_MARKER,
510+env: {
511+AWS_REGION: "us-east-1",
512+} as NodeJS.ProcessEnv,
513+now: () => 5000,
514+ tokenProviderFactory,
521515});
516+expect(resolved?.apiKey).toBe("bedrock-api-key-fresh");
517+expect(resolved?.expiresAt).toBe(5000 + 7200_000);
522518expect(tokenProvider).toHaveBeenCalledTimes(1);
523519});
524520@@ -547,10 +543,8 @@ describe("bedrock mantle discovery", () => {
547543});
548544549545expect(provider?.baseUrl).toBe("https://bedrock-mantle.us-east-1.api.aws/v1");
550-expect(mockFetch).toHaveBeenCalledWith(
551-"https://bedrock-mantle.us-east-1.api.aws/v1/models",
552-expect.anything(),
553-);
546+expect(mockFetch.mock.calls[0]?.[0]).toBe("https://bedrock-mantle.us-east-1.api.aws/v1/models");
547+expect(mockFetch.mock.calls[0]?.[1]).toBeDefined();
554548});
555549556550// ---------------------------------------------------------------------------
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。