Files
socraticode/tests/unit/embedding-config.test.ts
T
2026-02-28 17:06:21 +00:00

252 lines
8.6 KiB
TypeScript

// SPDX-License-Identifier: AGPL-3.0-only
// Copyright (C) 2026 Giancarlo Erra - Altaire Limited
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import {
getEmbeddingConfig,
loadEmbeddingConfig,
resetEmbeddingConfig,
} from "../../src/services/embedding-config.js";
describe("embedding-config", () => {
const originalEnv = { ...process.env };
beforeEach(() => {
resetEmbeddingConfig();
// Clear all embedding-related env vars
delete process.env.EMBEDDING_PROVIDER;
delete process.env.OLLAMA_MODE;
delete process.env.OLLAMA_URL;
delete process.env.EMBEDDING_MODEL;
delete process.env.EMBEDDING_DIMENSIONS;
delete process.env.EMBEDDING_CONTEXT_LENGTH;
delete process.env.OLLAMA_API_KEY;
delete process.env.OPENAI_API_KEY;
delete process.env.GOOGLE_API_KEY;
});
afterEach(() => {
resetEmbeddingConfig();
// Restore original env
process.env = { ...originalEnv };
});
describe("defaults (no env vars)", () => {
it("defaults to ollama provider", () => {
const config = loadEmbeddingConfig();
expect(config.embeddingProvider).toBe("ollama");
});
it("defaults to auto mode", () => {
const config = loadEmbeddingConfig();
expect(config.ollamaMode).toBe("auto");
});
it("defaults URL to localhost:11434 in auto mode", () => {
const config = loadEmbeddingConfig();
expect(config.ollamaUrl).toBe("http://localhost:11434");
});
it("defaults model to nomic-embed-text", () => {
const config = loadEmbeddingConfig();
expect(config.embeddingModel).toBe("nomic-embed-text");
});
it("defaults dimensions to 768", () => {
const config = loadEmbeddingConfig();
expect(config.embeddingDimensions).toBe(768);
});
it("has no API key by default", () => {
const config = loadEmbeddingConfig();
expect(config.ollamaApiKey).toBeUndefined();
});
});
describe("docker mode", () => {
it("uses docker URL default when OLLAMA_MODE=docker", () => {
process.env.OLLAMA_MODE = "docker";
const config = loadEmbeddingConfig();
expect(config.ollamaMode).toBe("docker");
expect(config.ollamaUrl).toBe("http://localhost:11435");
});
it("allows overriding URL in docker mode", () => {
process.env.OLLAMA_MODE = "docker";
process.env.OLLAMA_URL = "http://custom:9999";
const config = loadEmbeddingConfig();
expect(config.ollamaUrl).toBe("http://custom:9999");
});
});
describe("external mode", () => {
it("uses external URL default when OLLAMA_MODE=external", () => {
process.env.OLLAMA_MODE = "external";
const config = loadEmbeddingConfig();
expect(config.ollamaMode).toBe("external");
expect(config.ollamaUrl).toBe("http://localhost:11434");
});
it("allows overriding URL in external mode", () => {
process.env.OLLAMA_MODE = "external";
process.env.OLLAMA_URL = "http://gpu-server:11434";
const config = loadEmbeddingConfig();
expect(config.ollamaUrl).toBe("http://gpu-server:11434");
});
});
describe("model and dimensions overrides", () => {
it("allows custom model", () => {
process.env.EMBEDDING_MODEL = "mxbai-embed-large";
const config = loadEmbeddingConfig();
expect(config.embeddingModel).toBe("mxbai-embed-large");
});
it("allows custom dimensions", () => {
process.env.EMBEDDING_DIMENSIONS = "1024";
const config = loadEmbeddingConfig();
expect(config.embeddingDimensions).toBe(1024);
});
it("parses dimensions as integer", () => {
process.env.EMBEDDING_DIMENSIONS = "512";
const config = loadEmbeddingConfig();
expect(config.embeddingDimensions).toBe(512);
expect(typeof config.embeddingDimensions).toBe("number");
});
});
describe("API key", () => {
it("reads OLLAMA_API_KEY when set", () => {
process.env.OLLAMA_API_KEY = "test-key-123";
const config = loadEmbeddingConfig();
expect(config.ollamaApiKey).toBe("test-key-123");
});
it("is undefined when not set", () => {
const config = loadEmbeddingConfig();
expect(config.ollamaApiKey).toBeUndefined();
});
});
describe("invalid mode", () => {
it("throws for invalid OLLAMA_MODE", () => {
process.env.OLLAMA_MODE = "invalid";
expect(() => loadEmbeddingConfig()).toThrow(
'Invalid OLLAMA_MODE: "invalid". Must be "docker", "external", or "auto".',
);
});
});
describe("singleton behavior", () => {
it("caches config after first load", () => {
const first = loadEmbeddingConfig();
// Change env — should NOT affect cached config
process.env.OLLAMA_MODE = "external";
const second = loadEmbeddingConfig();
expect(second).toBe(first); // same reference
expect(second.ollamaMode).toBe("auto");
});
it("getEmbeddingConfig returns same as loadEmbeddingConfig", () => {
const loaded = loadEmbeddingConfig();
const got = getEmbeddingConfig();
expect(got).toBe(loaded);
});
it("resetEmbeddingConfig clears cache", () => {
const first = loadEmbeddingConfig();
expect(first.ollamaMode).toBe("auto");
resetEmbeddingConfig();
process.env.OLLAMA_MODE = "external";
const second = loadEmbeddingConfig();
expect(second.ollamaMode).toBe("external");
expect(second).not.toBe(first);
});
});
describe("full external config", () => {
it("handles complete external config with all options", () => {
process.env.OLLAMA_MODE = "external";
process.env.OLLAMA_URL = "http://remote-gpu:11434";
process.env.EMBEDDING_MODEL = "mxbai-embed-large";
process.env.EMBEDDING_DIMENSIONS = "1024";
process.env.OLLAMA_API_KEY = "secret";
const config = loadEmbeddingConfig();
expect(config).toEqual({
embeddingProvider: "ollama",
ollamaMode: "external",
ollamaUrl: "http://remote-gpu:11434",
embeddingModel: "mxbai-embed-large",
embeddingDimensions: 1024,
embeddingContextLength: 512,
ollamaApiKey: "secret",
});
});
});
describe("embedding provider selection", () => {
it("defaults to ollama when EMBEDDING_PROVIDER is not set", () => {
const config = loadEmbeddingConfig();
expect(config.embeddingProvider).toBe("ollama");
expect(config.embeddingModel).toBe("nomic-embed-text");
expect(config.embeddingDimensions).toBe(768);
});
it("selects openai provider with correct defaults", () => {
process.env.EMBEDDING_PROVIDER = "openai";
const config = loadEmbeddingConfig();
expect(config.embeddingProvider).toBe("openai");
expect(config.embeddingModel).toBe("text-embedding-3-small");
expect(config.embeddingDimensions).toBe(1536);
expect(config.embeddingContextLength).toBe(8191);
});
it("selects google provider with correct defaults", () => {
process.env.EMBEDDING_PROVIDER = "google";
const config = loadEmbeddingConfig();
expect(config.embeddingProvider).toBe("google");
expect(config.embeddingModel).toBe("gemini-embedding-001");
expect(config.embeddingDimensions).toBe(3072);
expect(config.embeddingContextLength).toBe(2048);
});
it("throws for invalid EMBEDDING_PROVIDER", () => {
process.env.EMBEDDING_PROVIDER = "anthropic";
expect(() => loadEmbeddingConfig()).toThrow(
'Invalid EMBEDDING_PROVIDER: "anthropic". Must be "ollama", "openai", or "google".',
);
});
it("allows overriding model for openai provider", () => {
process.env.EMBEDDING_PROVIDER = "openai";
process.env.EMBEDDING_MODEL = "text-embedding-3-large";
const config = loadEmbeddingConfig();
expect(config.embeddingModel).toBe("text-embedding-3-large");
expect(config.embeddingContextLength).toBe(8191);
});
it("allows overriding dimensions for openai provider", () => {
process.env.EMBEDDING_PROVIDER = "openai";
process.env.EMBEDDING_DIMENSIONS = "256";
const config = loadEmbeddingConfig();
expect(config.embeddingDimensions).toBe(256);
});
it("uses context length for unknown model", () => {
process.env.EMBEDDING_PROVIDER = "openai";
process.env.EMBEDDING_MODEL = "custom-embed-model";
const config = loadEmbeddingConfig();
expect(config.embeddingContextLength).toBe(0);
});
it("allows explicit context length override for any provider", () => {
process.env.EMBEDDING_PROVIDER = "google";
process.env.EMBEDDING_CONTEXT_LENGTH = "4096";
const config = loadEmbeddingConfig();
expect(config.embeddingContextLength).toBe(4096);
});
});
});