import test from 'brittle'
import fs from '#node:fs'
import path from '#node:path'
import { mkdtempSync, writeFileSync, mkdirSync } from '#node:fs'
import { tmpdir } from '#node:os'
import { parsePointer, selectMissingOids, discoverMirrorTargets, runOverlayMirror } from '../lib/overlay-mirror.js'
const deps = { fs, path }
const OID = 'a'.repeat(64)
const OID2 = 'b'.repeat(64)
test('parsePointer reads a hyper-overlay v1 pointer (strips blake2b: prefix)', (t) => {
const p = parsePointer('hyper-overlay v1\noid blake2b:' + OID + '\nsize 5878386\n')
t.alike(p, { oid: OID, size: 5878386 }, 'parsed oid + size')
t.alike(parsePointer('hyper-overlay v1\noid ' + OID + '\nsize 10'), { oid: OID, size: 10 }, 'oid without prefix also accepted')
t.is(parsePointer('\x00\x01 binary png bytes'), null, 'real binary (not a pointer) → null')
t.is(parsePointer('hyper-overlay v1\n'), null, 'magic but no oid → null')
})
test('selectMissingOids dedups + skips oids already present in the spool', (t) => {
const spool = mkdtempSync(path.join(tmpdir(), 'om-spool-'))
writeFileSync(path.join(spool, OID), 'already here')
const pointers = [
{ path: 'a.png', oid: OID, size: 1 }, // present → skip
{ path: 'b.png', oid: OID2, size: 2 }, // missing → keep
{ path: 'c.png', oid: OID2, size: 2 } // dup of b → skip
]
const missing = selectMissingOids(pointers, spool, deps)
t.is(missing.length, 1, 'only the one missing, de-duplicated')
t.is(missing[0].oid, OID2, 'the missing oid')
})
test('discoverMirrorTargets keeps repos published elsewhere, skips own + non-overlay', async (t) => {
const self = 'd'.repeat(64)
const other = 'e'.repeat(64)
const cfgs = {
'hyper-tps': { peerServerKey: other }, // published elsewhere → mirror it
'my-app': { peerServerKey: self }, // we publish it → skip
'plain-repo': null // no overlay.json → skip
}
const targets = await discoverMirrorTargets({
repos: ['hyper-tps', 'my-app', 'plain-repo'],
selfPubkeyHex: self,
readOverlayJson: async (r) => cfgs[r] // async (git read) in production
})
t.is(targets.length, 1, 'one mirror target')
t.alike(targets[0], { repo: 'hyper-tps', peerServerKey: other }, 'the foreign-published repo')
})
test('runOverlayMirror fetches only missing oids into <spool>/<oid> and summarizes', async (t) => {
const spool = mkdtempSync(path.join(tmpdir(), 'om-run-'))
writeFileSync(path.join(spool, OID), 'present') // already mirrored
const fetched = []
const summary = await runOverlayMirror({
targets: [{ repo: 'hyper-tps', peerServerKey: 'e'.repeat(64) }],
mirrorSpool: spool,
listPointers: async () => ([
{ path: 'a.png', oid: OID, size: 1 }, // present → not fetched
{ path: 'b.glb', oid: OID2, size: 2 } // missing → fetched
]),
fetchOid: async (peer, oid, dest) => { fetched.push({ peer, oid, dest }); return true },
deps
})
t.is(fetched.length, 1, 'fetched only the missing oid')
t.is(fetched[0].oid, OID2, 'the missing oid')
t.is(fetched[0].dest, path.join(spool, OID2), 'destination is content-addressed <spool>/<oid>')
t.is(fetched[0].peer, 'e'.repeat(64), 'fetched from the publisher')
t.alike(summary[0], { repo: 'hyper-tps', fetched: 1, missing: 1, total: 2 }, 'summary')
})