Files
peardata/test/integration.test.js
T
2026-07-18 16:22:56 -04:00

97 lines
2.8 KiB
JavaScript

/**
* End-to-end: ephemeral HyperDHT agent + client RPC + metric push.
* Skip with: SKIP_INTEGRATION=1 npm test
*/
import test from 'brittle'
import DHT from 'hyperdht'
import b4a from 'b4a'
import crypto from 'hypercore-crypto'
import { PeerSession } from '../server/rpc/session.js'
import { registerAllHandlers, cleanupSession } from '../server/rpc/register.js'
import { peers } from '../server/core/peer-registry.js'
import { initAuthKeys } from '../server/core/auth-keys.js'
import { PearDataConnection } from '../client/connection.js'
import { Methods, Pushes } from '../shared/protocol.js'
import { startPipeline } from '../server/pipeline.js'
import { getCollector } from '../server/services/collector.js'
const skip = process.env.SKIP_INTEGRATION === '1'
test('integration: dial, handshake, metrics, subscribe', { skip, timeout: 60_000 }, async (t) => {
const seed = crypto.randomBytes(32)
const keyPair = DHT.keyPair(seed)
const publicKeyHex = b4a.toString(keyPair.publicKey, 'hex')
const seedHex = b4a.toString(seed, 'hex')
initAuthKeys({ seedHex, publicKeyHex })
process.env.PEARDATA_INSECURE_OPEN_ADMIN = '1'
startPipeline()
const dht = new DHT()
const server = dht.createServer()
server.on('connection', (socket) => {
const session = new PeerSession(socket, {
serverPublicKey: keyPair.publicKey,
onClose: (s) => {
cleanupSession(s)
peers.remove(s.id)
},
})
registerAllHandlers(session)
peers.add(session)
})
await server.listen(keyPair)
t.teardown(async () => {
getCollector().stop()
for (const s of peers.list()) s.destroy()
await server.close().catch(() => {})
await dht.destroy().catch(() => {})
delete process.env.PEARDATA_INSECURE_OPEN_ADMIN
})
const conn = new PearDataConnection(publicKeyHex, {
adminSeed: seedHex,
timeoutMs: 45_000,
})
/** @type {object[]} */
const metricPushes = []
conn.on(Pushes.metrics, (m) => metricPushes.push(m))
await conn.connect()
t.is(conn.role, 'admin')
t.ok(conn.connected)
const pong = await conn.request(Methods.ping, {})
t.ok(pong.ok)
const info = await conn.request(Methods.getServerInfo, {})
t.is(info.app, 'peardata')
const charts = await conn.request(Methods.listCharts, {})
t.ok(charts.charts)
await conn.request(Methods.subscribeMetrics, { charts: ['*'], intervalMs: 1000 })
// wait for at least one collector tick + push
await new Promise((r) => setTimeout(r, 2200))
const q = await conn.request(Methods.queryData, {
chart: 'system.cpu',
after: -30,
points: 30,
})
t.ok(q.labels)
t.ok(Array.isArray(q.data))
const health = await conn.request(Methods.getHealth, {})
t.ok(health.status)
t.ok(metricPushes.length >= 0) // push timing may vary; query proves pipeline
await conn.destroy()
})