File size: 7,523 Bytes
cd8bd0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/**
 * TDD: GET /api/context/combos/default is a read-only shim.
 *
 * The default compression pipeline is now DERIVED from the engines map
 * (open-sse deriveDefaultPlan) rather than editable here:
 *   - GET  β†’ returns the derived default plan for the live config.
 *   - PUT  β†’ rejected with a deprecation error (not 200); body carries no stack trace.
 *
 * Auth + isolation pattern mirrors tests/unit/api/context-analytics-engine-route.test.ts:
 * - makeManagementSessionRequest() for JWT cookie auth.
 * - Temp DATA_DIR, resetDbInstance() before each test, cleanup in test.after().
 */
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";

import { makeManagementSessionRequest } from "../../helpers/managementSession.ts";
import { deriveDefaultPlan } from "@omniroute/open-sse/services/compression/deriveDefaultPlan.ts";

// ─── isolated temp DB ─────────────────────────────────────────────────────────

const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-ctx-combos-default-route-"));
const originalDataDir = process.env.DATA_DIR;
const originalJwtSecret = process.env.JWT_SECRET;

process.env.DATA_DIR = TEST_DATA_DIR;

const core = await import("../../../src/lib/db/core.ts");
const settingsDb = await import("../../../src/lib/db/settings.ts");
const compressionDb = await import("../../../src/lib/db/compression.ts");
const defaultRoute = await import("../../../src/app/api/context/combos/default/route.ts");

// ─── helpers ──────────────────────────────────────────────────────────────────

async function setupAuth(): Promise<void> {
  core.resetDbInstance();
  fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
  fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
  await settingsDb.updateSettings({
    requireLogin: true,
    setupComplete: true,
    password: "test-password-hash",
  });
}

// ─── lifecycle ────────────────────────────────────────────────────────────────

test.beforeEach(async () => {
  process.env.DATA_DIR = TEST_DATA_DIR;
  await setupAuth();
});

test.after(() => {
  if (originalDataDir === undefined) delete process.env.DATA_DIR;
  else process.env.DATA_DIR = originalDataDir;
  if (originalJwtSecret === undefined) delete process.env.JWT_SECRET;
  else process.env.JWT_SECRET = originalJwtSecret;
  core.resetDbInstance();
  fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});

// ─── tests ────────────────────────────────────────────────────────────────────

test("GET /api/context/combos/default returns the derived default plan (single-mode caveman)", async () => {
  await compressionDb.updateCompressionSettings({
    enabled: true,
    engines: { caveman: { enabled: true, level: "full" } },
  });

  const req = await makeManagementSessionRequest("http://localhost/api/context/combos/default");
  const res = await defaultRoute.GET(req);
  assert.equal(res.status, 200, `Expected 200, got ${res.status}`);

  const body = (await res.json()) as {
    mode: string;
    pipeline: Array<{ engine: string; intensity?: string }>;
  };

  // caveman alone is single-mode β†’ effective mode "standard", empty stacked pipeline.
  const expected = deriveDefaultPlan({ caveman: { enabled: true, level: "full" } }, true);
  assert.equal(body.mode, expected.mode, `expected mode ${expected.mode}`);
  assert.equal(body.mode, "standard");
  assert.deepEqual(body.pipeline, expected.stackedPipeline);
});

test("GET /api/context/combos/default returns the derived stacked pipeline (reflects enabled engines)", async () => {
  await compressionDb.updateCompressionSettings({
    enabled: true,
    engines: {
      caveman: { enabled: true, level: "full" },
      headroom: { enabled: true },
    },
  });

  const req = await makeManagementSessionRequest("http://localhost/api/context/combos/default");
  const res = await defaultRoute.GET(req);
  assert.equal(res.status, 200, `Expected 200, got ${res.status}`);

  const body = (await res.json()) as {
    mode: string;
    pipeline: Array<{ engine: string; intensity?: string }>;
  };

  const expected = deriveDefaultPlan(
    { caveman: { enabled: true, level: "full" }, headroom: { enabled: true } },
    true
  );
  assert.equal(body.mode, "stacked");
  assert.deepEqual(body.pipeline, expected.stackedPipeline);
  const engineIds = body.pipeline.map((s) => s.engine);
  assert.ok(engineIds.includes("caveman"), `expected caveman in derived pipeline, got: ${engineIds}`);
});

test("GET /api/context/combos/default returns off when master switch is disabled", async () => {
  await compressionDb.updateCompressionSettings({
    enabled: false,
    engines: { caveman: { enabled: true, level: "full" } },
  });

  const req = await makeManagementSessionRequest("http://localhost/api/context/combos/default");
  const res = await defaultRoute.GET(req);
  assert.equal(res.status, 200, `Expected 200, got ${res.status}`);

  const body = (await res.json()) as { mode: string; pipeline: unknown[] };
  assert.equal(body.mode, "off");
  assert.deepEqual(body.pipeline, []);
});

test("PUT /api/context/combos/default is deprecated and rejects writes (not 200)", async () => {
  const req = await makeManagementSessionRequest("http://localhost/api/context/combos/default", {
    method: "PUT",
    body: JSON.stringify({ engineId: "headroom", enabled: true }),
  });
  const res = await defaultRoute.PUT(req);
  assert.notEqual(res.status, 200, "PUT must no longer succeed β€” the route is read-only");
  assert.ok(res.status >= 400, `expected a 4xx deprecation status, got ${res.status}`);

  const body = (await res.json()) as { error?: { message?: string } | string };
  // The deprecation message points editors at the engines settings.
  const message =
    typeof body.error === "string" ? body.error : (body.error?.message ?? JSON.stringify(body));
  assert.match(message, /derived|engines|deprecat/i, `unexpected deprecation message: ${message}`);

  // Hard Rule #12: no raw stack trace leaks into the response body. Match the V8
  // stack-frame shape ("    at fn (file:line:col)") rather than the bare "at " token,
  // which legitimately appears in the URL inside the deprecation message.
  assert.ok(
    !/\bat\s+\S+\s+\(?\/?\S+:\d+:\d+/.test(JSON.stringify(body)),
    "error body must not contain a stack trace"
  );
  assert.ok(!/\n\s+at\s/.test(JSON.stringify(body)), "error body must not contain a stack trace");
});

test("POST /api/context/combos/default is deprecated and rejects writes (not 200)", async () => {
  const req = await makeManagementSessionRequest("http://localhost/api/context/combos/default", {
    method: "POST",
    body: JSON.stringify({ engineId: "headroom", enabled: true }),
  });
  const res = await defaultRoute.POST(req);
  assert.notEqual(res.status, 200, "POST must no longer succeed β€” the route is read-only");
  assert.ok(res.status >= 400, `expected a 4xx deprecation status, got ${res.status}`);
});