updates
CI / test (push) Failing after 6s
Release rolling / release (push) Has been cancelled

This commit is contained in:
Raven Scott
2026-07-18 19:11:32 -04:00
parent 9bc7a67020
commit 1d46b7b3ad
39 changed files with 2155 additions and 67 deletions
+55
View File
@@ -0,0 +1,55 @@
import test from 'brittle'
import fs from 'fs'
import path from 'path'
import os from 'os'
import { getStore } from '../server/services/store.js'
import {
toPrometheusText,
writeSnapshotFile,
buildSnapshot,
} from '../server/services/export.js'
test('toPrometheusText includes peardata_info and dimensions', (t) => {
const text = toPrometheusText({
'system.cpu': {
ts: Date.now(),
values: { user: 10, idle: 90 },
},
})
t.ok(text.includes('peardata_info'))
t.ok(text.includes('peardata_system_cpu'))
t.ok(text.includes('dimension="idle"'))
t.ok(text.includes(' 90'))
})
test('writeSnapshotFile respects PEARDATA_EXPORT_DIR', (t) => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'peardata-export-'))
const prev = process.env.PEARDATA_EXPORT_DIR
process.env.PEARDATA_EXPORT_DIR = dir
const snap = { ts: 1234567890, latest: {}, success: true }
const written = writeSnapshotFile(snap)
t.ok(written.path)
t.ok(fs.existsSync(written.path))
const parsed = JSON.parse(fs.readFileSync(written.path, 'utf8'))
t.is(parsed.ts, 1234567890)
fs.rmSync(dir, { recursive: true, force: true })
if (prev == null) delete process.env.PEARDATA_EXPORT_DIR
else process.env.PEARDATA_EXPORT_DIR = prev
})
test('buildSnapshot returns latest from store', (t) => {
// ensure singleton has something
const store = getStore()
store.ingest([
{
chart: 'system.ram',
context: 'system.ram',
ts: Date.now(),
values: { used: 100, free: 200, cached: 50, buffers: 10 },
},
])
const snap = buildSnapshot()
t.ok(snap.success)
t.ok(snap.latest['system.ram'])
t.ok(snap.health)
})
+34
View File
@@ -0,0 +1,34 @@
import test from 'brittle'
import { parseNginxStubStatus, isNginxEnabled } from '../server/services/collectors/nginx.js'
const SAMPLE = `Active connections: 291
server accepts handled requests
16630948 16630948 31070465
Reading: 6 Writing: 179 Waiting: 106
`
test('parseNginxStubStatus', (t) => {
const p = parseNginxStubStatus(SAMPLE)
t.ok(p)
t.is(p.active, 291)
t.is(p.accepts, 16630948)
t.is(p.handled, 16630948)
t.is(p.requests, 31070465)
t.is(p.reading, 6)
t.is(p.writing, 179)
t.is(p.waiting, 106)
})
test('parseNginxStubStatus rejects junk', (t) => {
t.is(parseNginxStubStatus('hello'), null)
})
test('isNginxEnabled', (t) => {
const prev = process.env.PEARDATA_NGINX
delete process.env.PEARDATA_NGINX
t.absent(isNginxEnabled())
process.env.PEARDATA_NGINX = '1'
t.ok(isNginxEnabled())
if (prev == null) delete process.env.PEARDATA_NGINX
else process.env.PEARDATA_NGINX = prev
})
+44
View File
@@ -0,0 +1,44 @@
import test from 'brittle'
import {
extractChildStats,
parseParentPeers,
isParentEnabled,
} from '../server/services/collectors/parent.js'
test('isParentEnabled', (t) => {
const prev = process.env.PEARDATA_PARENT
delete process.env.PEARDATA_PARENT
t.absent(isParentEnabled())
process.env.PEARDATA_PARENT = '1'
t.ok(isParentEnabled())
if (prev == null) delete process.env.PEARDATA_PARENT
else process.env.PEARDATA_PARENT = prev
})
test('parseParentPeers filters hex keys', (t) => {
const prev = process.env.PEARDATA_PARENT_PEERS
const prevFile = process.env.PEARDATA_PARENT_PEERS_FILE
delete process.env.PEARDATA_PARENT_PEERS_FILE
process.env.PEARDATA_PARENT_PEERS = `aa${'b'.repeat(62)}, not-a-key, ${'c'.repeat(64)}`
const list = parseParentPeers()
t.is(list.length, 2)
t.ok(list[0].startsWith('aa'))
if (prev == null) delete process.env.PEARDATA_PARENT_PEERS
else process.env.PEARDATA_PARENT_PEERS = prev
if (prevFile == null) delete process.env.PEARDATA_PARENT_PEERS_FILE
else process.env.PEARDATA_PARENT_PEERS_FILE = prevFile
})
test('extractChildStats from getAllMetrics body', (t) => {
const stats = extractChildStats({
contentType: 'application/json',
body: {
charts: {
'system.cpu': { dimensions: { idle: 72, user: 20, system: 8 } },
'system.ram': { dimensions: { used: 2048, free: 1024 } },
},
},
})
t.is(stats.cpu, 28)
t.is(stats.ram, 2048)
})
+29
View File
@@ -0,0 +1,29 @@
import test from 'brittle'
import {
parsePostgresStats,
isPostgresEnabled,
} from '../server/services/collectors/postgres.js'
test('parsePostgresStats', (t) => {
const s = parsePostgresStats(`
# comment
connections=18
xact_commit: 1000
xact_rollback=2
tuples_returned=50000
`)
t.is(s.connections, 18)
t.is(s.xact_commit, 1000)
t.is(s.xact_rollback, 2)
t.is(s.tuples_returned, 50000)
})
test('isPostgresEnabled', (t) => {
const prev = process.env.PEARDATA_POSTGRES
delete process.env.PEARDATA_POSTGRES
t.absent(isPostgresEnabled())
process.env.PEARDATA_POSTGRES = '1'
t.ok(isPostgresEnabled())
if (prev == null) delete process.env.PEARDATA_POSTGRES
else process.env.PEARDATA_POSTGRES = prev
})
+2
View File
@@ -37,6 +37,8 @@ test('method roles cover monitoring surface', (t) => {
'getDbInfo',
'linkPeer',
'unlinkPeer',
'getFleetHealth',
'listChildPeers',
]) {
t.ok(MethodRoles[m], m)
t.is(Methods[m], m)
+45
View File
@@ -0,0 +1,45 @@
import test from 'brittle'
import {
parseRedisInfo,
parseRedisAddr,
isRedisEnabled,
} from '../server/services/collectors/redis.js'
const SAMPLE = `# Server
redis_version:7.2.0
# Memory
used_memory:1048576
used_memory_peak:2097152
used_memory_rss:3145728
# Clients
connected_clients:12
blocked_clients:1
# Stats
instantaneous_ops_per_sec:42
keyspace_hits:90
keyspace_misses:10
`
test('parseRedisInfo', (t) => {
const info = parseRedisInfo(SAMPLE)
t.is(info.redis_version, '7.2.0')
t.is(info.used_memory, '1048576')
t.is(info.connected_clients, '12')
t.is(info.instantaneous_ops_per_sec, '42')
})
test('parseRedisAddr', (t) => {
t.is(parseRedisAddr('10.0.0.2:6380').port, 6380)
t.is(parseRedisAddr('redis://localhost:6379/0').host, 'localhost')
t.is(parseRedisAddr('redis://localhost:6379/0').port, 6379)
})
test('isRedisEnabled', (t) => {
const prev = process.env.PEARDATA_REDIS
delete process.env.PEARDATA_REDIS
t.absent(isRedisEnabled())
process.env.PEARDATA_REDIS = '1'
t.ok(isRedisEnabled())
if (prev == null) delete process.env.PEARDATA_REDIS
else process.env.PEARDATA_REDIS = prev
})
+117
View File
@@ -0,0 +1,117 @@
/**
* Linked peer warm pull: replicate Corestore A → B, open remote bee by dbKeyHex,
* query metric points without re-scraping.
*/
import test from 'brittle'
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'
import Corestore from 'corestore'
import { PearDataModel } from '../server/db/model.js'
import { MetricStore } from '../server/services/store.js'
import { openDb, closeDb } from '../server/db/index.js'
import { openRemoteDb, closeRemoteDbs, queryRemoteMetricPoints } from '../server/db/remote.js'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const TMP = path.join(__dirname, '..', 'tmp-swarm-pull-test')
function replicatePair(a, b) {
const s1 = a.replicate(true)
const s2 = b.replicate(false)
s1.pipe(s2).pipe(s1)
return () => {
try {
s1.destroy()
} catch {
// ignore
}
try {
s2.destroy()
} catch {
// ignore
}
}
}
test('linked peer pulls warm points over corestore replicate', async (t) => {
fs.rmSync(TMP, { recursive: true, force: true })
const dirA = path.join(TMP, 'a')
const dirB = path.join(TMP, 'b-local')
const storeA = new Corestore(path.join(dirA, 'corestore'))
await storeA.ready()
const coreA = storeA.get({ name: 'peardata-meta' })
const modelA = new PearDataModel(coreA, { autoUpdate: true })
await modelA.ready()
const now = Date.now()
await modelA.putMetricPoints([
{
chart: 'system.cpu',
context: 'system.cpu',
ts: now - 90_000,
values: { user: 15, system: 5, nice: 0, iowait: 0, irq: 0, softirq: 0, idle: 80 },
tier: 1,
},
{
chart: 'system.cpu',
context: 'system.cpu',
ts: now - 30_000,
values: { user: 25, system: 5, nice: 0, iowait: 0, irq: 0, softirq: 0, idle: 70 },
tier: 1,
},
])
const dbKeyHex = modelA.publicKeyHex
// B: local agent HyperDB + open A's core by key, then replicate
process.env.PEARDATA_DATA_DIR = dirB
delete process.env.PEARDATA_HYPERDB
await closeDb().catch(() => {})
await closeRemoteDbs().catch(() => {})
const localB = await openDb()
t.ok(localB)
const remote = await openRemoteDb(dbKeyHex)
t.ok(remote)
const storeB = (await import('../server/db/index.js')).getCorestore()
const stop = replicatePair(storeA, storeB)
// wait for remote core to download blocks
const deadline = Date.now() + 10_000
let rows = []
while (Date.now() < deadline) {
rows = await queryRemoteMetricPoints({
chart: 'system.cpu',
afterMs: now - 180_000,
beforeMs: now + 1000,
tier: 1,
limit: 100,
})
if (rows.length >= 2) break
await new Promise((r) => setTimeout(r, 100))
}
t.ok(rows.length >= 2, `expected warm rows, got ${rows.length}`)
// MetricStore query should surface hyperdb-remote when memory empty
const mem = new MetricStore()
const q = await mem.query({
chart: 'system.cpu',
after: Math.floor((now - 180_000) / 1000),
before: Math.floor(now / 1000),
points: 60,
tier: 1,
})
t.ok(q.source === 'hyperdb-remote' || q.source === 'hyperdb-warm')
t.ok(q.data.length >= 2)
stop()
await closeRemoteDbs()
await closeDb()
await modelA.close().catch(() => {})
await storeA.close().catch(() => {})
fs.rmSync(TMP, { recursive: true, force: true })
delete process.env.PEARDATA_DATA_DIR
})