123 lines
3.3 KiB
JavaScript
123 lines
3.3 KiB
JavaScript
/**
|
|
* Peer-demand stats: no Docker collection until a peer sets view interest.
|
|
*/
|
|
import test from 'brittle'
|
|
import { PeerRegistry } from '../server/core/peer-registry.js'
|
|
|
|
test('PeerRegistry onChange fires on add/remove and size transitions', (t) => {
|
|
const reg = new PeerRegistry()
|
|
/** @type {Array<[number, number]>} */
|
|
const events = []
|
|
const unsub = reg.onChange((size, prev) => events.push([size, prev]))
|
|
|
|
const s1 = { id: 'peer-aaa', destroy() {} }
|
|
const s2 = { id: 'peer-bbb', destroy() {} }
|
|
|
|
reg.add(s1)
|
|
t.is(reg.size, 1)
|
|
t.alike(events[events.length - 1], [1, 0])
|
|
|
|
reg.add(s2)
|
|
t.is(reg.size, 2)
|
|
t.alike(events[events.length - 1], [2, 1])
|
|
|
|
reg.remove('peer-aaa')
|
|
t.is(reg.size, 1)
|
|
t.alike(events[events.length - 1], [1, 2])
|
|
|
|
reg.remove('peer-bbb')
|
|
t.is(reg.size, 0)
|
|
t.alike(events[events.length - 1], [0, 1])
|
|
|
|
const n = events.length
|
|
reg.remove('nope')
|
|
t.is(events.length, n)
|
|
|
|
unsub()
|
|
reg.add(s1)
|
|
t.is(events.length, n, 'unsubscribed listener not called')
|
|
reg.clear()
|
|
})
|
|
|
|
test('PeerRegistry.broadcast is a no-op with zero peers', (t) => {
|
|
const reg = new PeerRegistry()
|
|
let pushed = 0
|
|
reg.broadcast('push:test', { x: 1 })
|
|
t.is(pushed, 0)
|
|
|
|
reg.add({
|
|
id: 'p1',
|
|
push() {
|
|
pushed += 1
|
|
},
|
|
destroy() {},
|
|
})
|
|
reg.broadcast('push:test', { x: 1 })
|
|
t.is(pushed, 1)
|
|
reg.clear()
|
|
})
|
|
|
|
test('stats service: idle until view interest; pauses when interest cleared', async (t) => {
|
|
const stats = await import('../server/services/stats.js')
|
|
const { peers } = await import('../server/core/peer-registry.js')
|
|
|
|
peers.clear()
|
|
stats.stopStatsBroadcast()
|
|
stats.resetStatsConfigForTests?.()
|
|
|
|
stats.startStatsBroadcast()
|
|
t.is(stats.isStatsCollectionActive(), false, 'idle with no interest')
|
|
|
|
const fake = {
|
|
id: 'test-peer-stats-idle',
|
|
role: 'viewer',
|
|
push() {},
|
|
destroy() {},
|
|
}
|
|
peers.add(fake)
|
|
await new Promise((r) => setTimeout(r, 30))
|
|
// Connected alone is NOT enough — must declare interest
|
|
t.is(stats.isStatsCollectionActive(), false, 'peer connected but no view interest')
|
|
|
|
stats.setPeerStatsInterest(fake.id, true, { view: 'containers' })
|
|
await new Promise((r) => setTimeout(r, 30))
|
|
t.is(stats.isStatsCollectionActive(), true, 'active after setStatsInterest')
|
|
t.is(stats.getStatsInterestCount(), 1)
|
|
|
|
stats.setPeerStatsInterest(fake.id, false)
|
|
await new Promise((r) => setTimeout(r, 20))
|
|
t.is(stats.isStatsCollectionActive(), false, 'paused after interest cleared')
|
|
t.is(stats.getStatsInterestCount(), 0)
|
|
|
|
stats.stopStatsBroadcast()
|
|
peers.clear()
|
|
})
|
|
|
|
test('stats interest cleared when peer removed from registry', async (t) => {
|
|
const stats = await import('../server/services/stats.js')
|
|
const { peers } = await import('../server/core/peer-registry.js')
|
|
|
|
peers.clear()
|
|
stats.stopStatsBroadcast()
|
|
stats.resetStatsConfigForTests?.()
|
|
stats.startStatsBroadcast()
|
|
|
|
const fake = {
|
|
id: 'test-peer-stats-drop',
|
|
role: 'viewer',
|
|
push() {},
|
|
destroy() {},
|
|
}
|
|
peers.add(fake)
|
|
stats.setPeerStatsInterest(fake.id, true, { view: 'dashboard' })
|
|
t.is(stats.isStatsCollectionActive(), true)
|
|
|
|
peers.remove(fake.id)
|
|
await new Promise((r) => setTimeout(r, 20))
|
|
t.is(stats.isStatsCollectionActive(), false, 'paused after peer disconnect')
|
|
t.is(stats.getStatsInterestCount(), 0)
|
|
|
|
stats.stopStatsBroadcast()
|
|
peers.clear()
|
|
})
|