// Testet die Shell-Skripte: Syntax + Single-Server-Invarianten. import { test } from "node:test"; import assert from "node:assert/strict"; import { execFileSync } from "node:child_process"; import { readdirSync } from "node:fs"; import { join } from "node:path"; import { repoRoot, readRepoFile } from "./helpers.mjs"; const shellScripts = readdirSync(repoRoot).filter((f) => f.endsWith(".sh")); for (const script of shellScripts) { test(`bash -n: ${script} hat gültige Syntax`, () => { // execFileSync wirft bei Exit != 0 (Syntaxfehler). execFileSync("bash", ["-n", join(repoRoot, script)]); }); } test("Dual-GPU-Skripte sind entfernt", () => { for (const gone of ["start-coder.sh", "start-judge.sh", "start-servers.sh"]) { assert.ok(!shellScripts.includes(gone), `${gone} sollte in der Single-GPU-Welt entfernt sein`); } }); test("start-coding-server.sh nutzt eine GPU und registriert Alias coding_model", () => { const s = readRepoFile("start-coding-server.sh"); assert.match(s, /--alias\s+"\$\{MODEL_ALIAS\}"/); assert.match(s, /MODEL_ALIAS="coding_model"/); assert.match(s, /device=\$\{GPU_DEVICE\}/, "GPU muss konfigurierbar/einzeln sein"); }); test("stop-coding-server.sh stoppt den Single-Container", () => { assert.match(readRepoFile("stop-coding-server.sh"), /coding_model/); }); test("status-coding-server.sh prüft den Single-Container", () => { assert.match(readRepoFile("status-coding-server.sh"), /coding_model/); }); test("install-Skript deployt settings.json mit vorherigem Backup", () => { const s = readRepoFile("install_servers_and_pi_coder_extension.sh"); assert.match(s, /settings\.json\.bak/, "muss settings.json vor dem Überschreiben sichern"); assert.match(s, /cp "\$REPO\/settings\.json"/, "muss settings.json aus dem Repo deployen"); assert.match(s, /cp "\$REPO\/models\.json"/); assert.match(s, /pi-coder-judge-extension\.ts/); });