fix: harden provider and gateway test seams

This commit is contained in:
Peter Steinberger
2026-04-23 23:47:44 +01:00
parent 0999fec19b
commit 6259f6addc
6 changed files with 28 additions and 21 deletions

View File

@@ -0,0 +1,8 @@
import { GoogleGenAI } from "@google/genai";
export type GoogleGenAIClient = InstanceType<typeof GoogleGenAI>;
export type GoogleGenAIOptions = ConstructorParameters<typeof GoogleGenAI>[0];
export function createGoogleGenAI(options: GoogleGenAIOptions): GoogleGenAIClient {
return new GoogleGenAI(options);
}

View File

@@ -1,19 +1,19 @@
import { afterEach, describe, expect, it, vi } from "vitest";
const { GoogleGenAIMock, generateContentMock } = vi.hoisted(() => {
const { createGoogleGenAIMock, generateContentMock } = vi.hoisted(() => {
const generateContentMock = vi.fn();
const GoogleGenAIMock = vi.fn(function GoogleGenAI() {
const createGoogleGenAIMock = vi.fn(() => {
return {
models: {
generateContent: generateContentMock,
},
};
});
return { GoogleGenAIMock, generateContentMock };
return { createGoogleGenAIMock, generateContentMock };
});
vi.mock("@google/genai", () => ({
GoogleGenAI: GoogleGenAIMock,
vi.mock("./google-genai-runtime.js", () => ({
createGoogleGenAI: createGoogleGenAIMock,
}));
import * as providerAuthRuntime from "openclaw/plugin-sdk/provider-auth-runtime";
@@ -24,7 +24,7 @@ describe("google music generation provider", () => {
afterEach(() => {
vi.restoreAllMocks();
generateContentMock.mockReset();
GoogleGenAIMock.mockClear();
createGoogleGenAIMock.mockClear();
});
it("declares explicit mode capabilities", () => {
@@ -75,7 +75,7 @@ describe("google music generation provider", () => {
expect(result.tracks).toHaveLength(1);
expect(result.tracks[0]?.mimeType).toBe("audio/mpeg");
expect(result.lyrics).toEqual(["wake the city up"]);
expect(GoogleGenAIMock).toHaveBeenCalledWith(
expect(createGoogleGenAIMock).toHaveBeenCalledWith(
expect.objectContaining({
apiKey: "google-key",
}),

View File

@@ -1,4 +1,3 @@
import { GoogleGenAI } from "@google/genai";
import { extensionForMime } from "openclaw/plugin-sdk/media-mime";
import type {
GeneratedMusicAsset,
@@ -14,6 +13,7 @@ import {
GOOGLE_MAX_INPUT_IMAGES,
GOOGLE_PRO_MUSIC_MODEL,
} from "./generation-provider-metadata.js";
import { createGoogleGenAI } from "./google-genai-runtime.js";
const DEFAULT_TIMEOUT_MS = 180_000;
@@ -128,7 +128,7 @@ export function buildGoogleMusicGenerationProvider(): MusicGenerationProvider {
}
}
const client = new GoogleGenAI({
const client = createGoogleGenAI({
apiKey: auth.apiKey,
httpOptions: {
...(resolveConfiguredGoogleMusicBaseUrl(req)

View File

@@ -1,9 +1,9 @@
import { afterEach, describe, expect, it, vi } from "vitest";
const { GoogleGenAIMock, generateVideosMock, getVideosOperationMock } = vi.hoisted(() => {
const { createGoogleGenAIMock, generateVideosMock, getVideosOperationMock } = vi.hoisted(() => {
const generateVideosMock = vi.fn();
const getVideosOperationMock = vi.fn();
const GoogleGenAIMock = vi.fn(function GoogleGenAI() {
const createGoogleGenAIMock = vi.fn(() => {
return {
models: {
generateVideos: generateVideosMock,
@@ -16,11 +16,11 @@ const { GoogleGenAIMock, generateVideosMock, getVideosOperationMock } = vi.hoist
},
};
});
return { GoogleGenAIMock, generateVideosMock, getVideosOperationMock };
return { createGoogleGenAIMock, generateVideosMock, getVideosOperationMock };
});
vi.mock("@google/genai", () => ({
GoogleGenAI: GoogleGenAIMock,
vi.mock("./google-genai-runtime.js", () => ({
createGoogleGenAI: createGoogleGenAIMock,
}));
import * as providerAuthRuntime from "openclaw/plugin-sdk/provider-auth-runtime";
@@ -32,7 +32,7 @@ describe("google video generation provider", () => {
vi.restoreAllMocks();
generateVideosMock.mockReset();
getVideosOperationMock.mockReset();
GoogleGenAIMock.mockClear();
createGoogleGenAIMock.mockClear();
});
it("declares explicit mode capabilities", () => {
@@ -89,7 +89,7 @@ describe("google video generation provider", () => {
expect(request?.config).not.toHaveProperty("numberOfVideos");
expect(result.videos).toHaveLength(1);
expect(result.videos[0]?.mimeType).toBe("video/mp4");
expect(GoogleGenAIMock).toHaveBeenCalledWith(
expect(createGoogleGenAIMock).toHaveBeenCalledWith(
expect.objectContaining({
apiKey: "google-key",
httpOptions: expect.not.objectContaining({

View File

@@ -1,6 +1,5 @@
import { mkdtemp, readFile, rm } from "node:fs/promises";
import path from "node:path";
import { GoogleGenAI } from "@google/genai";
import { resolveApiKeyForProvider } from "openclaw/plugin-sdk/provider-auth-runtime";
import {
createProviderOperationDeadline,
@@ -22,6 +21,7 @@ import {
GOOGLE_VIDEO_MAX_DURATION_SECONDS,
GOOGLE_VIDEO_MIN_DURATION_SECONDS,
} from "./generation-provider-metadata.js";
import { createGoogleGenAI, type GoogleGenAIClient } from "./google-genai-runtime.js";
const DEFAULT_TIMEOUT_MS = 180_000;
const POLL_INTERVAL_MS = 10_000;
@@ -126,7 +126,7 @@ function resolveInputVideo(req: VideoGenerationRequest) {
}
async function downloadGeneratedVideo(params: {
client: GoogleGenAI;
client: GoogleGenAIClient;
file: unknown;
index: number;
}): Promise<GeneratedVideoAsset> {
@@ -181,7 +181,7 @@ export function buildGoogleVideoGenerationProvider(): VideoGenerationProvider {
timeoutMs: req.timeoutMs,
label: "Google video generation",
});
const client = new GoogleGenAI({
const client = createGoogleGenAI({
apiKey: auth.apiKey,
httpOptions: {
...(configuredBaseUrl ? { baseUrl: configuredBaseUrl } : {}),

View File

@@ -59,8 +59,7 @@ let runtimeMod: EmbeddedGatewayRuntime | undefined;
async function getRuntime(): Promise<EmbeddedGatewayRuntime> {
if (!runtimeMod) {
const modPath = [".", "embedded-gateway-stub.runtime.js"].join("/");
runtimeMod = (await import(modPath)) as EmbeddedGatewayRuntime;
runtimeMod = (await import("./embedded-gateway-stub.runtime.js")) as EmbeddedGatewayRuntime;
}
return runtimeMod;
}