Files
2026-07-13 13:39:12 +08:00

132 lines
5.9 KiB
TypeScript

/**
* TDD tests for the llmlingua model registry + model store (Tasks 1-2).
*
* Tests are written RED-first (before the implementation exists).
*
* Coverage:
* 1. Registry shape — tinybert + bert-base present; default points at a valid key.
* 2. Each entry's factory/dtype/subfolder/hfRepo invariants hold.
* 3. resolveLlmlinguaModel() — known id, and the unknown/undefined/empty fallbacks.
* 4. getLlmlinguaModelCacheDir() — path suffix + DATA_DIR honoring.
* 5. configureTransformersEnv() — Hub download default vs local modelPath override.
*/
import { describe, it, after } from "node:test";
import assert from "node:assert/strict";
import os from "node:os";
import path from "node:path";
import fs from "node:fs";
import {
DEFAULT_LLMLINGUA_MODEL,
LLMLINGUA_MODELS,
} from "../../../open-sse/services/compression/engines/llmlingua/constants.ts";
import {
getLlmlinguaModelCacheDir,
resolveLlmlinguaModel,
configureTransformersEnv,
type TransformersEnvLike,
} from "../../../open-sse/services/compression/engines/llmlingua/modelStore.ts";
// ─── tests ────────────────────────────────────────────────────────────────────
describe("llmlingua model registry (constants)", () => {
// ── 1. registry shape ──────────────────────────────────────────────────────
it("LLMLINGUA_MODELS has both proven models and the default is a valid key", () => {
assert.ok(LLMLINGUA_MODELS.tinybert, "tinybert entry must exist");
assert.ok(LLMLINGUA_MODELS["bert-base"], "bert-base entry must exist");
assert.equal(DEFAULT_LLMLINGUA_MODEL, "tinybert");
assert.ok(
Object.prototype.hasOwnProperty.call(LLMLINGUA_MODELS, DEFAULT_LLMLINGUA_MODEL),
"default must be a key of the registry"
);
});
// ── 2. per-entry invariants ─────────────────────────────────────────────────
it("every entry uses WithBERTMultilingual / fp32 / '' subfolder and a sane hfRepo", () => {
for (const [key, entry] of Object.entries(LLMLINGUA_MODELS)) {
assert.equal(entry.factory, "WithBERTMultilingual", `${key}.factory`);
assert.equal(entry.dtype, "fp32", `${key}.dtype`);
assert.equal(entry.subfolder, "", `${key}.subfolder`);
assert.equal(typeof entry.hfRepo, "string", `${key}.hfRepo type`);
assert.ok(entry.hfRepo.length > 0, `${key}.hfRepo non-empty`);
assert.ok(entry.hfRepo.includes("/"), `${key}.hfRepo contains "/"`);
assert.equal(entry.id, key, `${key}.id matches its registry key`);
assert.equal(typeof entry.sizeMB, "number", `${key}.sizeMB type`);
assert.equal(typeof entry.label, "string", `${key}.label type`);
}
});
});
describe("resolveLlmlinguaModel", () => {
// ── 3. resolution + fallback ────────────────────────────────────────────────
it("returns the requested entry for a known id", () => {
const resolved = resolveLlmlinguaModel("bert-base");
assert.equal(resolved.id, "bert-base");
assert.equal(resolved, LLMLINGUA_MODELS["bert-base"]);
});
it("falls back to the default (tinybert) for unknown / undefined / empty ids", () => {
const def = LLMLINGUA_MODELS[DEFAULT_LLMLINGUA_MODEL];
assert.equal(resolveLlmlinguaModel("nonexistent"), def);
assert.equal(resolveLlmlinguaModel(undefined), def);
assert.equal(resolveLlmlinguaModel(null), def);
assert.equal(resolveLlmlinguaModel(""), def);
});
});
describe("getLlmlinguaModelCacheDir", () => {
const originalDataDir = process.env.DATA_DIR;
let tmpDir: string | undefined;
after(() => {
if (originalDataDir === undefined) {
delete process.env.DATA_DIR;
} else {
process.env.DATA_DIR = originalDataDir;
}
if (tmpDir) {
try {
fs.rmSync(tmpDir, { recursive: true, force: true });
} catch {
/* ignore cleanup errors */
}
}
});
// ── 4. path suffix + DATA_DIR honoring ──────────────────────────────────────
it("ends with models/llmlingua and lives under DATA_DIR when set", () => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "llm-"));
process.env.DATA_DIR = tmpDir;
const dir = getLlmlinguaModelCacheDir();
assert.ok(
dir.endsWith(path.join("models", "llmlingua")),
`cache dir should end with models/llmlingua, got: ${dir}`
);
assert.ok(dir.startsWith(tmpDir), `cache dir should be under DATA_DIR, got: ${dir}`);
assert.equal(dir, path.join(tmpDir, "models", "llmlingua"));
});
});
describe("configureTransformersEnv", () => {
// ── 5. Hub default vs local override ────────────────────────────────────────
it("Hub download default: cacheDir set, allowRemoteModels true, no localModelPath", () => {
const env: TransformersEnvLike = {};
configureTransformersEnv(env, {});
assert.equal(typeof env.cacheDir, "string");
assert.ok((env.cacheDir as string).length > 0, "cacheDir must be set");
assert.equal(env.allowRemoteModels, true);
assert.equal(env.localModelPath, undefined);
});
it("local modelPath override: localModelPath set, allowRemoteModels false, cacheDir still set", () => {
const env: TransformersEnvLike = {};
configureTransformersEnv(env, { modelPath: "/some/local/dir" });
assert.equal(env.localModelPath, "/some/local/dir");
assert.equal(env.allowRemoteModels, false);
assert.equal(typeof env.cacheDir, "string");
assert.ok((env.cacheDir as string).length > 0, "cacheDir must still be set");
});
});