-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathmetrics-sampler.test.ts
More file actions
125 lines (106 loc) · 4.42 KB
/
Copy pathmetrics-sampler.test.ts
File metadata and controls
125 lines (106 loc) · 4.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { collectMetricsSample, startMetricsSampler } from '../metrics-sampler';
const originalEnv = { ...process.env };
const tmpFile = (): string =>
path.join(os.tmpdir(), `metrics-sampler-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}.jsonl`);
const waitForFileContent = async (file: string, timeoutMs = 2_000): Promise<string> => {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
try {
const content = await fs.promises.readFile(file, 'utf8');
if (content.trim().length > 0) {
return content;
}
} catch {
// file not created yet
}
await new Promise((resolve) => setTimeout(resolve, 20));
}
throw new Error(`metrics file ${file} never received content`);
};
afterEach(() => {
process.env = { ...originalEnv };
});
describe('collectMetricsSample', () => {
it('produces a well-formed, JSON-serializable sample', () => {
const sample = collectMetricsSample();
expect(typeof sample.ts).toBe('string');
expect(Number.isNaN(Date.parse(sample.ts))).toBe(false);
expect(typeof sample.rss).toBe('number');
expect(typeof sample.heapUsed).toBe('number');
expect(typeof sample.heapTotal).toBe('number');
expect(typeof sample.external).toBe('number');
expect(typeof sample.heap_size_limit).toBe('number');
expect(typeof sample.cache.size).toBe('number');
expect(typeof sample.cache.keys).toBe('number');
// counters merge cache counters + graphile counters + build queue depth
expect(typeof sample.counters.disposals).toBe('number');
expect(typeof sample.counters.evictions.lru).toBe('number');
expect(typeof sample.counters.builds).toBe('number');
expect(typeof sample.counters.buildQueueDepth).toBe('number');
expect(typeof sample.counters.introspectionFilter.swaps).toBe('number');
expect(typeof sample.counters.introspectionFilter.discoveries).toBe('number');
expect(typeof sample.gc).toBe('object');
// Round-trips through JSON without loss.
expect(() => JSON.parse(JSON.stringify(sample))).not.toThrow();
});
});
describe('startMetricsSampler (disabled)', () => {
it('returns null and writes nothing when GRAPHILE_DEBUG_METRICS is unset', async () => {
delete process.env.GRAPHILE_DEBUG_METRICS;
const file = tmpFile();
process.env.GRAPHILE_DEBUG_METRICS_FILE = file;
const handle = startMetricsSampler();
expect(handle).toBeNull();
await new Promise((resolve) => setTimeout(resolve, 60));
expect(fs.existsSync(file)).toBe(false);
});
it('returns null when GRAPHILE_DEBUG_METRICS is a falsy string', () => {
process.env.GRAPHILE_DEBUG_METRICS = '0';
expect(startMetricsSampler()).toBeNull();
process.env.GRAPHILE_DEBUG_METRICS = 'false';
expect(startMetricsSampler()).toBeNull();
});
});
describe('startMetricsSampler (enabled)', () => {
it("writes a parseable JSON line to the configured file when enabled ('1')", async () => {
const file = tmpFile();
process.env.GRAPHILE_DEBUG_METRICS = '1';
process.env.GRAPHILE_DEBUG_METRICS_FILE = file;
process.env.GRAPHILE_DEBUG_METRICS_INTERVAL_MS = '50';
const handle = startMetricsSampler();
expect(handle).not.toBeNull();
try {
const content = await waitForFileContent(file);
const firstLine = content.trim().split('\n')[0];
const parsed = JSON.parse(firstLine);
expect(typeof parsed.ts).toBe('string');
expect(typeof parsed.rss).toBe('number');
expect(typeof parsed.heap_size_limit).toBe('number');
expect(parsed.cache).toBeDefined();
expect(typeof parsed.counters.disposals).toBe('number');
expect(typeof parsed.counters.buildQueueDepth).toBe('number');
expect(parsed.gc).toBeDefined();
} finally {
handle?.stop();
await fs.promises.rm(file, { force: true });
}
});
it("also treats 'true' as enabled", async () => {
const file = tmpFile();
process.env.GRAPHILE_DEBUG_METRICS = 'true';
process.env.GRAPHILE_DEBUG_METRICS_FILE = file;
process.env.GRAPHILE_DEBUG_METRICS_INTERVAL_MS = '50';
const handle = startMetricsSampler();
expect(handle).not.toBeNull();
try {
const content = await waitForFileContent(file);
expect(() => JSON.parse(content.trim().split('\n')[0])).not.toThrow();
} finally {
handle?.stop();
await fs.promises.rm(file, { force: true });
}
});
});