131 lines
4.4 KiB
TypeScript
131 lines
4.4 KiB
TypeScript
import { expect, test } from "vitest";
|
|
import { parseWorkspaceYaml, serializeWorkspaceYaml } from "../src/workspaces/schema.js";
|
|
|
|
export const validYaml = `workspace:
|
|
schema_version: 1
|
|
id: psd-clinical
|
|
name: Policlinico San Donato
|
|
description: Clinical data warehouse workspace
|
|
language: it
|
|
dwh:
|
|
engine: postgres
|
|
database: postgres
|
|
schema: datawarehouse
|
|
port: 5432
|
|
timeout_ms: 5000
|
|
supported_transports:
|
|
- postgres_direct
|
|
- rest_api
|
|
- ssh_tunnel
|
|
semantic_index:
|
|
vector_store:
|
|
engine: pgvector
|
|
database: postgres
|
|
schema: vectors
|
|
collection: clinical_documents
|
|
dimensions: 768
|
|
distance: cosine
|
|
port: 5432
|
|
timeout_ms: 5000
|
|
supported_transports:
|
|
- pgvector_direct
|
|
- rest_api
|
|
- ssh_tunnel
|
|
embedding:
|
|
provider: ollama_compatible
|
|
model: nomic-embed-text-v2-moe
|
|
dimensions: 768
|
|
timeout_ms: 5000
|
|
llm_policy:
|
|
default: zai/glm-5.2
|
|
allowed:
|
|
- zai/glm-5.2
|
|
- openai/gpt-5
|
|
`;
|
|
|
|
test("rejects a workspace whose embedding dimensions differ from its collection", () => {
|
|
expect(() => parseWorkspaceYaml(validYaml.replace("dimensions: 768", "dimensions: 1536")))
|
|
.toThrow(/dimensions/i);
|
|
});
|
|
|
|
test("rejects an LLM default outside its allowlist", () => {
|
|
expect(() => parseWorkspaceYaml(validYaml.replace("- zai/glm-5.2", "- openai/gpt-5")))
|
|
.toThrow(/allowlist/i);
|
|
});
|
|
|
|
test("rejects unknown keys and invalid immutable IDs", () => {
|
|
expect(() => parseWorkspaceYaml(validYaml.replace(" language: it", " language: it\n label: PSD")))
|
|
.toThrow(/unrecognized key/i);
|
|
expect(() => parseWorkspaceYaml(validYaml.replace("id: psd-clinical", "id: PSD")))
|
|
.toThrow(/id/i);
|
|
});
|
|
|
|
test("accepts optional connection ports and timeouts but rejects unsafe values", () => {
|
|
expect(parseWorkspaceYaml(validYaml).dwh.port).toBe(5432);
|
|
expect(() => parseWorkspaceYaml(validYaml.replace("port: 5432", "port: 0")))
|
|
.toThrow(/port/i);
|
|
expect(() => parseWorkspaceYaml(validYaml.replace("port: 5432", "port: 65536")))
|
|
.toThrow(/port/i);
|
|
expect(() => parseWorkspaceYaml(validYaml.replace("timeout_ms: 5000", "timeout_ms: 0")))
|
|
.toThrow(/timeout/i);
|
|
});
|
|
|
|
test("requires explicit vector database and schema identities with strict diagnostic declarations", () => {
|
|
const diagnosticWorkspace = validYaml.replace(
|
|
" engine: pgvector\n database: postgres",
|
|
" engine: pgvector\n database: vector_database",
|
|
).replace(
|
|
"llm_policy:\n",
|
|
"diagnostics:\n"
|
|
+ " dwh_rest:\n"
|
|
+ " method: POST\n"
|
|
+ " path: /rpc/ping\n"
|
|
+ " auth: bearer\n"
|
|
+ " response:\n"
|
|
+ " database: database\n"
|
|
+ " schema: schema\n"
|
|
+ " vector_rest:\n"
|
|
+ " metadata:\n"
|
|
+ " method: GET\n"
|
|
+ " path: /metadata\n"
|
|
+ " auth: bearer\n"
|
|
+ " response:\n"
|
|
+ " collection: collection\n"
|
|
+ " dimensions: dimensions\n"
|
|
+ " distance: distance\n"
|
|
+ " reversible_probe:\n"
|
|
+ " method: POST\n"
|
|
+ " path: /rpc/diagnostic_vector_probe\n"
|
|
+ " auth: bearer\n"
|
|
+ " embedding:\n"
|
|
+ " method: GET\n"
|
|
+ " path: /models\n"
|
|
+ " auth: none\n"
|
|
+ " response:\n"
|
|
+ " model: model\n"
|
|
+ " dimensions: dimensions\n"
|
|
+ "llm_policy:\n",
|
|
);
|
|
|
|
expect(parseWorkspaceYaml(diagnosticWorkspace).semantic_index.vector_store).toMatchObject({
|
|
database: "vector_database",
|
|
schema: "vectors",
|
|
});
|
|
expect(() => parseWorkspaceYaml(diagnosticWorkspace.replace("database: vector_database", 'database: " "')))
|
|
.toThrow(/database/i);
|
|
expect(() => parseWorkspaceYaml(diagnosticWorkspace.replace("schema: vectors", 'schema: " "')))
|
|
.toThrow(/schema/i);
|
|
expect(() => parseWorkspaceYaml(diagnosticWorkspace.replace("method: POST", "method: PATCH")))
|
|
.toThrow(/method/i);
|
|
expect(() => parseWorkspaceYaml(diagnosticWorkspace.replace(" distance: distance", " distance: distance\n extra: ignored")))
|
|
.toThrow(/unrecognized key/i);
|
|
});
|
|
|
|
test("serializes canonical YAML that parses back to the same workspace", () => {
|
|
const workspace = parseWorkspaceYaml(validYaml);
|
|
const serialized = serializeWorkspaceYaml(workspace);
|
|
|
|
expect(serializeWorkspaceYaml(parseWorkspaceYaml(serialized))).toBe(serialized);
|
|
expect(parseWorkspaceYaml(serialized)).toEqual(workspace);
|
|
});
|