153 lines
4.5 KiB
JavaScript
153 lines
4.5 KiB
JavaScript
import test from 'brittle'
|
|
import fs from 'fs'
|
|
import os from 'os'
|
|
import path from 'path'
|
|
import {
|
|
parsePeersPayload,
|
|
buildPeersPayload,
|
|
normalizePeerEntry,
|
|
writePeersToFile,
|
|
readPeersFromFile,
|
|
loadPeers,
|
|
savePeers,
|
|
clearPeers,
|
|
getPeersCachePath,
|
|
listSavedPeers,
|
|
} from '../client/peerCache.js'
|
|
|
|
const KEY =
|
|
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
|
|
const KEY2 =
|
|
'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
|
|
|
|
test('normalizePeerEntry accepts publicKeyHex', (t) => {
|
|
const e = normalizePeerEntry({ publicKeyHex: KEY, alias: 'prod' })
|
|
t.is(e.publicKeyHex, KEY)
|
|
t.is(e.id, KEY.slice(0, 12))
|
|
t.is(e.alias, 'prod')
|
|
})
|
|
|
|
test('normalizePeerEntry rejects invalid keys', (t) => {
|
|
t.absent(normalizePeerEntry({ publicKeyHex: 'nope' }))
|
|
t.absent(normalizePeerEntry(null))
|
|
})
|
|
|
|
test('parsePeersPayload supports versioned and legacy flat maps', (t) => {
|
|
const versioned = parsePeersPayload({
|
|
version: 1,
|
|
peers: {
|
|
[KEY.slice(0, 12)]: { publicKeyHex: KEY, alias: 'a' },
|
|
},
|
|
})
|
|
t.is(versioned[KEY.slice(0, 12)].publicKeyHex, KEY)
|
|
|
|
const flat = parsePeersPayload({
|
|
[KEY.slice(0, 12)]: { publicKeyHex: KEY, alias: 'b' },
|
|
})
|
|
t.is(flat[KEY.slice(0, 12)].alias, 'b')
|
|
})
|
|
|
|
test('buildPeersPayload wraps peers with version', (t) => {
|
|
const payload = buildPeersPayload({
|
|
[KEY.slice(0, 12)]: { publicKeyHex: KEY, alias: 'x' },
|
|
})
|
|
t.is(payload.version, 1)
|
|
t.ok(payload.updatedAt)
|
|
t.is(payload.peers[KEY.slice(0, 12)].publicKeyHex, KEY)
|
|
})
|
|
|
|
test('file cache round-trip under temp PEARDOCK_HOME', (t) => {
|
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'peardock-peers-cache-'))
|
|
const prev = process.env.PEARDOCK_HOME
|
|
process.env.PEARDOCK_HOME = tmp
|
|
t.teardown(() => {
|
|
if (prev === undefined) delete process.env.PEARDOCK_HOME
|
|
else process.env.PEARDOCK_HOME = prev
|
|
try {
|
|
fs.rmSync(tmp, { recursive: true, force: true })
|
|
} catch {
|
|
// ignore
|
|
}
|
|
})
|
|
|
|
const expectedPath = path.join(tmp, '.config', 'peardock', 'cache', 'peers.json')
|
|
t.is(getPeersCachePath(), expectedPath)
|
|
|
|
const seed = 'cd'.repeat(32)
|
|
const peers = {
|
|
[KEY.slice(0, 12)]: {
|
|
publicKeyHex: KEY,
|
|
alias: 'alpha',
|
|
inviteToken: 'tok',
|
|
adminSeed: seed,
|
|
},
|
|
[KEY2.slice(0, 12)]: { publicKeyHex: KEY2, alias: null },
|
|
}
|
|
const result = savePeers(peers)
|
|
t.ok(result.ok)
|
|
t.is(result.count, 2)
|
|
t.is(result.path, expectedPath)
|
|
t.ok(fs.existsSync(expectedPath))
|
|
|
|
const loaded = loadPeers()
|
|
t.is(loaded[KEY.slice(0, 12)].alias, 'alpha')
|
|
t.is(loaded[KEY.slice(0, 12)].inviteToken, 'tok')
|
|
t.is(loaded[KEY.slice(0, 12)].adminSeed, seed)
|
|
t.is(loaded[KEY2.slice(0, 12)].publicKeyHex, KEY2)
|
|
t.absent(loaded[KEY2.slice(0, 12)].adminSeed)
|
|
|
|
const list = listSavedPeers()
|
|
t.is(list.length, 2)
|
|
t.is(list.find((p) => p.publicKeyHex === KEY)?.adminSeed, seed)
|
|
|
|
clearPeers()
|
|
t.absent(fs.existsSync(expectedPath))
|
|
t.is(Object.keys(readPeersFromFile()).length, 0)
|
|
})
|
|
|
|
test('writePeersToFile is atomic enough to read back', (t) => {
|
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'peardock-peers-atomic-'))
|
|
const prev = process.env.PEARDOCK_HOME
|
|
process.env.PEARDOCK_HOME = tmp
|
|
t.teardown(() => {
|
|
if (prev === undefined) delete process.env.PEARDOCK_HOME
|
|
else process.env.PEARDOCK_HOME = prev
|
|
try {
|
|
fs.rmSync(tmp, { recursive: true, force: true })
|
|
} catch {
|
|
// ignore
|
|
}
|
|
})
|
|
|
|
t.ok(writePeersToFile({ [KEY.slice(0, 12)]: { publicKeyHex: KEY } }))
|
|
const again = readPeersFromFile()
|
|
t.is(again[KEY.slice(0, 12)].publicKeyHex, KEY)
|
|
})
|
|
|
|
test('savePeers empty map overwrites (explicit) but load survives merge pattern', (t) => {
|
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'peardock-peers-merge-'))
|
|
const prev = process.env.PEARDOCK_HOME
|
|
process.env.PEARDOCK_HOME = tmp
|
|
t.teardown(() => {
|
|
if (prev === undefined) delete process.env.PEARDOCK_HOME
|
|
else process.env.PEARDOCK_HOME = prev
|
|
try {
|
|
fs.rmSync(tmp, { recursive: true, force: true })
|
|
} catch {
|
|
// ignore
|
|
}
|
|
})
|
|
|
|
savePeers({ [KEY.slice(0, 12)]: { publicKeyHex: KEY, alias: 'Main' } })
|
|
t.is(loadPeers()[KEY.slice(0, 12)].alias, 'Main')
|
|
|
|
// Simulate safe merge used by manager.persist / saveConnections:
|
|
// never replace disk with bare empty without removeId intent
|
|
const existing = loadPeers()
|
|
const merged = { ...existing }
|
|
// no removeId → peers remain
|
|
savePeers(merged)
|
|
t.is(Object.keys(loadPeers()).length, 1)
|
|
t.is(loadPeers()[KEY.slice(0, 12)].alias, 'Main')
|
|
})
|