From e9b27ed2a682a0352753d88672f74b112b5ab353 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 25 Apr 2026 08:31:36 +0100 Subject: [PATCH] perf: speed up auth choice tests --- scripts/test-projects.test-support.mjs | 4 + src/commands/auth-choice.test.ts | 116 +++++++++++++++---------- src/plugins/provider-auth-choice.ts | 6 +- test/scripts/test-projects.test.ts | 10 +++ 4 files changed, 86 insertions(+), 50 deletions(-) diff --git a/scripts/test-projects.test-support.mjs b/scripts/test-projects.test-support.mjs index e97f01a26af..7ba582b1395 100644 --- a/scripts/test-projects.test-support.mjs +++ b/scripts/test-projects.test-support.mjs @@ -255,6 +255,10 @@ const SOURCE_TEST_TARGETS = new Map([ ["extensions/google-meet/src/oauth.ts", ["extensions/google-meet/src/oauth.test.ts"]], ["src/commands/doctor-memory-search.ts", ["src/commands/doctor-memory-search.test.ts"]], ["src/agents/live-model-turn-probes.ts", ["src/agents/live-model-turn-probes.test.ts"]], + [ + "src/plugins/provider-auth-choice.ts", + ["src/commands/auth-choice.apply.plugin-provider.test.ts", "src/commands/auth-choice.test.ts"], + ], [ "src/memory-host-sdk/host/embedding-defaults.ts", ["src/memory-host-sdk/host/embeddings.test.ts"], diff --git a/src/commands/auth-choice.test.ts b/src/commands/auth-choice.test.ts index ab3450d082d..99cf5f99878 100644 --- a/src/commands/auth-choice.test.ts +++ b/src/commands/auth-choice.test.ts @@ -5,6 +5,7 @@ import { resolveAgentDir } from "../agents/agent-scope.js"; import type { OpenClawConfig } from "../config/config.js"; import { resolveAgentModelPrimaryValue } from "../config/model-input.js"; import type { ModelProviderConfig } from "../config/types.models.js"; +import { __testing as providerAuthChoiceTesting } from "../plugins/provider-auth-choice.js"; import * as providerAuthChoices from "../plugins/provider-auth-choices.js"; import type { ProviderAuthMethod, ProviderAuthResult, ProviderPlugin } from "../plugins/types.js"; import type { WizardPrompter } from "../wizard/prompts.js"; @@ -25,43 +26,10 @@ const ZAI_CODING_CN_BASE_URL = "https://open.bigmodel.cn/api/coding/paas/v4"; const resolvePluginProviders = vi.hoisted(() => vi.fn<() => ProviderPlugin[]>(() => [])); const runProviderModelSelectedHook = vi.hoisted(() => vi.fn(async () => {})); -vi.mock("../plugins/provider-auth-choice.runtime.js", () => { - const normalizeProviderId = (value: string) => value.trim().toLowerCase(); - return { - resolvePluginProviders, - resolveProviderPluginChoice: (params: { providers: ProviderPlugin[]; choice: string }) => { - const choice = params.choice.trim(); - if (!choice) { - return null; - } - if (choice.startsWith("provider-plugin:")) { - const payload = choice.slice("provider-plugin:".length); - const separator = payload.indexOf(":"); - const providerId = separator >= 0 ? payload.slice(0, separator) : payload; - const methodId = separator >= 0 ? payload.slice(separator + 1) : undefined; - const provider = params.providers.find( - (entry) => normalizeProviderId(entry.id) === normalizeProviderId(providerId), - ); - const method = methodId - ? provider?.auth.find((entry) => entry.id === methodId) - : provider?.auth[0]; - return provider && method ? { provider, method } : null; - } - for (const provider of params.providers) { - for (const method of provider.auth) { - if (method.wizard?.choiceId === choice) { - return { provider, method, wizard: method.wizard }; - } - } - if (normalizeProviderId(provider.id) === normalizeProviderId(choice) && provider.auth[0]) { - return { provider, method: provider.auth[0] }; - } - } - return null; - }, - runProviderModelSelectedHook, - }; -}); + +vi.mock("../plugins/provider-install-catalog.js", () => ({ + resolveProviderInstallCatalogEntry: vi.fn(() => undefined), +})); vi.mock("./auth-choice.apply.api-providers.js", () => { const normalizeProviderId = (value: string) => value.trim().toLowerCase(); @@ -208,6 +176,41 @@ function normalizeText(value: unknown): string { return typeof value === "string" ? value.trim() : ""; } +function normalizeProviderId(value: string): string { + return value.trim().toLowerCase(); +} + +function resolveProviderPluginChoice(params: { providers: ProviderPlugin[]; choice: string }) { + const choice = params.choice.trim(); + if (!choice) { + return null; + } + if (choice.startsWith("provider-plugin:")) { + const payload = choice.slice("provider-plugin:".length); + const separator = payload.indexOf(":"); + const providerId = separator >= 0 ? payload.slice(0, separator) : payload; + const methodId = separator >= 0 ? payload.slice(separator + 1) : undefined; + const provider = params.providers.find( + (entry) => normalizeProviderId(entry.id) === normalizeProviderId(providerId), + ); + const method = methodId + ? provider?.auth.find((entry) => entry.id === methodId) + : provider?.auth[0]; + return provider && method ? { provider, method } : null; + } + for (const provider of params.providers) { + for (const method of provider.auth) { + if (method.wizard?.choiceId === choice) { + return { provider, method, wizard: method.wizard }; + } + } + if (normalizeProviderId(provider.id) === normalizeProviderId(choice) && provider.auth[0]) { + return { provider, method: provider.auth[0] }; + } + } + return null; +} + function providerConfigPatch( providerId: string, patch: Record, @@ -618,9 +621,17 @@ describe("applyAuthChoice", () => { authTestRoot = (await setupAuthTestEnv("openclaw-auth-")).stateDir; defaultProviderPlugins = await createDefaultProviderPlugins(); resolvePluginProviders.mockReturnValue(defaultProviderPlugins); + providerAuthChoiceTesting.setDepsForTest({ + loadPluginProviderRuntime: async () => ({ + resolvePluginProviders, + resolveProviderPluginChoice, + runProviderModelSelectedHook, + }), + }); }); afterAll(async () => { + providerAuthChoiceTesting.resetDepsForTest(); if (authTestRoot) { await fs.rm(authTestRoot, { recursive: true, force: true }); } @@ -693,17 +704,26 @@ describe("applyAuthChoice", () => { }); it("fails fast when a removed provider auth choice is passed to the interactive flow", async () => { - await expect( - applyAuthChoice({ - authChoice: "openai-codex-import", - config: {}, - prompter: createPrompter({}), - runtime: createExitThrowingRuntime(), - setDefaultModel: true, - }), - ).rejects.toThrow( - 'Auth choice "openai-codex-import" is no longer supported. Use "openai-codex" instead.', - ); + const spy = vi + .spyOn(providerAuthChoices, "resolveManifestDeprecatedProviderAuthChoice") + .mockReturnValueOnce({ + choiceId: "openai-codex", + } as never); + try { + await expect( + applyAuthChoice({ + authChoice: "openai-codex-import", + config: {}, + prompter: createPrompter({}), + runtime: createExitThrowingRuntime(), + setDefaultModel: true, + }), + ).rejects.toThrow( + 'Auth choice "openai-codex-import" is no longer supported. Use "openai-codex" instead.', + ); + } finally { + spy.mockRestore(); + } }); it("escapes removed provider auth choice guidance for terminal output", async () => { diff --git a/src/plugins/provider-auth-choice.ts b/src/plugins/provider-auth-choice.ts index 1a758603d39..36d554f8eb9 100644 --- a/src/plugins/provider-auth-choice.ts +++ b/src/plugins/provider-auth-choice.ts @@ -6,12 +6,10 @@ import { } from "../agents/agent-scope.js"; import { upsertAuthProfile } from "../agents/auth-profiles.js"; import { resolveDefaultAgentWorkspaceDir } from "../agents/workspace.js"; -import { ensureOnboardingPluginInstalled } from "../commands/onboarding-plugin-install.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import type { RuntimeEnv } from "../runtime.js"; import { sanitizeTerminalText } from "../terminal/safe-text.js"; import type { WizardPrompter } from "../wizard/prompts.js"; -import { clearPluginDiscoveryCache } from "./discovery.js"; import { enablePluginInConfig } from "./enable.js"; import { applyProviderAuthConfigPatch, @@ -290,6 +288,10 @@ export async function applyAuthChoiceLoadedPluginProvider( choice: params.authChoice, }); if (!resolved && installCatalogEntry) { + const [{ ensureOnboardingPluginInstalled }, { clearPluginDiscoveryCache }] = await Promise.all([ + import("../commands/onboarding-plugin-install.js"), + import("./discovery.js"), + ]); const installResult = await ensureOnboardingPluginInstalled({ cfg: nextConfig, entry: { diff --git a/test/scripts/test-projects.test.ts b/test/scripts/test-projects.test.ts index f70d7c4cbc3..d2e8ad04b4b 100644 --- a/test/scripts/test-projects.test.ts +++ b/test/scripts/test-projects.test.ts @@ -339,6 +339,16 @@ describe("scripts/test-projects changed-target routing", () => { }); }); + it("routes provider auth choice edits to focused auth-choice tests", () => { + expect(resolveChangedTestTargetPlan(["src/plugins/provider-auth-choice.ts"])).toEqual({ + mode: "targets", + targets: [ + "src/commands/auth-choice.apply.plugin-provider.test.ts", + "src/commands/auth-choice.test.ts", + ], + }); + }); + it("routes changed utils and shared files to their light scoped lanes", () => { const plans = buildVitestRunPlans(["--changed", "origin/main"], process.cwd(), () => [ "src/shared/string-normalization.ts",