Files
SubMiner/scripts/package-bun-source.test.ts
T

154 lines
5.2 KiB
TypeScript

import { describe, expect, test } from 'bun:test';
import { createHash } from 'node:crypto';
import fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import {
downloadArchive,
parseRegisteredRepositories,
parseSourceManifest,
validateBunPins,
validateRuntimeAlignment,
} from './package-bun-source.mjs';
const projectRoot = path.resolve(import.meta.dir, '..');
describe('Bun corresponding-source manifest', () => {
test('removes partial downloads when placing a valid archive fails', async () => {
const cacheDir = await fs.mkdtemp(path.join(os.tmpdir(), 'subminer-bun-source-test-'));
try {
const payload = new Uint8Array([1, 2, 3]);
const source = {
name: 'fixture',
repository: 'example/fixture',
revision: 'a'.repeat(40),
sha256: createHash('sha256').update(payload).digest('hex'),
};
const archivePath = path.join(cacheDir, `${source.name}-${source.revision}.tar.gz`);
await expect(
downloadArchive(source, cacheDir, async () => {
await fs.mkdir(archivePath);
return { ok: true, status: 200, body: new Response(payload).body };
}),
).rejects.toMatchObject({ syscall: 'rename' });
const entries = await fs.readdir(cacheDir);
expect(entries.filter((entry) => entry.includes('.download-'))).toEqual([]);
} finally {
await fs.rm(cacheDir, { recursive: true, force: true });
}
});
test('pins the source to the revision reported by the distributed binary', async () => {
const manifest = parseSourceManifest(
JSON.parse(
await fs.readFile(path.join(projectRoot, 'build/bun-source-manifest.json'), 'utf8'),
),
);
expect(manifest.version).toBe('1.3.5');
expect(manifest.bunRevision).toBe('1e86cebd74a5723e818b5c0555276b646bcf0e4c');
expect(manifest.releaseTagCommit).toBe('fa5a5bbe556a4bda5bde77b4013aa6c3bb4ec9ab');
expect(manifest.sources.find((source) => source.name === 'WebKit')?.revision).toBe(
'6d0f3aac0b817cc01a846b3754b21271adedac12',
);
expect(manifest.sources.find((source) => source.name === 'tinycc')?.revision).toBe(
'29985a3b59898861442fa3b43f663fc1af2591d7',
);
});
test('parses commit and tag registrations from Bun CMake', () => {
const registrations = parseRegisteredRepositories(`
register_repository(
NAME tinycc
REPOSITORY oven-sh/tinycc
COMMIT
# A comment between the field and its value is valid CMake.
29985a3b59898861442fa3b43f663fc1af2591d7
)
register_repository(
NAME brotli
REPOSITORY google/brotli
TAG v1.1.0
)
`);
expect(registrations.get('tinycc')).toEqual({
repository: 'oven-sh/tinycc',
kind: 'commit',
reference: '29985a3b59898861442fa3b43f663fc1af2591d7',
});
expect(registrations.get('brotli')).toEqual({
repository: 'google/brotli',
kind: 'tag',
reference: 'v1.1.0',
});
});
test('rejects stale runtime or package-manager pins', async () => {
const manifest = parseSourceManifest(
JSON.parse(
await fs.readFile(path.join(projectRoot, 'build/bun-source-manifest.json'), 'utf8'),
),
);
const runtimeManifest = {
version: manifest.version,
bunRevision: manifest.bunRevision,
correspondingSourceAsset: manifest.archiveName,
};
expect(() =>
validateRuntimeAlignment(manifest, { packageManager: 'bun@1.3.5' }, runtimeManifest),
).not.toThrow();
expect(() =>
validateRuntimeAlignment(manifest, { packageManager: 'bun@1.3.6' }, runtimeManifest),
).toThrow('package.json must pin bun@1.3.5');
expect(() =>
validateRuntimeAlignment(
manifest,
{ packageManager: 'bun@1.3.5' },
{
...runtimeManifest,
correspondingSourceAsset: 'stale.tar.gz',
},
),
).toThrow('correspondingSourceAsset does not match');
});
test('rejects drift in CMake dependency and WebKit pins', async () => {
const manifest = parseSourceManifest(
JSON.parse(
await fs.readFile(path.join(projectRoot, 'build/bun-source-manifest.json'), 'utf8'),
),
);
const registrations = manifest.sources
.filter((source) => source.destination.startsWith('bun/vendor/') && source.name !== 'WebKit')
.map(
(source) => `register_repository(
NAME ${source.name}
REPOSITORY ${source.repository}
${source.upstreamReference ? 'TAG' : 'COMMIT'} ${source.upstreamReference ?? source.revision}
)`,
)
.join('\n');
expect(() =>
validateBunPins(
manifest,
[registrations],
'set(WEBKIT_VERSION 6d0f3aac0b817cc01a846b3754b21271adedac12)',
),
).not.toThrow();
expect(() =>
validateBunPins(
manifest,
[registrations.replace('29985a3b59898861442fa3b43f663fc1af2591d7', '0'.repeat(40))],
'set(WEBKIT_VERSION 6d0f3aac0b817cc01a846b3754b21271adedac12)',
),
).toThrow('revision mismatch for tinycc');
expect(() =>
validateBunPins(manifest, [registrations], `set(WEBKIT_VERSION ${'0'.repeat(40)})`),
).toThrow('WebKit revision does not match');
});
});