Files
bare-operating-system/packages/bare-os-coreutils/test/pear-release.test.mjs
T
2026-05-26 23:45:54 +00:00

246 lines
6.9 KiB
JavaScript

import { readFile } from 'node:fs/promises'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import test from 'brittle'
import b4a from 'b4a'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor
async function loadPearBin() {
const runtime = await readFile(path.join(__dirname, '../lib/runtime.js'), 'utf8')
const stage = await readFile(path.join(__dirname, '../lib/pear-stage.js'), 'utf8')
const release = await readFile(path.join(__dirname, '../lib/pear-release.js'), 'utf8')
const body = await readFile(path.join(__dirname, '../src/pear.js'), 'utf8')
return new AsyncFunction(
'ctx',
'argv',
`${runtime}\n${stage}\n${release}\n${body}\nif (typeof run === 'function') return await run(ctx, argv)\n`
)
}
function mkMemVfs(initial = {}) {
/** @type {Map<string, Uint8Array>} */
const files = new Map(Object.entries(initial))
const vfs = {
env: {},
files,
getcwd() {
return '/home/guest/pear-projects/my-pear-app'
},
async mkdir(p) {
void p
},
async readdir(p) {
const prefix = p.endsWith('/') ? p : p + '/'
const names = new Set()
for (const key of files.keys()) {
if (!key.startsWith(prefix)) continue
const rest = key.slice(prefix.length)
const seg = rest.split('/')[0]
if (seg) names.add(seg)
}
return [...names]
},
async stat(p) {
if (!files.has(p)) {
for (const key of files.keys()) {
if (key.startsWith(p + '/')) return { isDirectory: true, type: 'directory' }
}
throw new Error('ENOENT')
}
return { isDirectory: false, type: 'file' }
},
async readFile(p) {
if (!files.has(p)) throw new Error('ENOENT ' + p)
return files.get(p)
},
async writeFile(p, buf) {
files.set(p, buf instanceof Uint8Array ? buf : new Uint8Array(buf))
}
}
return vfs
}
function mkFakeHdms() {
const key = b4a.from('abc123')
const drive = {
key,
version: 7,
discoveryKey: b4a.from('disc'),
async flush() {}
}
/** @type {Map<string, { drive: typeof drive, writable: boolean, entry: object }>} */
const byLabel = new Map()
const hdms = {
active: true,
byLabel,
registry: { version: 1, drives: [] },
swarm: { join() {}, flush: async () => {} },
async create(ctx, label) {
byLabel.set(label, {
drive,
writable: true,
entry: { label, mode: 'writable', key: 'mockkey6' }
})
this.registry.drives.push({ label, mode: 'writable', key: 'mockkey6' })
ctx.console.log('Created ' + label)
},
async _openEntry(entry) {
byLabel.set(entry.label, {
drive,
writable: entry.mode === 'writable',
entry
})
}
}
return hdms
}
test('pear release mirrors stage to HDMS mount and writes release.json', async (t) => {
const project = '/home/guest/pear-projects/my-pear-app'
const stageDir = `${project}/.pear/stage`
const vfs = mkMemVfs({
[`${project}/.pear/stage/stage.json`]: b4a.from(
JSON.stringify({
name: 'my-pear-app',
stageDir,
entry: 'index.js',
bundleMethod: 'test'
}),
'utf8'
),
[`${project}/.pear/stage/package.json`]: b4a.from('{"name":"my-pear-app"}\n', 'utf8'),
[`${project}/.pear/stage/app.bundle.js`]: b4a.from('console.log(1)\n', 'utf8')
})
const hdms = mkFakeHdms()
const logs = []
const ctx = {
vfs,
b4a,
env: { HOME: '/home/guest', PWD: project },
identity: { state: 'unlocked' },
disk: { hdmsController: hdms },
bare: {
hypercoreIdEncoding: {
encode(buf) {
return 'z32_' + b4a.toString(buf, 'utf8')
},
decode() {
return b4a.alloc(0)
}
}
},
console: {
log(...a) {
logs.push(a.join(' '))
},
error() {},
warn() {}
}
}
const run = await loadPearBin()
await run(ctx, ['pear', 'release', '.'])
t.ok(vfs.files.has('/mnt/pear-my-pear-app/app.bundle.js'))
t.ok(vfs.files.has(`${project}/.pear/release.json`))
const rel = JSON.parse(b4a.toString(vfs.files.get(`${project}/.pear/release.json`), 'utf8'))
t.is(rel.label, 'pear-my-pear-app')
t.is(rel.latest.length, 7)
t.ok(rel.latest.pearLink.startsWith('pear://'))
t.ok(logs.some((l) => l.includes('versioned:')))
})
test('pear release requires staged tree', async (t) => {
const project = '/home/guest/pear-projects/empty'
const vfs = mkMemVfs({})
const ctx = {
vfs,
b4a,
env: { HOME: '/home/guest', PWD: project },
identity: { state: 'unlocked' },
disk: { hdmsController: mkFakeHdms() },
bare: { hypercoreIdEncoding: { encode: () => 'k', decode: () => b4a.alloc(0) } },
console: { log() {}, error() {}, warn() {} },
exitCode: 0
}
const run = await loadPearBin()
await run(ctx, ['pear', 'release', '.'])
t.is(ctx.exitCode, 1)
})
test('pear release works without ctx.bare (HDMS registry key)', async (t) => {
const project = '/home/guest/pear-projects/my-pear-app'
const stageDir = `${project}/.pear/stage`
const vfs = mkMemVfs({
[`${project}/.pear/stage/stage.json`]: b4a.from(
JSON.stringify({ name: 'my-pear-app', stageDir, entry: 'index.js' }),
'utf8'
),
[`${project}/.pear/stage/index.js`]: b4a.from('console.log(1)\n', 'utf8')
})
const hdms = mkFakeHdms()
const ctx = {
vfs,
b4a,
env: { HOME: '/home/guest', PWD: project },
identity: { state: 'unlocked' },
disk: { hdmsController: hdms },
console: { log() {}, error() {}, warn() {} }
}
const run = await loadPearBin()
await run(ctx, ['pear', 'release', '.', '--json'])
const rel = JSON.parse(b4a.toString(vfs.files.get(`${project}/.pear/release.json`), 'utf8'))
t.is(rel.latest.keyZ32, 'mockkey6')
})
test('pear seed opens existing release mount', async (t) => {
const project = '/home/guest/pear-projects/my-pear-app'
const vfs = mkMemVfs({
[`${project}/.pear/release.json`]: b4a.from(
JSON.stringify({
schema: 1,
label: 'pear-my-pear-app',
latest: {
label: 'pear-my-pear-app',
pearLink: 'pear://z32_abc123',
versionedLink: 'pear://0.7.z32_abc123',
length: 7
}
}),
'utf8'
)
})
const hdms = mkFakeHdms()
hdms.registry.drives.push({ label: 'pear-my-pear-app', mode: 'writable', key: 'mockkey6' })
const ctx = {
vfs,
b4a,
env: { HOME: '/home/guest', PWD: project },
identity: { state: 'unlocked' },
disk: { hdmsController: hdms },
bare: {
hypercoreIdEncoding: {
encode(buf) {
return 'z32_' + b4a.toString(buf, 'utf8')
},
decode() {
return b4a.alloc(0)
}
}
},
console: { log() {}, error() {}, warn() {} }
}
const run = await loadPearBin()
await run(ctx, ['pear', 'seed', '.', '--wait-ms', '0'])
t.ok(hdms.byLabel.has('pear-my-pear-app'))
})