All checks were successful
Quality gates / quality (pull_request) Successful in 1m30s
93 lines
4.6 KiB
JavaScript
93 lines
4.6 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { spawnSync } from 'node:child_process';
|
|
import { chmod, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
import { join } from 'node:path';
|
|
import { tmpdir } from 'node:os';
|
|
|
|
const script = new URL('../scripts/bootstrap_selfhost_smolvlm.sh', import.meta.url).pathname;
|
|
|
|
test('self-host bootstrap reports immutable source and model receipts', () => {
|
|
const result = spawnSync('bash', [script, 'receipt'], { encoding: 'utf8' });
|
|
|
|
assert.equal(result.status, 0, result.stderr);
|
|
assert.match(result.stdout, /llama\.cpp commit: [0-9a-f]{40}/);
|
|
assert.match(result.stdout, /SmolVLM2-2\.2B-Instruct-Q4_K_M\.gguf sha256: [0-9a-f]{64}/);
|
|
assert.match(result.stdout, /mmproj-SmolVLM2-2\.2B-Instruct-Q8_0\.gguf sha256: [0-9a-f]{64}/);
|
|
assert.match(result.stdout, /bind address: 127\.0\.0\.1:8080/);
|
|
});
|
|
|
|
test('self-host bootstrap rejects model files that do not match pinned hashes', () => {
|
|
const result = spawnSync('bash', [script, 'verify'], {
|
|
encoding: 'utf8',
|
|
env: { ...process.env, TIMMY_SELFHOST_ROOT: '/tmp/timmy-missing-bootstrap' },
|
|
});
|
|
|
|
assert.notEqual(result.status, 0);
|
|
assert.match(result.stderr, /Run .* install|Missing required file/);
|
|
});
|
|
|
|
test('self-host bootstrap completes the pinned private worker lifecycle from an empty directory', async () => {
|
|
const sandbox = await mkdtemp(join(tmpdir(), 'timmy-bootstrap-'));
|
|
const bin = join(sandbox, 'bin');
|
|
const root = join(sandbox, 'worker');
|
|
spawnSync('mkdir', ['-p', bin]);
|
|
const commands = join(sandbox, 'commands.log');
|
|
const tools = {
|
|
git: `#!/bin/sh\nprintf 'git %s\\n' "$*" >> "$COMMAND_LOG"\nif [ "$1" = clone ]; then mkdir -p "$3/.git"; fi\n`,
|
|
cmake: `#!/bin/sh\nprintf 'cmake %s\\n' "$*" >> "$COMMAND_LOG"\nbuild=''; prev=''; for arg in "$@"; do [ "$prev" = --build ] && build="$arg"; prev="$arg"; done\nif [ -n "$build" ]; then mkdir -p "$build/bin"; printf '#!/bin/sh\\n' > "$build/bin/llama-server"; chmod +x "$build/bin/llama-server"; fi\n`,
|
|
curl: `#!/bin/sh\nprintf 'curl %s\\n' "$*" >> "$COMMAND_LOG"\nout=''; prev=''; for arg in "$@"; do { [ "$prev" = -o ] || [ "$prev" = --output ]; } && out="$arg"; prev="$arg"; done\ncase "$out" in *mmproj*) printf 'mmproj\\n' > "$out";; *) printf 'model\\n' > "$out";; esac\n`,
|
|
};
|
|
for (const [name, contents] of Object.entries(tools)) {
|
|
await writeFile(join(bin, name), contents);
|
|
await chmod(join(bin, name), 0o755);
|
|
}
|
|
|
|
const result = spawnSync('bash', [script, 'install'], {
|
|
encoding: 'utf8',
|
|
env: {
|
|
...process.env,
|
|
PATH: `${bin}:${process.env.PATH}`,
|
|
COMMAND_LOG: commands,
|
|
TIMMY_SELFHOST_ROOT: root,
|
|
TIMMY_MODEL_SHA256: '98ad61a25e3683b6adf2474b01bbe1c27de6aad2ce3a80ff4140fe473c14e691',
|
|
TIMMY_MMPROJ_SHA256: 'ce52f16b076dcb922c667c08d62881c85fa26aca7cc60394050d5bb1153b7276',
|
|
},
|
|
});
|
|
|
|
assert.equal(result.status, 0, result.stderr);
|
|
const log = await readFile(commands, 'utf8');
|
|
assert.match(log, /git clone https:\/\/github\.com\/ggml-org\/llama\.cpp/);
|
|
assert.match(log, /checkout --detach 6d05498314db1b57f81c271080018aa2d0b89be9/);
|
|
assert.match(log, /curl .*SmolVLM2-2\.2B-Instruct-Q4_K_M\.gguf/);
|
|
assert.match(result.stdout, /Pinned model files verified/);
|
|
|
|
const fakeServer = join(root, 'llama.cpp', 'build', 'bin', 'llama-server');
|
|
await writeFile(fakeServer, `#!/usr/bin/env python3
|
|
import argparse, json
|
|
from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
parser = argparse.ArgumentParser(add_help=False)
|
|
parser.add_argument('--host'); parser.add_argument('--port', type=int)
|
|
args, _ = parser.parse_known_args()
|
|
class Handler(BaseHTTPRequestHandler):
|
|
def do_GET(self):
|
|
body = json.dumps({'data': [{'id': 'SmolVLM2-2.2B-Instruct'}]}).encode()
|
|
self.send_response(200); self.send_header('Content-Type', 'application/json'); self.end_headers(); self.wfile.write(body)
|
|
def log_message(self, *_): pass
|
|
HTTPServer((args.host, args.port), Handler).serve_forever()
|
|
`);
|
|
await chmod(fakeServer, 0o755);
|
|
const lifecycleEnv = {
|
|
...process.env,
|
|
TIMMY_SELFHOST_ROOT: root,
|
|
TIMMY_MODEL_PORT: String(19000 + process.pid % 1000),
|
|
TIMMY_MODEL_SHA256: '98ad61a25e3683b6adf2474b01bbe1c27de6aad2ce3a80ff4140fe473c14e691',
|
|
TIMMY_MMPROJ_SHA256: 'ce52f16b076dcb922c667c08d62881c85fa26aca7cc60394050d5bb1153b7276',
|
|
};
|
|
for (const command of ['start', 'health', 'stop']) {
|
|
const commandResult = spawnSync('bash', [script, command], { encoding: 'utf8', env: lifecycleEnv });
|
|
assert.equal(commandResult.status, 0, `${command}: ${commandResult.stderr}`);
|
|
}
|
|
await rm(sandbox, { recursive: true, force: true });
|
|
});
|