observability-toolkit 1.8.4 → 1.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backends/local-jsonl-boolean-search.test.js +8 -8
- package/dist/backends/local-jsonl-boolean-search.test.js.map +1 -1
- package/dist/backends/local-jsonl-cache.test.d.ts +2 -0
- package/dist/backends/local-jsonl-cache.test.d.ts.map +1 -0
- package/dist/backends/local-jsonl-cache.test.js +295 -0
- package/dist/backends/local-jsonl-cache.test.js.map +1 -0
- package/dist/backends/local-jsonl-circuit-breaker.test.d.ts +2 -0
- package/dist/backends/local-jsonl-circuit-breaker.test.d.ts.map +1 -0
- package/dist/backends/local-jsonl-circuit-breaker.test.js +180 -0
- package/dist/backends/local-jsonl-circuit-breaker.test.js.map +1 -0
- package/dist/backends/local-jsonl-export.test.d.ts +2 -0
- package/dist/backends/local-jsonl-export.test.d.ts.map +1 -0
- package/dist/backends/local-jsonl-export.test.js +704 -0
- package/dist/backends/local-jsonl-export.test.js.map +1 -0
- package/dist/backends/local-jsonl-index.test.d.ts +2 -0
- package/dist/backends/local-jsonl-index.test.d.ts.map +1 -0
- package/dist/backends/local-jsonl-index.test.js +554 -0
- package/dist/backends/local-jsonl-index.test.js.map +1 -0
- package/dist/backends/local-jsonl-logs.test.js +52 -43
- package/dist/backends/local-jsonl-logs.test.js.map +1 -1
- package/dist/backends/local-jsonl-metrics.test.d.ts +2 -0
- package/dist/backends/local-jsonl-metrics.test.d.ts.map +1 -0
- package/dist/backends/local-jsonl-metrics.test.js +876 -0
- package/dist/backends/local-jsonl-metrics.test.js.map +1 -0
- package/dist/backends/local-jsonl-traces.test.js +89 -83
- package/dist/backends/local-jsonl-traces.test.js.map +1 -1
- package/dist/backends/local-jsonl.d.ts +9 -0
- package/dist/backends/local-jsonl.d.ts.map +1 -1
- package/dist/backends/local-jsonl.js +348 -227
- package/dist/backends/local-jsonl.js.map +1 -1
- package/dist/backends/signoz-api-circuit-breaker.test.d.ts +6 -0
- package/dist/backends/signoz-api-circuit-breaker.test.d.ts.map +1 -0
- package/dist/backends/signoz-api-circuit-breaker.test.js +548 -0
- package/dist/backends/signoz-api-circuit-breaker.test.js.map +1 -0
- package/dist/backends/signoz-api-rate-limiter.test.d.ts +6 -0
- package/dist/backends/signoz-api-rate-limiter.test.d.ts.map +1 -0
- package/dist/backends/signoz-api-rate-limiter.test.js +389 -0
- package/dist/backends/signoz-api-rate-limiter.test.js.map +1 -0
- package/dist/backends/signoz-api-ssrf.test.d.ts +6 -0
- package/dist/backends/signoz-api-ssrf.test.d.ts.map +1 -0
- package/dist/backends/signoz-api-ssrf.test.js +216 -0
- package/dist/backends/signoz-api-ssrf.test.js.map +1 -0
- package/dist/backends/signoz-api-test-helpers.d.ts +80 -0
- package/dist/backends/signoz-api-test-helpers.d.ts.map +1 -0
- package/dist/backends/signoz-api-test-helpers.js +79 -0
- package/dist/backends/signoz-api-test-helpers.js.map +1 -0
- package/dist/backends/signoz-api.d.ts +16 -0
- package/dist/backends/signoz-api.d.ts.map +1 -1
- package/dist/backends/signoz-api.js +71 -9
- package/dist/backends/signoz-api.js.map +1 -1
- package/dist/backends/signoz-api.test.d.ts +9 -0
- package/dist/backends/signoz-api.test.d.ts.map +1 -1
- package/dist/backends/signoz-api.test.js +14 -1027
- package/dist/backends/signoz-api.test.js.map +1 -1
- package/dist/lib/cache.d.ts +47 -1
- package/dist/lib/cache.d.ts.map +1 -1
- package/dist/lib/cache.js +40 -3
- package/dist/lib/cache.js.map +1 -1
- package/dist/lib/circuit-breaker.d.ts +83 -0
- package/dist/lib/circuit-breaker.d.ts.map +1 -0
- package/dist/lib/circuit-breaker.js +125 -0
- package/dist/lib/circuit-breaker.js.map +1 -0
- package/dist/lib/circuit-breaker.test.d.ts +2 -0
- package/dist/lib/circuit-breaker.test.d.ts.map +1 -0
- package/dist/lib/circuit-breaker.test.js +263 -0
- package/dist/lib/circuit-breaker.test.js.map +1 -0
- package/dist/lib/constants-symlink.test.d.ts +12 -0
- package/dist/lib/constants-symlink.test.d.ts.map +1 -0
- package/dist/lib/constants-symlink.test.js +357 -0
- package/dist/lib/constants-symlink.test.js.map +1 -0
- package/dist/lib/edge-cases.test.js +17 -17
- package/dist/lib/edge-cases.test.js.map +1 -1
- package/dist/lib/error-sanitizer.d.ts.map +1 -1
- package/dist/lib/error-sanitizer.js +29 -3
- package/dist/lib/error-sanitizer.js.map +1 -1
- package/dist/lib/error-sanitizer.test.js +159 -0
- package/dist/lib/error-sanitizer.test.js.map +1 -1
- package/dist/lib/error-types.d.ts +54 -0
- package/dist/lib/error-types.d.ts.map +1 -0
- package/dist/lib/error-types.js +154 -0
- package/dist/lib/error-types.js.map +1 -0
- package/dist/lib/error-types.test.d.ts +2 -0
- package/dist/lib/error-types.test.d.ts.map +1 -0
- package/dist/lib/error-types.test.js +196 -0
- package/dist/lib/error-types.test.js.map +1 -0
- package/dist/lib/indexer.test.js +27 -27
- package/dist/lib/indexer.test.js.map +1 -1
- package/dist/lib/input-validator.d.ts +12 -0
- package/dist/lib/input-validator.d.ts.map +1 -1
- package/dist/lib/input-validator.fuzz.test.d.ts +12 -0
- package/dist/lib/input-validator.fuzz.test.d.ts.map +1 -0
- package/dist/lib/input-validator.fuzz.test.js +290 -0
- package/dist/lib/input-validator.fuzz.test.js.map +1 -0
- package/dist/lib/input-validator.js +57 -3
- package/dist/lib/input-validator.js.map +1 -1
- package/dist/lib/input-validator.test.js +129 -1
- package/dist/lib/input-validator.test.js.map +1 -1
- package/dist/lib/logger.d.ts +46 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +81 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/logger.test.d.ts +2 -0
- package/dist/lib/logger.test.d.ts.map +1 -0
- package/dist/lib/logger.test.js +122 -0
- package/dist/lib/logger.test.js.map +1 -0
- package/dist/lib/server-utils.d.ts +8 -0
- package/dist/lib/server-utils.d.ts.map +1 -1
- package/dist/lib/server-utils.js +34 -2
- package/dist/lib/server-utils.js.map +1 -1
- package/dist/lib/shared-schemas.d.ts +22 -0
- package/dist/lib/shared-schemas.d.ts.map +1 -1
- package/dist/lib/shared-schemas.js +22 -0
- package/dist/lib/shared-schemas.js.map +1 -1
- package/dist/lib/toon-encoder.d.ts +7 -2
- package/dist/lib/toon-encoder.d.ts.map +1 -1
- package/dist/lib/toon-encoder.js +21 -6
- package/dist/lib/toon-encoder.js.map +1 -1
- package/dist/lib/toon-encoder.test.d.ts +5 -0
- package/dist/lib/toon-encoder.test.d.ts.map +1 -0
- package/dist/lib/toon-encoder.test.js +85 -0
- package/dist/lib/toon-encoder.test.js.map +1 -0
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -1
- package/dist/server.test.js +30 -0
- package/dist/server.test.js.map +1 -1
- package/dist/test-helpers/env-utils.d.ts +22 -0
- package/dist/test-helpers/env-utils.d.ts.map +1 -1
- package/dist/test-helpers/env-utils.js +38 -0
- package/dist/test-helpers/env-utils.js.map +1 -1
- package/dist/test-helpers/fuzz-generators.d.ts +58 -0
- package/dist/test-helpers/fuzz-generators.d.ts.map +1 -0
- package/dist/test-helpers/fuzz-generators.js +216 -0
- package/dist/test-helpers/fuzz-generators.js.map +1 -0
- package/dist/test-helpers/index.d.ts +1 -0
- package/dist/test-helpers/index.d.ts.map +1 -1
- package/dist/test-helpers/index.js +2 -0
- package/dist/test-helpers/index.js.map +1 -1
- package/dist/test-helpers/memfs-utils.d.ts +181 -0
- package/dist/test-helpers/memfs-utils.d.ts.map +1 -0
- package/dist/test-helpers/memfs-utils.js +292 -0
- package/dist/test-helpers/memfs-utils.js.map +1 -0
- package/dist/test-helpers/memfs-utils.test.d.ts +5 -0
- package/dist/test-helpers/memfs-utils.test.d.ts.map +1 -0
- package/dist/test-helpers/memfs-utils.test.js +338 -0
- package/dist/test-helpers/memfs-utils.test.js.map +1 -0
- package/dist/test-helpers/race-condition-helpers.d.ts +85 -0
- package/dist/test-helpers/race-condition-helpers.d.ts.map +1 -0
- package/dist/test-helpers/race-condition-helpers.js +279 -0
- package/dist/test-helpers/race-condition-helpers.js.map +1 -0
- package/dist/test-helpers/test-data-builders.d.ts +40 -3
- package/dist/test-helpers/test-data-builders.d.ts.map +1 -1
- package/dist/test-helpers/test-data-builders.js +54 -5
- package/dist/test-helpers/test-data-builders.js.map +1 -1
- package/dist/test-helpers/tool-validators.d.ts.map +1 -1
- package/dist/test-helpers/tool-validators.js +16 -1
- package/dist/test-helpers/tool-validators.js.map +1 -1
- package/dist/tools/query-evaluations.d.ts.map +1 -1
- package/dist/tools/query-evaluations.js +16 -2
- package/dist/tools/query-evaluations.js.map +1 -1
- package/dist/tools/query-evaluations.test.js +53 -46
- package/dist/tools/query-evaluations.test.js.map +1 -1
- package/dist/tools/query-llm-events.test.js +6 -3
- package/dist/tools/query-llm-events.test.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory file system utilities for tests
|
|
3
|
+
*
|
|
4
|
+
* Uses memfs to provide a virtual file system that avoids disk I/O.
|
|
5
|
+
* Tests can use createMemFs() to get an isolated fs instance and directory.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { createMemFs, writeJsonlMem } from '../test-helpers/memfs-utils.js';
|
|
10
|
+
*
|
|
11
|
+
* describe('MyTest', () => {
|
|
12
|
+
* let mfs: MemFsInstance;
|
|
13
|
+
*
|
|
14
|
+
* beforeEach(() => {
|
|
15
|
+
* mfs = createMemFs();
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* it('should work', async () => {
|
|
19
|
+
* writeJsonlMem(mfs, 'traces-2026-01-31.jsonl', [{ traceId: 't1' }]);
|
|
20
|
+
* // mfs.dir contains the path prefix to use
|
|
21
|
+
* const backend = new LocalJsonlBackend(mfs.dir, { fs: mfs.fs });
|
|
22
|
+
* });
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
import { createFsFromVolume, Volume } from 'memfs';
|
|
27
|
+
import * as path from 'path';
|
|
28
|
+
/** Counter for unique directory names */
|
|
29
|
+
let memFsCounter = 0;
|
|
30
|
+
/**
|
|
31
|
+
* Create a new in-memory file system instance
|
|
32
|
+
*
|
|
33
|
+
* Each call creates an isolated volume with its own directory.
|
|
34
|
+
* The returned fs object is compatible with node:fs operations.
|
|
35
|
+
*
|
|
36
|
+
* @param prefix - Optional prefix for the directory name
|
|
37
|
+
* @returns MemFsInstance with fs, vol, dir, and reset function
|
|
38
|
+
*/
|
|
39
|
+
export function createMemFs(prefix = 'test') {
|
|
40
|
+
const vol = new Volume();
|
|
41
|
+
const fs = createFsFromVolume(vol);
|
|
42
|
+
const dir = `/memfs-${prefix}-${++memFsCounter}`;
|
|
43
|
+
// Create the base directory
|
|
44
|
+
vol.mkdirSync(dir, { recursive: true });
|
|
45
|
+
return {
|
|
46
|
+
fs: fs,
|
|
47
|
+
vol,
|
|
48
|
+
dir,
|
|
49
|
+
reset: () => {
|
|
50
|
+
// Clear volume and recreate base directory
|
|
51
|
+
vol.reset();
|
|
52
|
+
vol.mkdirSync(dir, { recursive: true });
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Write JSONL data to an in-memory file
|
|
58
|
+
*
|
|
59
|
+
* @param mfs - MemFsInstance from createMemFs()
|
|
60
|
+
* @param filename - Filename (not full path) to write
|
|
61
|
+
* @param data - Array of objects to write as JSONL
|
|
62
|
+
*/
|
|
63
|
+
export function writeJsonlMem(mfs, filename, data) {
|
|
64
|
+
const content = data.map(item => JSON.stringify(item)).join('\n');
|
|
65
|
+
const filePath = path.join(mfs.dir, filename);
|
|
66
|
+
mfs.vol.writeFileSync(filePath, content, { encoding: 'utf-8' });
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Write raw content to an in-memory file
|
|
70
|
+
*
|
|
71
|
+
* @param mfs - MemFsInstance from createMemFs()
|
|
72
|
+
* @param filename - Filename (not full path) to write
|
|
73
|
+
* @param content - Content to write (string or Buffer)
|
|
74
|
+
*/
|
|
75
|
+
export function writeFileMem(mfs, filename, content) {
|
|
76
|
+
const filePath = path.join(mfs.dir, filename);
|
|
77
|
+
mfs.vol.writeFileSync(filePath, content);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Read file content from in-memory file system
|
|
81
|
+
*
|
|
82
|
+
* @param mfs - MemFsInstance from createMemFs()
|
|
83
|
+
* @param filename - Filename (not full path) to read
|
|
84
|
+
* @returns File content as string
|
|
85
|
+
*/
|
|
86
|
+
export function readFileMem(mfs, filename) {
|
|
87
|
+
const filePath = path.join(mfs.dir, filename);
|
|
88
|
+
return mfs.vol.readFileSync(filePath, 'utf-8');
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Check if a file exists in the in-memory file system
|
|
92
|
+
*
|
|
93
|
+
* @param mfs - MemFsInstance from createMemFs()
|
|
94
|
+
* @param filename - Filename (not full path) to check
|
|
95
|
+
* @returns true if file exists
|
|
96
|
+
*/
|
|
97
|
+
export function existsMem(mfs, filename) {
|
|
98
|
+
const filePath = path.join(mfs.dir, filename);
|
|
99
|
+
return mfs.vol.existsSync(filePath);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Create a subdirectory in the in-memory file system
|
|
103
|
+
*
|
|
104
|
+
* @param mfs - MemFsInstance from createMemFs()
|
|
105
|
+
* @param dirname - Directory name to create (relative to mfs.dir)
|
|
106
|
+
*/
|
|
107
|
+
export function mkdirMem(mfs, dirname) {
|
|
108
|
+
const dirPath = path.join(mfs.dir, dirname);
|
|
109
|
+
mfs.vol.mkdirSync(dirPath, { recursive: true });
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* List files in a directory in the in-memory file system
|
|
113
|
+
*
|
|
114
|
+
* @param mfs - MemFsInstance from createMemFs()
|
|
115
|
+
* @param dirname - Optional subdirectory (defaults to mfs.dir)
|
|
116
|
+
* @returns Array of filenames
|
|
117
|
+
*/
|
|
118
|
+
export function readdirMem(mfs, dirname = '') {
|
|
119
|
+
const dirPath = dirname ? path.join(mfs.dir, dirname) : mfs.dir;
|
|
120
|
+
return mfs.vol.readdirSync(dirPath);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Get today's date in YYYY-MM-DD format
|
|
124
|
+
* @returns Today's date string
|
|
125
|
+
*/
|
|
126
|
+
export function getTestDateMem() {
|
|
127
|
+
return new Date().toISOString().split('T')[0];
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Shared memfs instances for test suites
|
|
131
|
+
* Use getSharedMemFs() to get/create a shared instance by ID
|
|
132
|
+
*/
|
|
133
|
+
const sharedMemFsInstances = new Map();
|
|
134
|
+
/**
|
|
135
|
+
* Get or create a shared memfs instance for a test suite
|
|
136
|
+
*
|
|
137
|
+
* Use this when multiple tests in a suite can share the same in-memory fs.
|
|
138
|
+
* Call resetSharedMemFs() in beforeEach to clear files between tests.
|
|
139
|
+
*
|
|
140
|
+
* @param suiteId - Unique identifier for the test suite
|
|
141
|
+
* @returns Shared MemFsInstance
|
|
142
|
+
*/
|
|
143
|
+
export function getSharedMemFs(suiteId) {
|
|
144
|
+
let mfs = sharedMemFsInstances.get(suiteId);
|
|
145
|
+
if (!mfs) {
|
|
146
|
+
mfs = createMemFs(suiteId);
|
|
147
|
+
sharedMemFsInstances.set(suiteId, mfs);
|
|
148
|
+
}
|
|
149
|
+
return mfs;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Reset (clear) a shared memfs instance
|
|
153
|
+
*
|
|
154
|
+
* Call this in beforeEach to ensure clean state between tests.
|
|
155
|
+
*
|
|
156
|
+
* @param suiteId - Unique identifier for the test suite
|
|
157
|
+
*/
|
|
158
|
+
export function resetSharedMemFs(suiteId) {
|
|
159
|
+
const mfs = sharedMemFsInstances.get(suiteId);
|
|
160
|
+
if (mfs) {
|
|
161
|
+
mfs.reset();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Remove a shared memfs instance
|
|
166
|
+
*
|
|
167
|
+
* Call this in after() to clean up suite-level resources.
|
|
168
|
+
*
|
|
169
|
+
* @param suiteId - Unique identifier for the test suite
|
|
170
|
+
*/
|
|
171
|
+
export function removeSharedMemFs(suiteId) {
|
|
172
|
+
sharedMemFsInstances.delete(suiteId);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Clean up all shared memfs instances
|
|
176
|
+
*
|
|
177
|
+
* Useful for global test teardown.
|
|
178
|
+
*/
|
|
179
|
+
export function cleanupAllSharedMemFs() {
|
|
180
|
+
sharedMemFsInstances.clear();
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Read JSONL content from in-memory file and parse to objects
|
|
184
|
+
*
|
|
185
|
+
* @param mfs - MemFsInstance from createMemFs()
|
|
186
|
+
* @param filename - Filename (not full path) to read
|
|
187
|
+
* @returns Array of parsed objects (skips invalid lines)
|
|
188
|
+
*/
|
|
189
|
+
export function readJsonlMem(mfs, filename) {
|
|
190
|
+
const content = readFileMem(mfs, filename);
|
|
191
|
+
const results = [];
|
|
192
|
+
for (const line of content.split('\n')) {
|
|
193
|
+
const trimmed = line.trim();
|
|
194
|
+
if (!trimmed)
|
|
195
|
+
continue;
|
|
196
|
+
try {
|
|
197
|
+
results.push(JSON.parse(trimmed));
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
// Skip invalid JSON lines
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return results;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Read JSONL content with stats (mirrors readJsonlSyncWithStats)
|
|
207
|
+
*
|
|
208
|
+
* @param mfs - MemFsInstance from createMemFs()
|
|
209
|
+
* @param filename - Filename (not full path) to read
|
|
210
|
+
* @returns Object with data array and stats
|
|
211
|
+
*/
|
|
212
|
+
export function readJsonlMemWithStats(mfs, filename) {
|
|
213
|
+
const content = readFileMem(mfs, filename);
|
|
214
|
+
const data = [];
|
|
215
|
+
let totalLines = 0;
|
|
216
|
+
let skippedLines = 0;
|
|
217
|
+
let emptyLines = 0;
|
|
218
|
+
for (const line of content.split('\n')) {
|
|
219
|
+
totalLines++;
|
|
220
|
+
const trimmed = line.trim();
|
|
221
|
+
if (!trimmed) {
|
|
222
|
+
emptyLines++;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
try {
|
|
226
|
+
data.push(JSON.parse(trimmed));
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
skippedLines++;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return { data, stats: { totalLines, skippedLines, emptyLines } };
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Async generator for streaming JSONL from memfs (mirrors streamJsonl)
|
|
236
|
+
*
|
|
237
|
+
* @param mfs - MemFsInstance from createMemFs()
|
|
238
|
+
* @param filename - Filename (not full path) to read
|
|
239
|
+
* @yields Parsed objects from each line
|
|
240
|
+
*/
|
|
241
|
+
export async function* streamJsonlMem(mfs, filename) {
|
|
242
|
+
const content = readFileMem(mfs, filename);
|
|
243
|
+
for (const line of content.split('\n')) {
|
|
244
|
+
const trimmed = line.trim();
|
|
245
|
+
if (!trimmed)
|
|
246
|
+
continue;
|
|
247
|
+
try {
|
|
248
|
+
yield JSON.parse(trimmed);
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
// Skip invalid JSON lines
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* List files matching a pattern prefix in the memfs directory
|
|
257
|
+
*
|
|
258
|
+
* @param mfs - MemFsInstance from createMemFs()
|
|
259
|
+
* @param prefix - Filename prefix to match (e.g., 'traces-')
|
|
260
|
+
* @returns Array of matching filenames
|
|
261
|
+
*/
|
|
262
|
+
export function listFilesMem(mfs, prefix) {
|
|
263
|
+
const files = readdirMem(mfs);
|
|
264
|
+
return files.filter(f => f.startsWith(prefix)).sort();
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* List files matching a date range pattern
|
|
268
|
+
*
|
|
269
|
+
* @param mfs - MemFsInstance from createMemFs()
|
|
270
|
+
* @param type - Telemetry type prefix (e.g., 'traces', 'logs')
|
|
271
|
+
* @param startDate - Optional start date (YYYY-MM-DD)
|
|
272
|
+
* @param endDate - Optional end date (YYYY-MM-DD)
|
|
273
|
+
* @returns Array of matching full paths
|
|
274
|
+
*/
|
|
275
|
+
export function listFilesInRangeMem(mfs, type, startDate, endDate) {
|
|
276
|
+
const allFiles = listFilesMem(mfs, `${type}-`);
|
|
277
|
+
const result = [];
|
|
278
|
+
for (const filename of allFiles) {
|
|
279
|
+
// Extract date from filename (e.g., traces-2026-01-31.jsonl -> 2026-01-31)
|
|
280
|
+
const match = filename.match(/\d{4}-\d{2}-\d{2}/);
|
|
281
|
+
if (!match)
|
|
282
|
+
continue;
|
|
283
|
+
const fileDate = match[0];
|
|
284
|
+
if (startDate && fileDate < startDate)
|
|
285
|
+
continue;
|
|
286
|
+
if (endDate && fileDate > endDate)
|
|
287
|
+
continue;
|
|
288
|
+
result.push(path.join(mfs.dir, filename));
|
|
289
|
+
}
|
|
290
|
+
return result;
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=memfs-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memfs-utils.js","sourceRoot":"","sources":["../../src/test-helpers/memfs-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memfs-utils.test.d.ts","sourceRoot":"","sources":["../../src/test-helpers/memfs-utils.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for in-memory file system utilities
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, after, beforeEach } from 'node:test';
|
|
5
|
+
import * as assert from 'node:assert';
|
|
6
|
+
import { createMemFs, writeJsonlMem, writeFileMem, readFileMem, readJsonlMem, readJsonlMemWithStats, streamJsonlMem, existsMem, mkdirMem, readdirMem, listFilesMem, listFilesInRangeMem, getTestDateMem, getSharedMemFs, resetSharedMemFs, removeSharedMemFs, cleanupAllSharedMemFs, } from './memfs-utils.js';
|
|
7
|
+
describe('memfs-utils', () => {
|
|
8
|
+
describe('createMemFs', () => {
|
|
9
|
+
it('should create isolated memfs instance', () => {
|
|
10
|
+
const mfs1 = createMemFs();
|
|
11
|
+
const mfs2 = createMemFs();
|
|
12
|
+
assert.ok(mfs1.dir !== mfs2.dir, 'Each instance should have unique directory');
|
|
13
|
+
assert.ok(mfs1.fs !== mfs2.fs, 'Each instance should have unique fs');
|
|
14
|
+
});
|
|
15
|
+
it('should create base directory on initialization', () => {
|
|
16
|
+
const mfs = createMemFs();
|
|
17
|
+
assert.ok(mfs.vol.existsSync(mfs.dir), 'Base directory should exist');
|
|
18
|
+
});
|
|
19
|
+
it('should support custom prefix', () => {
|
|
20
|
+
const mfs = createMemFs('custom');
|
|
21
|
+
assert.ok(mfs.dir.includes('custom'), 'Directory should include prefix');
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe('writeJsonlMem and readJsonlMem', () => {
|
|
25
|
+
let mfs;
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
mfs = createMemFs('jsonl');
|
|
28
|
+
});
|
|
29
|
+
it('should write and read JSONL data', () => {
|
|
30
|
+
const data = [
|
|
31
|
+
{ id: 1, name: 'first' },
|
|
32
|
+
{ id: 2, name: 'second' },
|
|
33
|
+
];
|
|
34
|
+
writeJsonlMem(mfs, 'test.jsonl', data);
|
|
35
|
+
const result = readJsonlMem(mfs, 'test.jsonl');
|
|
36
|
+
assert.strictEqual(result.length, 2);
|
|
37
|
+
assert.deepStrictEqual(result[0], { id: 1, name: 'first' });
|
|
38
|
+
assert.deepStrictEqual(result[1], { id: 2, name: 'second' });
|
|
39
|
+
});
|
|
40
|
+
it('should handle empty array', () => {
|
|
41
|
+
writeJsonlMem(mfs, 'empty.jsonl', []);
|
|
42
|
+
const result = readJsonlMem(mfs, 'empty.jsonl');
|
|
43
|
+
assert.strictEqual(result.length, 0);
|
|
44
|
+
});
|
|
45
|
+
it('should skip invalid JSON lines', () => {
|
|
46
|
+
writeFileMem(mfs, 'mixed.jsonl', '{"id":1}\ninvalid json\n{"id":2}');
|
|
47
|
+
const result = readJsonlMem(mfs, 'mixed.jsonl');
|
|
48
|
+
assert.strictEqual(result.length, 2);
|
|
49
|
+
assert.strictEqual(result[0].id, 1);
|
|
50
|
+
assert.strictEqual(result[1].id, 2);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe('readJsonlMemWithStats', () => {
|
|
54
|
+
let mfs;
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
mfs = createMemFs('stats');
|
|
57
|
+
});
|
|
58
|
+
it('should track line statistics', () => {
|
|
59
|
+
writeFileMem(mfs, 'test.jsonl', '{"id":1}\n\ninvalid\n{"id":2}');
|
|
60
|
+
const { data, stats } = readJsonlMemWithStats(mfs, 'test.jsonl');
|
|
61
|
+
assert.strictEqual(data.length, 2);
|
|
62
|
+
assert.strictEqual(stats.totalLines, 4);
|
|
63
|
+
assert.strictEqual(stats.emptyLines, 1);
|
|
64
|
+
assert.strictEqual(stats.skippedLines, 1);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe('streamJsonlMem', () => {
|
|
68
|
+
let mfs;
|
|
69
|
+
beforeEach(() => {
|
|
70
|
+
mfs = createMemFs('stream');
|
|
71
|
+
});
|
|
72
|
+
it('should stream JSONL data', async () => {
|
|
73
|
+
const data = [
|
|
74
|
+
{ id: 1, value: 'a' },
|
|
75
|
+
{ id: 2, value: 'b' },
|
|
76
|
+
{ id: 3, value: 'c' },
|
|
77
|
+
];
|
|
78
|
+
writeJsonlMem(mfs, 'stream.jsonl', data);
|
|
79
|
+
const results = [];
|
|
80
|
+
for await (const item of streamJsonlMem(mfs, 'stream.jsonl')) {
|
|
81
|
+
results.push(item);
|
|
82
|
+
}
|
|
83
|
+
assert.strictEqual(results.length, 3);
|
|
84
|
+
assert.deepStrictEqual(results, data);
|
|
85
|
+
});
|
|
86
|
+
it('should skip invalid lines when streaming', async () => {
|
|
87
|
+
writeFileMem(mfs, 'mixed.jsonl', '{"id":1}\nbad line\n{"id":2}');
|
|
88
|
+
const results = [];
|
|
89
|
+
for await (const item of streamJsonlMem(mfs, 'mixed.jsonl')) {
|
|
90
|
+
results.push(item);
|
|
91
|
+
}
|
|
92
|
+
assert.strictEqual(results.length, 2);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
describe('file operations', () => {
|
|
96
|
+
let mfs;
|
|
97
|
+
beforeEach(() => {
|
|
98
|
+
mfs = createMemFs('fileops');
|
|
99
|
+
});
|
|
100
|
+
it('should check file existence', () => {
|
|
101
|
+
assert.strictEqual(existsMem(mfs, 'nonexistent.txt'), false);
|
|
102
|
+
writeFileMem(mfs, 'exists.txt', 'content');
|
|
103
|
+
assert.strictEqual(existsMem(mfs, 'exists.txt'), true);
|
|
104
|
+
});
|
|
105
|
+
it('should create subdirectories', () => {
|
|
106
|
+
mkdirMem(mfs, 'subdir/nested');
|
|
107
|
+
writeFileMem(mfs, 'subdir/nested/file.txt', 'nested content');
|
|
108
|
+
const content = readFileMem(mfs, 'subdir/nested/file.txt');
|
|
109
|
+
assert.strictEqual(content, 'nested content');
|
|
110
|
+
});
|
|
111
|
+
it('should list directory contents', () => {
|
|
112
|
+
writeFileMem(mfs, 'file1.txt', 'a');
|
|
113
|
+
writeFileMem(mfs, 'file2.txt', 'b');
|
|
114
|
+
mkdirMem(mfs, 'subdir');
|
|
115
|
+
const files = readdirMem(mfs);
|
|
116
|
+
assert.ok(files.includes('file1.txt'));
|
|
117
|
+
assert.ok(files.includes('file2.txt'));
|
|
118
|
+
assert.ok(files.includes('subdir'));
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
describe('listFilesMem', () => {
|
|
122
|
+
let mfs;
|
|
123
|
+
beforeEach(() => {
|
|
124
|
+
mfs = createMemFs('listfiles');
|
|
125
|
+
});
|
|
126
|
+
it('should list files matching prefix', () => {
|
|
127
|
+
writeFileMem(mfs, 'traces-2026-01-28.jsonl', '{}');
|
|
128
|
+
writeFileMem(mfs, 'traces-2026-01-29.jsonl', '{}');
|
|
129
|
+
writeFileMem(mfs, 'logs-2026-01-28.jsonl', '{}');
|
|
130
|
+
const traces = listFilesMem(mfs, 'traces-');
|
|
131
|
+
assert.strictEqual(traces.length, 2);
|
|
132
|
+
assert.ok(traces.includes('traces-2026-01-28.jsonl'));
|
|
133
|
+
assert.ok(traces.includes('traces-2026-01-29.jsonl'));
|
|
134
|
+
const logs = listFilesMem(mfs, 'logs-');
|
|
135
|
+
assert.strictEqual(logs.length, 1);
|
|
136
|
+
});
|
|
137
|
+
it('should return sorted files', () => {
|
|
138
|
+
writeFileMem(mfs, 'traces-2026-01-31.jsonl', '{}');
|
|
139
|
+
writeFileMem(mfs, 'traces-2026-01-28.jsonl', '{}');
|
|
140
|
+
writeFileMem(mfs, 'traces-2026-01-30.jsonl', '{}');
|
|
141
|
+
const traces = listFilesMem(mfs, 'traces-');
|
|
142
|
+
assert.deepStrictEqual(traces, [
|
|
143
|
+
'traces-2026-01-28.jsonl',
|
|
144
|
+
'traces-2026-01-30.jsonl',
|
|
145
|
+
'traces-2026-01-31.jsonl',
|
|
146
|
+
]);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
describe('listFilesInRangeMem', () => {
|
|
150
|
+
let mfs;
|
|
151
|
+
beforeEach(() => {
|
|
152
|
+
mfs = createMemFs('daterange');
|
|
153
|
+
writeFileMem(mfs, 'traces-2026-01-28.jsonl', '{}');
|
|
154
|
+
writeFileMem(mfs, 'traces-2026-01-29.jsonl', '{}');
|
|
155
|
+
writeFileMem(mfs, 'traces-2026-01-30.jsonl', '{}');
|
|
156
|
+
writeFileMem(mfs, 'traces-2026-01-31.jsonl', '{}');
|
|
157
|
+
});
|
|
158
|
+
it('should filter by date range', () => {
|
|
159
|
+
const files = listFilesInRangeMem(mfs, 'traces', '2026-01-29', '2026-01-30');
|
|
160
|
+
assert.strictEqual(files.length, 2);
|
|
161
|
+
assert.ok(files[0].includes('2026-01-29'));
|
|
162
|
+
assert.ok(files[1].includes('2026-01-30'));
|
|
163
|
+
});
|
|
164
|
+
it('should return all files when no date range', () => {
|
|
165
|
+
const files = listFilesInRangeMem(mfs, 'traces');
|
|
166
|
+
assert.strictEqual(files.length, 4);
|
|
167
|
+
});
|
|
168
|
+
it('should filter by start date only', () => {
|
|
169
|
+
const files = listFilesInRangeMem(mfs, 'traces', '2026-01-30');
|
|
170
|
+
assert.strictEqual(files.length, 2);
|
|
171
|
+
});
|
|
172
|
+
it('should filter by end date only', () => {
|
|
173
|
+
const files = listFilesInRangeMem(mfs, 'traces', undefined, '2026-01-29');
|
|
174
|
+
assert.strictEqual(files.length, 2);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
describe('reset', () => {
|
|
178
|
+
it('should clear all files on reset', () => {
|
|
179
|
+
const mfs = createMemFs('reset');
|
|
180
|
+
writeFileMem(mfs, 'file1.txt', 'a');
|
|
181
|
+
writeFileMem(mfs, 'file2.txt', 'b');
|
|
182
|
+
assert.strictEqual(readdirMem(mfs).length, 2);
|
|
183
|
+
mfs.reset();
|
|
184
|
+
assert.strictEqual(readdirMem(mfs).length, 0);
|
|
185
|
+
assert.ok(mfs.vol.existsSync(mfs.dir), 'Base directory should still exist');
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
describe('shared memfs instances', () => {
|
|
189
|
+
const SUITE_ID = 'test-shared-suite';
|
|
190
|
+
after(() => {
|
|
191
|
+
removeSharedMemFs(SUITE_ID);
|
|
192
|
+
});
|
|
193
|
+
it('should return same instance for same suite ID', () => {
|
|
194
|
+
const mfs1 = getSharedMemFs(SUITE_ID);
|
|
195
|
+
const mfs2 = getSharedMemFs(SUITE_ID);
|
|
196
|
+
assert.strictEqual(mfs1, mfs2);
|
|
197
|
+
});
|
|
198
|
+
it('should reset shared instance files', () => {
|
|
199
|
+
const mfs = getSharedMemFs(SUITE_ID);
|
|
200
|
+
writeFileMem(mfs, 'shared.txt', 'content');
|
|
201
|
+
assert.ok(existsMem(mfs, 'shared.txt'));
|
|
202
|
+
resetSharedMemFs(SUITE_ID);
|
|
203
|
+
assert.strictEqual(existsMem(mfs, 'shared.txt'), false);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
describe('getTestDateMem', () => {
|
|
207
|
+
it('should return date in YYYY-MM-DD format', () => {
|
|
208
|
+
const date = getTestDateMem();
|
|
209
|
+
assert.match(date, /^\d{4}-\d{2}-\d{2}$/);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
describe('cleanupAllSharedMemFs', () => {
|
|
213
|
+
it('should clear all shared instances', () => {
|
|
214
|
+
getSharedMemFs('suite1');
|
|
215
|
+
getSharedMemFs('suite2');
|
|
216
|
+
cleanupAllSharedMemFs();
|
|
217
|
+
// After cleanup, getting same IDs should create new instances
|
|
218
|
+
const newMfs = getSharedMemFs('suite1');
|
|
219
|
+
assert.ok(newMfs, 'Should be able to create new instance after cleanup');
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
describe('memfs-utils: realistic test patterns', () => {
|
|
224
|
+
describe('trace data pattern', () => {
|
|
225
|
+
let mfs;
|
|
226
|
+
beforeEach(() => {
|
|
227
|
+
mfs = createMemFs('traces');
|
|
228
|
+
});
|
|
229
|
+
it('should handle trace span data', () => {
|
|
230
|
+
const today = getTestDateMem();
|
|
231
|
+
const spans = [
|
|
232
|
+
{
|
|
233
|
+
traceId: 'trace1',
|
|
234
|
+
spanId: 'span1',
|
|
235
|
+
name: 'http-request',
|
|
236
|
+
startTime: [1700000000, 0],
|
|
237
|
+
attributes: { 'http.method': 'GET' },
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
traceId: 'trace1',
|
|
241
|
+
spanId: 'span2',
|
|
242
|
+
name: 'db-query',
|
|
243
|
+
startTime: [1700000001, 0],
|
|
244
|
+
attributes: { 'db.system': 'postgres' },
|
|
245
|
+
},
|
|
246
|
+
];
|
|
247
|
+
writeJsonlMem(mfs, `traces-${today}.jsonl`, spans);
|
|
248
|
+
const loaded = readJsonlMem(mfs, `traces-${today}.jsonl`);
|
|
249
|
+
assert.strictEqual(loaded.length, 2);
|
|
250
|
+
assert.strictEqual(loaded[0].traceId, 'trace1');
|
|
251
|
+
assert.strictEqual(loaded[1].name, 'db-query');
|
|
252
|
+
});
|
|
253
|
+
it('should handle trace data filtering pattern', async () => {
|
|
254
|
+
const spans = Array.from({ length: 100 }, (_, i) => ({
|
|
255
|
+
traceId: `trace-${i % 10}`,
|
|
256
|
+
spanId: `span-${i}`,
|
|
257
|
+
name: i % 2 === 0 ? 'http-request' : 'db-query',
|
|
258
|
+
startTime: [1700000000 + i, 0],
|
|
259
|
+
}));
|
|
260
|
+
writeJsonlMem(mfs, 'traces-2026-01-31.jsonl', spans);
|
|
261
|
+
// Simulate filtering by traceId using streaming
|
|
262
|
+
const filteredSpans = [];
|
|
263
|
+
for await (const span of streamJsonlMem(mfs, 'traces-2026-01-31.jsonl')) {
|
|
264
|
+
if (span.traceId === 'trace-5') {
|
|
265
|
+
filteredSpans.push(span);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
assert.strictEqual(filteredSpans.length, 10);
|
|
269
|
+
assert.ok(filteredSpans.every(s => s.traceId === 'trace-5'));
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
describe('log data pattern', () => {
|
|
273
|
+
let mfs;
|
|
274
|
+
beforeEach(() => {
|
|
275
|
+
mfs = createMemFs('logs');
|
|
276
|
+
});
|
|
277
|
+
it('should handle log record data', () => {
|
|
278
|
+
const logs = [
|
|
279
|
+
{ timestamp: '2026-01-31T10:00:00Z', severityText: 'INFO', body: 'Application started' },
|
|
280
|
+
{ timestamp: '2026-01-31T10:00:01Z', severityText: 'ERROR', body: 'Connection failed' },
|
|
281
|
+
];
|
|
282
|
+
writeJsonlMem(mfs, 'logs-2026-01-31.jsonl', logs);
|
|
283
|
+
const loaded = readJsonlMem(mfs, 'logs-2026-01-31.jsonl');
|
|
284
|
+
assert.strictEqual(loaded.length, 2);
|
|
285
|
+
assert.strictEqual(loaded[1].severityText, 'ERROR');
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
describe('index data pattern', () => {
|
|
289
|
+
let mfs;
|
|
290
|
+
beforeEach(() => {
|
|
291
|
+
mfs = createMemFs('index');
|
|
292
|
+
});
|
|
293
|
+
it('should handle index file storage', () => {
|
|
294
|
+
// Simulate index structure
|
|
295
|
+
const index = {
|
|
296
|
+
version: 1,
|
|
297
|
+
sourceFile: '/path/to/traces.jsonl',
|
|
298
|
+
sourceMtime: Date.now(),
|
|
299
|
+
entries: [
|
|
300
|
+
{ lineNumber: 1, timestamp: 1700000000000, traceId: 'trace1', spanName: 'op1' },
|
|
301
|
+
{ lineNumber: 2, timestamp: 1700000001000, traceId: 'trace2', spanName: 'op2' },
|
|
302
|
+
],
|
|
303
|
+
};
|
|
304
|
+
writeFileMem(mfs, 'traces.jsonl.idx', JSON.stringify(index));
|
|
305
|
+
const loaded = JSON.parse(readFileMem(mfs, 'traces.jsonl.idx'));
|
|
306
|
+
assert.strictEqual(loaded.version, 1);
|
|
307
|
+
assert.strictEqual(loaded.entries.length, 2);
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
describe('multi-file query pattern', () => {
|
|
311
|
+
let mfs;
|
|
312
|
+
beforeEach(() => {
|
|
313
|
+
mfs = createMemFs('multifile');
|
|
314
|
+
// Create files for multiple dates
|
|
315
|
+
for (let day = 28; day <= 31; day++) {
|
|
316
|
+
const date = `2026-01-${day}`;
|
|
317
|
+
const spans = [{ traceId: `trace-${day}`, spanId: 's1', name: 'op', startTime: [1700000000, 0] }];
|
|
318
|
+
writeJsonlMem(mfs, `traces-${date}.jsonl`, spans);
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
it('should query across date range', async () => {
|
|
322
|
+
const files = listFilesInRangeMem(mfs, 'traces', '2026-01-29', '2026-01-30');
|
|
323
|
+
assert.strictEqual(files.length, 2);
|
|
324
|
+
// Aggregate results from all files
|
|
325
|
+
const allSpans = [];
|
|
326
|
+
for (const file of files) {
|
|
327
|
+
const filename = file.split('/').pop();
|
|
328
|
+
for await (const span of streamJsonlMem(mfs, filename)) {
|
|
329
|
+
allSpans.push(span);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
assert.strictEqual(allSpans.length, 2);
|
|
333
|
+
assert.ok(allSpans.some(s => s.traceId === 'trace-29'));
|
|
334
|
+
assert.ok(allSpans.some(s => s.traceId === 'trace-30'));
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
//# sourceMappingURL=memfs-utils.test.js.map
|