Runner: Geruest, Eingabepruefung, Auth
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c402837df6
commit
aeb08580bb
7 files changed
+296
No files matched your search
@@ -0,0 +1,120 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { writeFileSync, mkdtempSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { createApiServer, readMemAvailable } from '../src/server.js';
|
||||
import { loadConfig } from '../src/config.js';
|
||||
import { validateJob } from '../src/validate.js';
|
||||
|
||||
|
||||
const config = { ...loadConfig({ PREVIEW_RUNNER_TOKEN: 'geheim' }) };
|
||||
const submitted = [];
|
||||
const jobs = {
|
||||
submit: (j) => { submitted.push(j); return { runId: 'r1' }; },
|
||||
get: (id) => (id === 'r1' ? { runId: 'r1', state: 'building' } : null),
|
||||
queueLength: () => 0,
|
||||
};
|
||||
const stopped = [];
|
||||
const dev = {
|
||||
ensure: async (sub) => ({ sub, state: 'starting' }),
|
||||
stop: async (sub) => { stopped.push(sub); },
|
||||
list: () => [],
|
||||
};
|
||||
|
||||
async function withServer(cfg, fn) {
|
||||
const srv = createApiServer({ config: cfg, jobs, dev, mem: () => 123 });
|
||||
await new Promise((r) => srv.listen(0, '127.0.0.1', r));
|
||||
const base = `http://127.0.0.1:${srv.address().port}`;
|
||||
try { await fn(base); } finally { await new Promise((r) => srv.close(r)); }
|
||||
}
|
||||
const auth = { Authorization: 'Bearer geheim', 'Content-Type': 'application/json' };
|
||||
const good = { sub: 'demo', repo: 'JUSN/demo', sha: 'abcdef1', branch: 'main' };
|
||||
|
||||
test('loadConfig: Vorgaben', () => {
|
||||
const c = loadConfig({});
|
||||
assert.equal(c.baseHost, 'project.webklar.com');
|
||||
assert.equal(c.workRoot, '/srv/webklar-preview-runner/work');
|
||||
assert.equal(c.cacheRoot, '/srv/webklar-preview-runner/cache');
|
||||
assert.equal(c.previewsRoot, '/var/www/previews');
|
||||
assert.equal(c.apiPort, 8080);
|
||||
assert.equal(c.proxyPort, 8081);
|
||||
assert.equal(c.minFreeBytes, 1.5 * 1024 ** 3);
|
||||
assert.equal(c.buildTimeoutMs, 900000);
|
||||
assert.equal(c.devIdleMs, 1200000);
|
||||
assert.equal(c.devMax, 3);
|
||||
assert.equal(c.devReadyMs, 180000);
|
||||
assert.equal(c.token, '');
|
||||
});
|
||||
|
||||
test('401 ohne/mit falschem Token und bei leerem konfiguriertem Token', async () => {
|
||||
await withServer(config, async (base) => {
|
||||
assert.equal((await fetch(`${base}/status`)).status, 401);
|
||||
assert.equal((await fetch(`${base}/status`, { headers: { Authorization: 'Bearer falsch' } })).status, 401);
|
||||
});
|
||||
await withServer({ ...config, token: '' }, async (base) => {
|
||||
assert.equal((await fetch(`${base}/status`, { headers: { Authorization: 'Bearer ' } })).status, 401);
|
||||
});
|
||||
});
|
||||
|
||||
test('GET /status', async () => {
|
||||
await withServer(config, async (base) => {
|
||||
const r = await fetch(`${base}/status`, { headers: auth });
|
||||
assert.equal(r.status, 200);
|
||||
assert.deepEqual(await r.json(), { dev: [], queue: 0, memAvailable: 123 });
|
||||
});
|
||||
});
|
||||
|
||||
test('POST /jobs/build: 400 bei ungültiger Eingabe, 200 bei gültiger', async () => {
|
||||
await withServer(config, async (base) => {
|
||||
for (const bad of [{ sub: '../x' }, { repo: 'a/b;rm' }, { sha: 'xyz' }]) {
|
||||
const r = await fetch(`${base}/jobs/build`, { method: 'POST', headers: auth, body: JSON.stringify({ ...good, ...bad }) });
|
||||
assert.equal(r.status, 400);
|
||||
}
|
||||
const ok = await fetch(`${base}/jobs/build`, { method: 'POST', headers: auth, body: JSON.stringify(good) });
|
||||
assert.equal(ok.status, 200);
|
||||
assert.deepEqual(await ok.json(), { runId: 'r1' });
|
||||
assert.equal(submitted[0].sub, 'demo');
|
||||
const nojson = await fetch(`${base}/jobs/build`, { method: 'POST', headers: auth, body: '{kaputt' });
|
||||
assert.equal(nojson.status, 400);
|
||||
});
|
||||
});
|
||||
|
||||
test('GET /jobs/:runId, Dev-Start/Stop', async () => {
|
||||
await withServer(config, async (base) => {
|
||||
assert.equal((await fetch(`${base}/jobs/r1`, { headers: auth })).status, 200);
|
||||
assert.equal((await fetch(`${base}/jobs/nix`, { headers: auth })).status, 404);
|
||||
const s = await fetch(`${base}/dev/demo/start`, { method: 'POST', headers: auth, body: JSON.stringify(good) });
|
||||
assert.equal(s.status, 200);
|
||||
assert.equal((await fetch(`${base}/dev/..x/start`, { method: 'POST', headers: auth, body: JSON.stringify(good) })).status, 400);
|
||||
const t = await fetch(`${base}/dev/demo/stop`, { method: 'POST', headers: auth });
|
||||
assert.equal(t.status, 200);
|
||||
assert.deepEqual(stopped, ['demo']);
|
||||
});
|
||||
});
|
||||
|
||||
test('Body über 256 KB ⇒ 413', async () => {
|
||||
await withServer(config, async (base) => {
|
||||
const r = await fetch(`${base}/jobs/build`, { method: 'POST', headers: auth, body: JSON.stringify({ ...good, x: 'a'.repeat(300 * 1024) }) });
|
||||
assert.equal(r.status, 413);
|
||||
});
|
||||
});
|
||||
|
||||
test('validateJob: env, index, mode', () => {
|
||||
assert.equal(validateJob({ ...good, mode: 'dev', index: 'src/a.html', env: { A_B: 'x' } }).ok, true);
|
||||
assert.equal(validateJob({ ...good, mode: 'off' }).ok, false);
|
||||
assert.equal(validateJob({ ...good, index: '../etc' }).ok, false);
|
||||
assert.equal(validateJob({ ...good, index: '/abs' }).ok, false);
|
||||
assert.equal(validateJob({ ...good, env: { 'a-b': 'x' } }).ok, false);
|
||||
assert.equal(validateJob({ ...good, env: { A: 'x'.repeat(4097) } }).ok, false);
|
||||
const many = Object.fromEntries(Array.from({ length: 31 }, (_, i) => [`V${i}`, '1']));
|
||||
assert.equal(validateJob({ ...good, env: many }).ok, false);
|
||||
assert.equal(validateJob({ ...good, branch: 'a b' }).ok, false);
|
||||
assert.equal(validateJob(null).ok, false);
|
||||
});
|
||||
|
||||
test('readMemAvailable liest MemAvailable in Bytes', () => {
|
||||
const p = join(mkdtempSync(join(tmpdir(), 'mem-')), 'meminfo');
|
||||
writeFileSync(p, 'MemTotal: 8000000 kB\nMemFree: 100000 kB\nMemAvailable: 2048000 kB\n');
|
||||
assert.equal(readMemAvailable(p), 2048000 * 1024);
|
||||
});
|
||||
Reference in new issue
Block a user