test: dedupe plugin provider runtime suites

This commit is contained in:
Peter Steinberger
2026-03-28 04:02:02 +00:00
parent 708ff9145e
commit e74f206a68
23 changed files with 509 additions and 295 deletions

View File

@@ -24,20 +24,27 @@ describe("gateway request scope", () => {
});
}
function expectGatewayScope(
runtimeScope: Awaited<ReturnType<typeof importGatewayRequestScopeModule>>,
expected: PluginRuntimeGatewayRequestScope,
) {
expect(runtimeScope.getPluginRuntimeGatewayRequestScope()).toEqual(expected);
}
it("reuses AsyncLocalStorage across reloaded module instances", async () => {
const first = await importGatewayRequestScopeModule();
await first.withPluginRuntimeGatewayRequestScope(TEST_SCOPE, async () => {
vi.resetModules();
const second = await importGatewayRequestScopeModule();
expect(second.getPluginRuntimeGatewayRequestScope()).toEqual(TEST_SCOPE);
expectGatewayScope(second, TEST_SCOPE);
});
});
it("attaches plugin id to the active scope", async () => {
await withTestGatewayScope(async (runtimeScope) => {
await runtimeScope.withPluginRuntimePluginIdScope("voice-call", async () => {
expect(runtimeScope.getPluginRuntimeGatewayRequestScope()).toEqual({
expectGatewayScope(runtimeScope, {
...TEST_SCOPE,
pluginId: "voice-call",
});

View File

@@ -50,6 +50,12 @@ function expectGatewaySubagentRunFailure(
);
}
function expectFunctionKeys(value: Record<string, unknown>, keys: readonly string[]) {
keys.forEach((key) => {
expect(typeof value[key]).toBe("function");
});
}
describe("plugin runtime command execution", () => {
beforeEach(() => {
vi.restoreAllMocks();
@@ -96,10 +102,12 @@ describe("plugin runtime command execution", () => {
{
name: "exposes runtime.mediaUnderstanding helpers and keeps stt as an alias",
assert: (runtime: ReturnType<typeof createPluginRuntime>) => {
expect(typeof runtime.mediaUnderstanding.runFile).toBe("function");
expect(typeof runtime.mediaUnderstanding.describeImageFile).toBe("function");
expect(typeof runtime.mediaUnderstanding.describeImageFileWithModel).toBe("function");
expect(typeof runtime.mediaUnderstanding.describeVideoFile).toBe("function");
expectFunctionKeys(runtime.mediaUnderstanding as Record<string, unknown>, [
"runFile",
"describeImageFile",
"describeImageFileWithModel",
"describeVideoFile",
]);
expect(runtime.mediaUnderstanding.transcribeAudioFile).toBe(
runtime.stt.transcribeAudioFile,
);
@@ -108,15 +116,19 @@ describe("plugin runtime command execution", () => {
{
name: "exposes runtime.imageGeneration helpers",
assert: (runtime: ReturnType<typeof createPluginRuntime>) => {
expect(typeof runtime.imageGeneration.generate).toBe("function");
expect(typeof runtime.imageGeneration.listProviders).toBe("function");
expectFunctionKeys(runtime.imageGeneration as Record<string, unknown>, [
"generate",
"listProviders",
]);
},
},
{
name: "exposes runtime.webSearch helpers",
assert: (runtime: ReturnType<typeof createPluginRuntime>) => {
expect(typeof runtime.webSearch.listProviders).toBe("function");
expect(typeof runtime.webSearch.search).toBe("function");
expectFunctionKeys(runtime.webSearch as Record<string, unknown>, [
"listProviders",
"search",
]);
},
},
{
@@ -126,17 +138,23 @@ describe("plugin runtime command execution", () => {
model: DEFAULT_MODEL,
provider: DEFAULT_PROVIDER,
});
expect(typeof runtime.agent.runEmbeddedPiAgent).toBe("function");
expect(typeof runtime.agent.resolveAgentDir).toBe("function");
expect(typeof runtime.agent.session.resolveSessionFilePath).toBe("function");
expectFunctionKeys(runtime.agent as Record<string, unknown>, [
"runEmbeddedPiAgent",
"resolveAgentDir",
]);
expectFunctionKeys(runtime.agent.session as Record<string, unknown>, [
"resolveSessionFilePath",
]);
},
},
{
name: "exposes runtime.modelAuth with getApiKeyForModel and resolveApiKeyForProvider",
assert: (runtime: ReturnType<typeof createPluginRuntime>) => {
expect(runtime.modelAuth).toBeDefined();
expect(typeof runtime.modelAuth.getApiKeyForModel).toBe("function");
expect(typeof runtime.modelAuth.resolveApiKeyForProvider).toBe("function");
expectFunctionKeys(runtime.modelAuth as Record<string, unknown>, [
"getApiKeyForModel",
"resolveApiKeyForProvider",
]);
},
},
] as const)("$name", ({ assert }) => {

View File

@@ -23,6 +23,13 @@ function buildTelegramTypingParams(
};
}
function expectTelegramPulseCount(
pulse: ReturnType<typeof vi.fn<() => Promise<unknown>>>,
expected: number,
) {
expect(pulse).toHaveBeenCalledTimes(expected);
}
describe("createTelegramTypingLease", () => {
afterEach(() => {
vi.useRealTimers();
@@ -65,11 +72,11 @@ describe("createTelegramTypingLease", () => {
pulse,
});
expect(pulse).toHaveBeenCalledTimes(1);
expectTelegramPulseCount(pulse, 1);
await vi.advanceTimersByTimeAsync(TELEGRAM_TYPING_DEFAULT_INTERVAL_MS - 1);
expect(pulse).toHaveBeenCalledTimes(1);
expectTelegramPulseCount(pulse, 1);
await vi.advanceTimersByTimeAsync(1);
expect(pulse).toHaveBeenCalledTimes(2);
expectTelegramPulseCount(pulse, 2);
lease.stop();
});

View File

@@ -1,5 +1,9 @@
import { expect, vi } from "vitest";
function expectPulseCount(pulse: { mock: { calls: unknown[] } }, expected: number) {
expect(pulse.mock.calls).toHaveLength(expected);
}
export async function expectIndependentTypingLeases<
TParams extends { intervalMs?: number; pulse: (...args: never[]) => Promise<unknown> },
TLease extends { refresh: () => Promise<void>; stop: () => void },
@@ -13,17 +17,17 @@ export async function expectIndependentTypingLeases<
const leaseA = await params.createLease(params.buildParams(pulse));
const leaseB = await params.createLease(params.buildParams(pulse));
expect(pulse).toHaveBeenCalledTimes(2);
expectPulseCount(pulse as unknown as { mock: { calls: unknown[] } }, 2);
await vi.advanceTimersByTimeAsync(2_000);
expect(pulse).toHaveBeenCalledTimes(4);
expectPulseCount(pulse as unknown as { mock: { calls: unknown[] } }, 4);
leaseA.stop();
await vi.advanceTimersByTimeAsync(2_000);
expect(pulse).toHaveBeenCalledTimes(5);
expectPulseCount(pulse as unknown as { mock: { calls: unknown[] } }, 5);
await leaseB.refresh();
expect(pulse).toHaveBeenCalledTimes(6);
expectPulseCount(pulse as unknown as { mock: { calls: unknown[] } }, 6);
leaseB.stop();
}
@@ -41,7 +45,7 @@ export async function expectBackgroundTypingPulseFailuresAreSwallowed<
const lease = await params.createLease(params.buildParams(params.pulse));
await expect(vi.advanceTimersByTimeAsync(2_000)).resolves.toBe(vi);
expect(params.pulse).toHaveBeenCalledTimes(2);
expectPulseCount(params.pulse as unknown as { mock: { calls: unknown[] } }, 2);
lease.stop();
}