Files
Webklar-Kundenbereich/runner/test/index-fallback.test.js
T

108 lines
6.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import test from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, existsSync, readdirSync, statSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { createJobs } from '../src/jobs.js';
import { validateJob } from '../src/validate.js';
function setup({ files, dockerImpl }) {
const root = mkdtempSync(join(tmpdir(), 'idx-'));
const config = { giteaUrl: 'https://git.x', giteaToken: 'tok_SECRET_123456', previewsRoot: join(root, 'previews'), workRoot: join(root, 'work'), cacheRoot: join(root, 'cache'), minFreeBytes: 1000, buildTimeoutMs: 900000 };
const git = async ({ dir }) => { for (const [f, c] of Object.entries(files)) { mkdirSync(join(dir, f, '..'), { recursive: true }); writeFileSync(join(dir, f), c); } mkdirSync(join(dir, '.git'), { recursive: true }); writeFileSync(join(dir, '.git', 'config'), 'x'); };
const docker = { run: async (args) => (dockerImpl ? dockerImpl(args) : { code: 0 }) };
const jobs = createJobs({ config, docker, git, mem: () => 1e10, fs: { chownR: async () => {} }, setTimer: () => {} });
return { config, jobs, out: join(config.previewsRoot, 'demo') };
}
const job = (o = {}) => ({ sub: 'demo', repo: 'own/rep', sha: 'abcdef1', branch: 'main', mode: 'auto', env: {}, ...o });
const wait = async (jobs, id) => { for (let i = 0; i < 400; i++) { const r = jobs.get(id); if (r.state === 'done' || r.state === 'failed') return r; await new Promise((r2) => setTimeout(r2, 5)); } throw new Error('timeout'); };
const workOf = (args) => args.find((a) => a.endsWith(':/work')).split(':')[0];
test('Doener-Fall: nur Doener_Nation_Website.html ⇒ index.html ist Byte-Kopie, Original bleibt', async () => {
const html = Buffer.from('<!doctype html><title>Döner</title>äö\n');
const s = setup({ files: { 'Doener_Nation_Website.html': html, '.webklar-preview.json': '{}' } });
const r = await wait(s.jobs, s.jobs.submit(job()));
assert.equal(r.state, 'done');
assert.deepEqual(readFileSync(join(s.out, 'index.html')), html);
assert.deepEqual(readFileSync(join(s.out, 'Doener_Nation_Website.html')), html);
assert.equal(statSync(join(s.out, 'index.html')).mode & 0o777, 0o644);
});
test('vorhandene index.html bleibt unberührt', async () => {
const s = setup({ files: { 'index.html': 'ORIG', 'home.html': 'HOME' } });
await wait(s.jobs, s.jobs.submit(job()));
assert.equal(readFileSync(join(s.out, 'index.html'), 'utf8'), 'ORIG');
});
test('bevorzugter Name gewinnt, sonst größte Datei', async () => {
let s = setup({ files: { 'a.html': 'aaaa', 'Main.html': 'm', 'zz.html': 'zzzzzzzz' } });
await wait(s.jobs, s.jobs.submit(job()));
assert.equal(readFileSync(join(s.out, 'index.html'), 'utf8'), 'm');
s = setup({ files: { 'a.html': 'aaaa', 'b.htm': 'bbbbbbbbb', 'c.html': 'c' } });
await wait(s.jobs, s.jobs.submit(job()));
assert.equal(readFileSync(join(s.out, 'index.html'), 'utf8'), 'bbbbbbbbb');
});
test('index-Unterordner wird Webroot; fehlender Ordner ⇒ Repo-Wurzel', async () => {
let s = setup({ files: { 'public/index.html': 'PUB', 'x.html': 'root' } });
let r = await wait(s.jobs, s.jobs.submit(job({ index: 'public' })));
assert.equal(r.state, 'done');
assert.deepEqual(readdirSync(s.out), ['index.html']);
s = setup({ files: { 'x.html': 'root' } });
await wait(s.jobs, s.jobs.submit(job({ index: 'gibtsnicht' })));
assert.equal(readFileSync(join(s.out, 'index.html'), 'utf8'), 'root');
});
test('kein HTML ⇒ Platzhalter mit Anzeigename (maskiert)', async () => {
const s = setup({ files: { 'readme.txt': 'x' } });
await wait(s.jobs, s.jobs.submit(job({ displayName: 'A & <B>' })));
const h = readFileSync(join(s.out, 'index.html'), 'utf8');
assert.match(h, /<h1>A &amp; &lt;B&gt;<\/h1>/);
assert.match(h, /<title>A &amp; &lt;B&gt; – wird vorbereitet<\/title>/);
const s2 = setup({ files: { 'readme.txt': 'x' } });
await wait(s2.jobs, s2.jobs.submit(job()));
assert.match(readFileSync(join(s2.out, 'index.html'), 'utf8'), /<h1>demo<\/h1>/);
});
test('Build ohne index.html im Ausgabeordner ⇒ Quellstand statisch + Kandidat/Platzhalter', async () => {
const s = setup({
files: { 'package.json': JSON.stringify({ scripts: { build: 'x' } }), 'seite.html': 'SEITE' },
dockerImpl: (args) => { if (args.includes('build')) { mkdirSync(join(workOf(args), 'dist'), { recursive: true }); writeFileSync(join(workOf(args), 'dist', 'app.js'), 'x'); mkdirSync(join(workOf(args), 'node_modules'), { recursive: true }); writeFileSync(join(workOf(args), 'node_modules', 'm.js'), 'x'); } return { code: 0 }; },
});
const r = await wait(s.jobs, s.jobs.submit(job()));
assert.equal(r.state, 'done'); assert.equal(r.result, 'static');
assert.equal(readFileSync(join(s.out, 'index.html'), 'utf8'), 'SEITE');
assert.ok(!existsSync(join(s.out, 'node_modules')));
const s2 = setup({
files: { 'package.json': JSON.stringify({ scripts: { build: 'x' } }) },
dockerImpl: (args) => { if (args.includes('build')) mkdirSync(join(workOf(args), 'dist'), { recursive: true }); return { code: 0 }; },
});
await wait(s2.jobs, s2.jobs.submit(job({ displayName: 'Shop' })));
assert.match(readFileSync(join(s2.out, 'index.html'), 'utf8'), /<h1>Shop<\/h1>/);
});
test('Build-Ausgabe mit index.html wird unverändert veröffentlicht', async () => {
const s = setup({
files: { 'package.json': JSON.stringify({ scripts: { build: 'x' } }) },
dockerImpl: (args) => { if (args.includes('build')) { mkdirSync(join(workOf(args), 'dist'), { recursive: true }); writeFileSync(join(workOf(args), 'dist', 'index.html'), 'B'); writeFileSync(join(workOf(args), 'dist', 'o.html'), 'O'); } return { code: 0 }; },
});
const r = await wait(s.jobs, s.jobs.submit(job()));
assert.equal(r.result, 'build');
assert.deepEqual(readdirSync(s.out).sort(), ['index.html', 'o.html']);
});
test('fehlgeschlagener Build bleibt ein Fehler (alter Stand bleibt)', async () => {
const s = setup({ files: { 'package.json': JSON.stringify({ scripts: { build: 'x' } }) }, dockerImpl: (args) => ({ code: args.includes('build') ? 1 : 0 }) });
const r = await wait(s.jobs, s.jobs.submit(job()));
assert.equal(r.state, 'failed');
});
test('validateJob: displayName optional, ≤100 Zeichen, keine Steuerzeichen', () => {
const good = { sub: 'a', repo: 'o/r', sha: 'abcdef1', branch: 'main' };
assert.equal(validateJob({ ...good, displayName: 'Döner Nation' }).job.displayName, 'Döner Nation');
assert.equal('displayName' in validateJob(good).job, false);
assert.equal(validateJob({ ...good, displayName: 'x'.repeat(101) }).ok, false);
assert.equal(validateJob({ ...good, displayName: 'a\nb' }).ok, false);
assert.equal(validateJob({ ...good, displayName: 5 }).ok, false);
});