test(openai): cover automatic image auth readiness

This commit is contained in:
Peter Steinberger
2026-04-23 22:14:48 +01:00
parent c952379419
commit 2f14461976
2 changed files with 81 additions and 0 deletions

View File

@@ -2,12 +2,14 @@ import { afterEach, describe, expect, it, vi } from "vitest";
import { buildOpenAIImageGenerationProvider } from "./image-generation-provider.js";
const {
isProviderApiKeyConfiguredMock,
resolveApiKeyForProviderMock,
postJsonRequestMock,
postMultipartRequestMock,
assertOkOrThrowHttpErrorMock,
resolveProviderHttpRequestConfigMock,
} = vi.hoisted(() => ({
isProviderApiKeyConfiguredMock: vi.fn(() => false),
resolveApiKeyForProviderMock: vi.fn(
async (_params?: {
provider?: string;
@@ -26,6 +28,10 @@ const {
})),
}));
vi.mock("openclaw/plugin-sdk/provider-auth", () => ({
isProviderApiKeyConfigured: isProviderApiKeyConfiguredMock,
}));
vi.mock("openclaw/plugin-sdk/provider-auth-runtime", () => ({
resolveApiKeyForProvider: resolveApiKeyForProviderMock,
}));
@@ -90,6 +96,8 @@ function mockCodexAuthOnly() {
describe("openai image generation provider", () => {
afterEach(() => {
isProviderApiKeyConfiguredMock.mockReset();
isProviderApiKeyConfiguredMock.mockReturnValue(false);
resolveApiKeyForProviderMock.mockReset();
resolveApiKeyForProviderMock.mockResolvedValue({ apiKey: "openai-key" });
postJsonRequestMock.mockReset();
@@ -109,6 +117,36 @@ describe("openai image generation provider", () => {
);
});
it("reports configured when either OpenAI API key auth or Codex OAuth auth is available", () => {
const provider = buildOpenAIImageGenerationProvider();
isProviderApiKeyConfiguredMock.mockImplementation(
(params: { provider: string }) => params.provider === "openai",
);
expect(provider.isConfigured?.({ agentDir: "/tmp/agent" })).toBe(true);
expect(isProviderApiKeyConfiguredMock).toHaveBeenCalledWith({
provider: "openai",
agentDir: "/tmp/agent",
});
isProviderApiKeyConfiguredMock.mockClear();
isProviderApiKeyConfiguredMock.mockImplementation(
(params: { provider: string }) => params.provider === "openai-codex",
);
expect(provider.isConfigured?.({ agentDir: "/tmp/agent" })).toBe(true);
expect(isProviderApiKeyConfiguredMock).toHaveBeenCalledWith({
provider: "openai",
agentDir: "/tmp/agent",
});
expect(isProviderApiKeyConfiguredMock).toHaveBeenCalledWith({
provider: "openai-codex",
agentDir: "/tmp/agent",
});
isProviderApiKeyConfiguredMock.mockReturnValue(false);
expect(provider.isConfigured?.({ agentDir: "/tmp/agent" })).toBe(false);
});
it("does not auto-allow local baseUrl overrides for image requests", async () => {
mockGeneratedPngResponse();

View File

@@ -266,6 +266,49 @@ describe("createImageGenerateTool", () => {
expect(createImageGenerateTool({ config: {} })).not.toBeNull();
});
it("infers the canonical OpenAI image model from provider readiness without explicit config", () => {
const isConfigured = vi.fn(({ agentDir }: { agentDir?: string }) => agentDir === "/tmp/agent");
vi.spyOn(imageGenerationRuntime, "listRuntimeImageGenerationProviders").mockReturnValue([
{
id: "openai",
defaultModel: "gpt-image-2",
models: ["gpt-image-2"],
isConfigured,
capabilities: {
generate: {
maxCount: 4,
supportsSize: true,
},
edit: {
enabled: true,
maxInputImages: 5,
supportsSize: true,
},
geometry: {
sizes: ["1024x1024", "1536x1024", "1024x1536"],
},
},
generateImage: vi.fn(async () => {
throw new Error("not used");
}),
},
]);
expect(
resolveImageGenerationModelConfigForTool({
cfg: {},
agentDir: "/tmp/agent",
}),
).toEqual({
primary: "openai/gpt-image-2",
});
expect(createImageGenerateTool({ config: {}, agentDir: "/tmp/agent" })).not.toBeNull();
expect(isConfigured).toHaveBeenCalledWith({
cfg: {},
agentDir: "/tmp/agent",
});
});
it("prefers the primary model provider when multiple image providers have auth", () => {
stubImageGenerationProviders();
vi.stubEnv("OPENAI_API_KEY", "openai-test");