test(ops): verify Docker persistence, browser workflows and document deployment
This commit is contained in:
1 parent
a58516e424
commit
8fa63415f1
35 files changed
+1105
No files matched your search
@@ -0,0 +1,107 @@
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { randomBytes } from 'node:crypto';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
// Isolated disposable Compose project. Never targets the user's deployment or volumes.
|
||||
const project = `hamham-check-${randomBytes(4).toString('hex')}`;
|
||||
const port = process.env.VERIFY_PORT ?? '3200';
|
||||
const origin = `http://localhost:${port}`;
|
||||
const password = randomBytes(30).toString('base64url');
|
||||
const env = {
|
||||
...process.env,
|
||||
POSTGRES_PASSWORD: randomBytes(32).toString('hex'),
|
||||
HOST_PORT: port,
|
||||
APP_ORIGIN: origin,
|
||||
COOKIE_SECURE: 'false',
|
||||
};
|
||||
const compose = (args: string[], input?: string | Buffer) =>
|
||||
execFileSync('docker', ['compose', '-p', project, ...args], {
|
||||
env,
|
||||
input,
|
||||
maxBuffer: 32 * 1024 * 1024,
|
||||
stdio: input === undefined ? ['ignore', 'pipe', 'inherit'] : ['pipe', 'pipe', 'inherit'],
|
||||
});
|
||||
let cookie = '';
|
||||
async function request(path: string, method = 'GET', body?: unknown) {
|
||||
const response = await fetch(`${origin}/api/${path}`, {
|
||||
method,
|
||||
headers: {
|
||||
Origin: origin,
|
||||
Cookie: cookie,
|
||||
Connection: 'close',
|
||||
...(body === undefined ? {} : { 'Content-Type': 'application/json' }),
|
||||
},
|
||||
body: body === undefined ? undefined : JSON.stringify(body),
|
||||
});
|
||||
assert.ok(
|
||||
response.ok,
|
||||
`${method} ${path}: ${response.status} ${response.ok ? '' : await response.text()}`,
|
||||
);
|
||||
if (response.headers.get('set-cookie'))
|
||||
cookie = response.headers.get('set-cookie')!.split(';')[0];
|
||||
return response;
|
||||
}
|
||||
try {
|
||||
console.log(`Compose-Integrationstest: ${project} (${origin})`);
|
||||
console.log(compose(['up', '-d', '--build', '--wait', '--wait-timeout', '240']).toString());
|
||||
assert.equal(compose(['exec', '-T', 'app', 'id', '-u']).toString().trim(), '1000');
|
||||
console.log(
|
||||
compose(
|
||||
['exec', '-T', 'app', 'npm', 'run', 'admin:create', '--', 'dockercheck'],
|
||||
`${password}\n`,
|
||||
).toString(),
|
||||
);
|
||||
await request('auth/login', 'POST', { username: 'dockercheck', password });
|
||||
const raw = await readFile('public/examples/kochbuch.json', 'utf8');
|
||||
const recipes = await (
|
||||
await request('import', 'POST', { raw, format: 'json', preview: false })
|
||||
).json();
|
||||
assert.equal(recipes.length, 3);
|
||||
const imageResponse = await fetch(`${origin}/api/media`, {
|
||||
method: 'POST',
|
||||
headers: { Origin: origin, Cookie: cookie, Connection: 'close', 'Content-Type': 'image/jpeg' },
|
||||
body: await readFile('public/images/garden.jpg'),
|
||||
});
|
||||
assert.equal(imageResponse.status, 201);
|
||||
const { url: image } = await imageResponse.json();
|
||||
const before = await fetch(`${origin}${image}`, { headers: { Connection: 'close' } }).then((r) =>
|
||||
r.arrayBuffer(),
|
||||
);
|
||||
await request(`recipes/${recipes[0].id}`, 'PUT', { ...recipes[0], image });
|
||||
assert.equal((await (await request('export')).json()).recipes.length, 3);
|
||||
console.log('Admin-CLI, Login, Import, Bild-Upload, Rezeptänderung und Export: OK');
|
||||
console.log(compose(['restart']).toString());
|
||||
console.log(compose(['up', '-d', '--wait', '--wait-timeout', '120']).toString());
|
||||
const after = await fetch(`${origin}${image}`, { headers: { Connection: 'close' } }).then((r) =>
|
||||
r.arrayBuffer(),
|
||||
);
|
||||
assert.deepEqual(Buffer.from(after), Buffer.from(before));
|
||||
assert.equal((await (await request('recipes')).json()).length, 3);
|
||||
console.log('Persistenz nach Neustart: Datenbank, Sitzung und Bildbytes OK');
|
||||
const dump = compose(['exec', '-T', 'db', 'pg_dump', '-U', 'hamham', '-d', 'hamham', '-Fc']);
|
||||
compose(['exec', '-T', 'db', 'createdb', '-U', 'hamham', 'hamham_restore']);
|
||||
compose(['exec', '-T', 'db', 'pg_restore', '-U', 'hamham', '-d', 'hamham_restore'], dump);
|
||||
assert.equal(
|
||||
compose([
|
||||
'exec',
|
||||
'-T',
|
||||
'db',
|
||||
'psql',
|
||||
'-U',
|
||||
'hamham',
|
||||
'-d',
|
||||
'hamham_restore',
|
||||
'-Atc',
|
||||
'SELECT count(*) FROM recipes',
|
||||
])
|
||||
.toString()
|
||||
.trim(),
|
||||
'3',
|
||||
);
|
||||
console.log('PostgreSQL-Backup/Restore und wiederholte Migrationen: OK');
|
||||
console.log(compose(['ps']).toString());
|
||||
} finally {
|
||||
// Only the unique verification project created above is removed, including its test volumes.
|
||||
compose(['down', '-v', '--remove-orphans']);
|
||||
}
|
||||
Reference in new issue
Block a user