Add process view
This commit is contained in:
@@ -4,6 +4,10 @@ import { isProcessCollectorEnabled, listProcStats } from '../server/services/col
|
||||
test('isProcessCollectorEnabled', (t) => {
|
||||
const prev = process.env.PEARDATA_PROCESSES
|
||||
delete process.env.PEARDATA_PROCESSES
|
||||
// Default on for Linux hosts
|
||||
if (process.platform === 'linux') t.ok(isProcessCollectorEnabled())
|
||||
else t.absent(isProcessCollectorEnabled())
|
||||
process.env.PEARDATA_PROCESSES = '0'
|
||||
t.absent(isProcessCollectorEnabled())
|
||||
process.env.PEARDATA_PROCESSES = '1'
|
||||
t.ok(isProcessCollectorEnabled())
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
import test from 'brittle'
|
||||
import {
|
||||
parseProcStat,
|
||||
parseProcStatus,
|
||||
processMatchesQuery,
|
||||
processMatchesFilter,
|
||||
sortProcesses,
|
||||
listProcesses,
|
||||
_resetProcessMonitorForTests,
|
||||
} from '../server/services/processes.js'
|
||||
import { validateMethodArgs } from '../shared/schema.js'
|
||||
import { isProcessCollectorEnabled } from '../server/services/collectors/processes.js'
|
||||
|
||||
test('parseProcStat extracts comm and counters', (t) => {
|
||||
const raw =
|
||||
'1 (systemd) S 0 1 1 0 -1 4194560 123 0 0 0 10 20 0 0 20 0 1 0 12345 1000000 100 18446744073709551615 1 1 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0'
|
||||
const st = parseProcStat(raw)
|
||||
t.ok(st)
|
||||
t.is(st.name, 'systemd')
|
||||
t.is(st.state, 'S')
|
||||
t.is(st.ppid, 0)
|
||||
t.is(st.utime, 10)
|
||||
t.is(st.stime, 20)
|
||||
})
|
||||
|
||||
test('parseProcStatus reads uid and threads', (t) => {
|
||||
const s = parseProcStatus('Name:\tfoo\nUid:\t1000\t1000\t1000\t1000\nThreads:\t4\nVmRSS:\t2048 kB\n')
|
||||
t.is(s.uid, 1000)
|
||||
t.is(s.threads, 4)
|
||||
t.is(s.vmRssKb, 2048)
|
||||
})
|
||||
|
||||
test('process filter + query helpers', (t) => {
|
||||
const row = {
|
||||
pid: 42,
|
||||
name: 'nginx',
|
||||
cmdline: '/usr/sbin/nginx -g daemon',
|
||||
user: 'www',
|
||||
stateLabel: 'running',
|
||||
cpu: 12,
|
||||
mem: 200,
|
||||
io: 3,
|
||||
kernel: false,
|
||||
}
|
||||
t.ok(processMatchesQuery(row, 'nginx'))
|
||||
t.ok(processMatchesQuery(row, '42'))
|
||||
t.absent(processMatchesQuery(row, 'postgres'))
|
||||
t.ok(processMatchesFilter(row, 'running'))
|
||||
t.ok(processMatchesFilter(row, 'highcpu'))
|
||||
t.ok(processMatchesFilter(row, 'highmem'))
|
||||
t.ok(processMatchesFilter(row, 'user'))
|
||||
t.absent(processMatchesFilter(row, 'zombie'))
|
||||
})
|
||||
|
||||
test('sortProcesses orders by cpu desc', (t) => {
|
||||
const rows = [
|
||||
{ pid: 1, name: 'a', cpu: 1, mem: 9 },
|
||||
{ pid: 2, name: 'b', cpu: 9, mem: 1 },
|
||||
]
|
||||
const sorted = sortProcesses(rows, 'cpu', 'desc')
|
||||
t.is(sorted[0].pid, 2)
|
||||
t.is(sortProcesses(rows, 'rss', 'desc')[0].pid, 1)
|
||||
})
|
||||
|
||||
test('validateMethodArgs listProcesses', (t) => {
|
||||
const ok = validateMethodArgs('listProcesses', { sort: 'cpu', limit: 50 })
|
||||
t.ok(ok.ok)
|
||||
t.is(ok.args.sort, 'cpu')
|
||||
const bad = validateMethodArgs('listProcesses', { sort: 'nope' })
|
||||
t.absent(bad.ok)
|
||||
})
|
||||
|
||||
test('listProcesses returns shape', (t) => {
|
||||
_resetProcessMonitorForTests()
|
||||
const res = listProcesses({ limit: 20, sort: 'cpu' })
|
||||
t.ok(res.ok)
|
||||
t.ok(res.summary)
|
||||
t.ok(Array.isArray(res.processes))
|
||||
if (process.platform === 'linux') {
|
||||
t.ok(res.supported)
|
||||
t.ok(res.summary.total > 0)
|
||||
// Second call should populate CPU rates after prev sample
|
||||
_resetProcessMonitorForTests()
|
||||
listProcesses({ limit: 5 })
|
||||
const again = listProcesses({ limit: 5 })
|
||||
t.ok(again.processes.length > 0)
|
||||
t.ok(again.processes[0].pid > 0)
|
||||
t.ok(again.processes[0].name)
|
||||
} else {
|
||||
t.absent(res.supported)
|
||||
}
|
||||
})
|
||||
|
||||
test('isProcessCollectorEnabled defaults on linux', (t) => {
|
||||
const prev = process.env.PEARDATA_PROCESSES
|
||||
delete process.env.PEARDATA_PROCESSES
|
||||
if (process.platform === 'linux') t.ok(isProcessCollectorEnabled())
|
||||
else t.absent(isProcessCollectorEnabled())
|
||||
process.env.PEARDATA_PROCESSES = '0'
|
||||
t.absent(isProcessCollectorEnabled())
|
||||
process.env.PEARDATA_PROCESSES = '1'
|
||||
t.ok(isProcessCollectorEnabled())
|
||||
if (prev == null) delete process.env.PEARDATA_PROCESSES
|
||||
else process.env.PEARDATA_PROCESSES = prev
|
||||
})
|
||||
@@ -41,6 +41,7 @@ test('method roles cover monitoring surface', (t) => {
|
||||
'listChildPeers',
|
||||
'getWeights',
|
||||
'queryLogs',
|
||||
'listProcesses',
|
||||
'getStorageInfo',
|
||||
'getRetentionConfig',
|
||||
'setRetentionConfig',
|
||||
|
||||
Reference in New Issue
Block a user