mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 13:14:58 +00:00
test(memory): dedupe embeddings provider test fixtures
This commit is contained in:
@@ -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"'),
|
||||||
|
|||||||
Reference in New Issue
Block a user