test(memory): dedupe embeddings provider test fixtures

This commit is contained in:
Peter Steinberger
2026-02-18 12:28:25 +00:00
parent 87ca2a24bd
commit c3472f6c54

View File

@@ -25,6 +25,11 @@ const createFetchMock = () =>
json: async () => ({ data: [{ embedding: [1, 2, 3] }] }), json: async () => ({ data: [{ embedding: [1, 2, 3] }] }),
})); }));
afterEach(() => {
vi.resetAllMocks();
vi.unstubAllGlobals();
});
function requireProvider(result: Awaited<ReturnType<typeof createEmbeddingProvider>>) { function requireProvider(result: Awaited<ReturnType<typeof createEmbeddingProvider>>) {
if (!result.provider) { if (!result.provider) {
throw new Error("Expected embedding provider"); throw new Error("Expected embedding provider");
@@ -32,20 +37,36 @@ function requireProvider(result: Awaited<ReturnType<typeof createEmbeddingProvid
return result.provider; return result.provider;
} }
describe("embedding provider remote overrides", () => { function mockResolvedProviderKey(apiKey = "provider-key") {
afterEach(() => { vi.mocked(authModule.resolveApiKeyForProvider).mockResolvedValue({
vi.resetAllMocks(); apiKey,
vi.unstubAllGlobals(); mode: "api-key",
source: "test",
}); });
}
function mockMissingLocalEmbeddingDependency() {
importNodeLlamaCppMock.mockRejectedValue(
Object.assign(new Error("Cannot find package 'node-llama-cpp'"), {
code: "ERR_MODULE_NOT_FOUND",
}),
);
}
function createLocalProvider(options?: { fallback?: "none" | "openai" }) {
return createEmbeddingProvider({
config: {} as never,
provider: "local",
model: "text-embedding-3-small",
fallback: options?.fallback ?? "none",
});
}
describe("embedding provider remote overrides", () => {
it("uses remote baseUrl/apiKey and merges headers", async () => { it("uses remote baseUrl/apiKey and merges headers", async () => {
const fetchMock = createFetchMock(); const fetchMock = createFetchMock();
vi.stubGlobal("fetch", fetchMock); vi.stubGlobal("fetch", fetchMock);
vi.mocked(authModule.resolveApiKeyForProvider).mockResolvedValue({ mockResolvedProviderKey("provider-key");
apiKey: "provider-key",
mode: "api-key",
source: "test",
});
const cfg = { const cfg = {
models: { models: {
@@ -94,11 +115,7 @@ describe("embedding provider remote overrides", () => {
it("falls back to resolved api key when remote apiKey is blank", async () => { it("falls back to resolved api key when remote apiKey is blank", async () => {
const fetchMock = createFetchMock(); const fetchMock = createFetchMock();
vi.stubGlobal("fetch", fetchMock); vi.stubGlobal("fetch", fetchMock);
vi.mocked(authModule.resolveApiKeyForProvider).mockResolvedValue({ mockResolvedProviderKey("provider-key");
apiKey: "provider-key",
mode: "api-key",
source: "test",
});
const cfg = { const cfg = {
models: { models: {
@@ -137,11 +154,7 @@ describe("embedding provider remote overrides", () => {
json: async () => ({ embedding: { values: [1, 2, 3] } }), json: async () => ({ embedding: { values: [1, 2, 3] } }),
})); }));
vi.stubGlobal("fetch", fetchMock); vi.stubGlobal("fetch", fetchMock);
vi.mocked(authModule.resolveApiKeyForProvider).mockResolvedValue({ mockResolvedProviderKey("provider-key");
apiKey: "provider-key",
mode: "api-key",
source: "test",
});
const cfg = { const cfg = {
models: { models: {
@@ -178,11 +191,6 @@ describe("embedding provider remote overrides", () => {
}); });
describe("embedding provider auto selection", () => { describe("embedding provider auto selection", () => {
afterEach(() => {
vi.resetAllMocks();
vi.unstubAllGlobals();
});
it("prefers openai when a key resolves", async () => { it("prefers openai when a key resolves", async () => {
vi.mocked(authModule.resolveApiKeyForProvider).mockImplementation(async ({ provider }) => { vi.mocked(authModule.resolveApiKeyForProvider).mockImplementation(async ({ provider }) => {
if (provider === "openai") { if (provider === "openai") {
@@ -271,33 +279,15 @@ describe("embedding provider auto selection", () => {
}); });
describe("embedding provider local fallback", () => { describe("embedding provider local fallback", () => {
afterEach(() => {
vi.resetAllMocks();
vi.unstubAllGlobals();
});
it("falls back to openai when node-llama-cpp is missing", async () => { it("falls back to openai when node-llama-cpp is missing", async () => {
importNodeLlamaCppMock.mockRejectedValue( mockMissingLocalEmbeddingDependency();
Object.assign(new Error("Cannot find package 'node-llama-cpp'"), {
code: "ERR_MODULE_NOT_FOUND",
}),
);
const fetchMock = createFetchMock(); const fetchMock = createFetchMock();
vi.stubGlobal("fetch", fetchMock); vi.stubGlobal("fetch", fetchMock);
vi.mocked(authModule.resolveApiKeyForProvider).mockResolvedValue({ mockResolvedProviderKey("provider-key");
apiKey: "provider-key",
mode: "api-key",
source: "test",
});
const result = await createEmbeddingProvider({ const result = await createLocalProvider({ fallback: "openai" });
config: {} as never,
provider: "local",
model: "text-embedding-3-small",
fallback: "openai",
});
const provider = requireProvider(result); const provider = requireProvider(result);
expect(provider.id).toBe("openai"); expect(provider.id).toBe("openai");
@@ -306,46 +296,17 @@ describe("embedding provider local fallback", () => {
}); });
it("throws a helpful error when local is requested and fallback is none", async () => { it("throws a helpful error when local is requested and fallback is none", async () => {
importNodeLlamaCppMock.mockRejectedValue( mockMissingLocalEmbeddingDependency();
Object.assign(new Error("Cannot find package 'node-llama-cpp'"), { await expect(createLocalProvider()).rejects.toThrow(/optional dependency node-llama-cpp/i);
code: "ERR_MODULE_NOT_FOUND",
}),
);
await expect(
createEmbeddingProvider({
config: {} as never,
provider: "local",
model: "text-embedding-3-small",
fallback: "none",
}),
).rejects.toThrow(/optional dependency node-llama-cpp/i);
}); });
it("mentions every remote provider in local setup guidance", async () => { it("mentions every remote provider in local setup guidance", async () => {
importNodeLlamaCppMock.mockRejectedValue( mockMissingLocalEmbeddingDependency();
Object.assign(new Error("Cannot find package 'node-llama-cpp'"), { await expect(createLocalProvider()).rejects.toThrow(/provider = "gemini"/i);
code: "ERR_MODULE_NOT_FOUND",
}),
);
await expect(
createEmbeddingProvider({
config: {} as never,
provider: "local",
model: "text-embedding-3-small",
fallback: "none",
}),
).rejects.toThrow(/provider = "gemini"/i);
}); });
}); });
describe("local embedding normalization", () => { describe("local embedding normalization", () => {
afterEach(() => {
vi.resetAllMocks();
vi.unstubAllGlobals();
});
async function createLocalProviderForTest() { async function createLocalProviderForTest() {
return createEmbeddingProvider({ return createEmbeddingProvider({
config: {} as never, config: {} as never,
@@ -456,11 +417,6 @@ describe("local embedding normalization", () => {
}); });
describe("FTS-only fallback when no provider available", () => { describe("FTS-only fallback when no provider available", () => {
afterEach(() => {
vi.resetAllMocks();
vi.unstubAllGlobals();
});
it("returns null provider with reason when auto mode finds no providers", async () => { it("returns null provider with reason when auto mode finds no providers", async () => {
vi.mocked(authModule.resolveApiKeyForProvider).mockRejectedValue( vi.mocked(authModule.resolveApiKeyForProvider).mockRejectedValue(
new Error('No API key found for provider "openai"'), new Error('No API key found for provider "openai"'),