// P1 two-node e2e, driven entirely through cli/host.js (bare hosts, no node):
// node A serves a directory → node B mirrors it → bytes land byte-exact.
// Mirrors the command sequence of test/flow/foreign-mirror.test.js (approval OFF).
// Run: bare cli/e2e-mirror.js
const fs = require('bare-fs')
const path = require('bare-path')
const os = require('bare-os')
const b4a = require('b4a')
const { createHost } = require('./host')
let failed = false
function ok (cond, msg) { console.log((cond ? ' ok ' : ' FAIL ') + msg); if (!cond) failed = true }
function tmp (label) {
const d = path.join(os.tmpdir(), 'mirall-e2e-' + label + '-' + Math.floor(Math.random() * 1e9))
fs.mkdirSync(d, { recursive: true })
return d
}
;(async () => {
// Local 3-node DHT so the two peers discover each other off the public DHT.
const createTestnet = (await import('hyperdht/testnet.js')).default
const testnet = await createTestnet(3)
const boot = testnet.bootstrap
const A = createHost({ storage: tmp('A'), downloads: tmp('Adl'), dhtBootstrap: boot })
const B = createHost({ storage: tmp('B'), downloads: tmp('Bdl'), dhtBootstrap: boot })
try {
await A.ready; await B.ready
await A.request('profile:set', { displayName: 'Alice', avatar: null })
await B.request('profile:set', { displayName: 'Bob', avatar: null })
ok(true, 'both peers booted headless under bare + profiled')
// Connect in a space (approval off — matches foreign-mirror.test.js's connectInSpace).
const space = await A.request('space:create', { name: 'E2E' })
const spaceId = space.spaceId
const invite = await A.request('space:invite', { spaceId })
const aSawB = A.waitFor('event:member-joined', (m) => m.spaceId === spaceId, 120000)
const bSawA = B.waitFor('event:member-joined', (m) => m.spaceId === spaceId, 120000)
await B.request('space:join', { inviteCode: invite })
await Promise.all([aSawB, bSawA])
ok(true, 'A + B connected in space ' + spaceId)
const aKey = (await A.request('profile:get')).publicKey
// A serves an owned folder with two files.
const share = await A.request('share:create', { spaceId, name: 'Photos' })
const folder = tmp('src')
const picBytes = b4a.alloc(20 * 1024)
for (let i = 0; i < picBytes.length; i++) picBytes[i] = (i * 11 + 13) & 0xff
fs.writeFileSync(path.join(folder, 'pic.bin'), picBytes)
fs.writeFileSync(path.join(folder, 'readme.txt'), 'hello mirror')
const scanDone = A.waitFor('event:owned-folder-scan-completed', (m) => m.shareId === share.id, 60000)
await A.request('owned-folder:mount', { spaceId, shareId: share.id, mountPath: folder })
await scanDone
ok(true, 'A published the owned folder (pic.bin 20KB + readme.txt)')
// B sees the share and mirrors it to a local dir.
await B.until('share:list', { spaceId }, (list) => list.some((s) => s.id === share.id))
const mirrorDir = tmp('mirror')
const active = B.waitFor('event:foreign-folder-mount-status',
(m) => m.shareId === share.id && m.status === 'active', 90000)
await B.request('foreign-folder:mount', { spaceId, shareId: share.id, ownerKey: aKey, mountPath: mirrorDir })
await active
ok(true, 'B mounted the mirror (status active)')
// Wait until the mirror's materialize tick reports pic.bin synced.
await B.until('share:list-files', { spaceId, ownerKey: aKey, shareId: share.id },
(f) => f && f.entries && f.entries.find((e) => e.relPath === 'pic.bin') &&
f.entries.find((e) => e.relPath === 'pic.bin').status === 'synced', { ms: 60000 })
// The real proof: bytes on B's disk, byte-exact.
const gotPic = path.join(mirrorDir, 'pic.bin')
const gotTxt = path.join(mirrorDir, 'readme.txt')
ok(fs.existsSync(gotPic), 'pic.bin materialized on B')
ok(fs.existsSync(gotPic) && b4a.equals(fs.readFileSync(gotPic), picBytes), 'pic.bin bytes match source (20KB, byte-exact)')
ok(fs.existsSync(gotTxt) && b4a.toString(fs.readFileSync(gotTxt), 'utf8') === 'hello mirror', 'readme.txt content matches')
ok(!fs.readdirSync(mirrorDir).some((f) => f.endsWith('.mirall.part')), 'no leftover partial')
console.log(failed
? 'P1 E2E FAIL'
: 'P1 E2E PASS: full peer served a directory; second peer mirrored it; bytes byte-exact — all via cli/host.js under bare')
} catch (err) {
console.log('P1 E2E FAIL:', err.message)
failed = true
} finally {
try { await A.close() } catch {}
try { await B.close() } catch {}
try { await testnet.destroy() } catch {}
}
Bare.exit(failed ? 1 : 0)
})()