Files
SubMiner/scripts/aur-release-download.test.ts
T

94 lines
3.4 KiB
TypeScript

import assert from 'node:assert/strict';
import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import { test } from 'bun:test';
test.each([false, true])(
'AUR downloads handle empty release metadata, unavailable=%s',
async (unavailable) => {
const workflow = await readFile(
new URL('../.github/workflows/release.yml', import.meta.url),
'utf8',
);
const step = workflow
.split(' - name: Download release assets for AUR\n')[1]
?.split('\n - name:')[0];
const script = step?.split(' run: |\n')[1]?.replace(/^ /gm, '');
assert.ok(script, 'AUR download step must have a shell script');
const workspace = await mkdtemp(path.join(os.tmpdir(), 'subminer-aur-download-'));
const requests: string[] = [];
const files = new Map([
['SubMiner-0.20.0.AppImage', 'appimage bytes'],
['subminer', 'launcher bytes'],
['subminer-assets.tar.gz', 'optional assets bytes'],
]);
const server = Bun.serve({
hostname: '127.0.0.1',
port: 0,
fetch(request) {
const pathname = new URL(request.url).pathname;
requests.push(pathname);
if (unavailable || requests.length === 1) return new Response('try again', { status: 503 });
const name = pathname.split('/').at(-1);
const body = name ? files.get(name) : undefined;
return new Response(body ?? 'not found', { status: body ? 200 : 404 });
},
});
try {
const bin = path.join(workspace, 'bin');
await mkdir(bin);
await writeFile(
path.join(bin, 'gh'),
'#!/bin/sh\necho "no assets to download" >&2\nexit 1\n',
{ mode: 0o755 },
);
const output = path.join(workspace, 'output');
const proc = Bun.spawn(['bash', '-c', script], {
cwd: workspace,
env: {
...process.env,
PATH: `${bin}${path.delimiter}${process.env.PATH}`,
RELEASE_VERSION: 'v0.20.0',
GITHUB_SERVER_URL: server.url.origin,
GITHUB_REPOSITORY: 'ksyasuda/SubMiner',
GITHUB_OUTPUT: output,
},
stdout: 'pipe',
stderr: 'pipe',
});
const [status, stderr, stdout] = await Promise.all([
proc.exited,
new Response(proc.stderr).text(),
new Response(proc.stdout).text(),
]);
assert.equal(status, 0, stderr);
if (unavailable) {
assert.equal(requests.length, 4, 'failed downloads stop after three retries');
assert.match(await readFile(output, 'utf8'), /^skip=true$/m);
assert.match(stdout, /::warning::Unable to download/);
await assert.rejects(
readFile(path.join(workspace, '.tmp/aur-release-assets/SubMiner-0.20.0.AppImage')),
{ code: 'ENOENT' },
);
return;
}
for (const [name, body] of files) {
assert.equal(
await readFile(path.join(workspace, '.tmp/aur-release-assets', name), 'utf8'),
body,
);
assert.ok(requests.includes(`/ksyasuda/SubMiner/releases/download/v0.20.0/${name}`));
}
assert.equal(requests.length, 4, 'the first failed download must be retried');
assert.match(await readFile(output, 'utf8'), /^skip=false$/m);
} finally {
server.stop(true);
await rm(workspace, { recursive: true, force: true });
}
},
15_000,
);