@pikku/inspector 0.9.6-next.0 → 0.10.0
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/CHANGELOG.md +6 -0
- package/dist/add/add-channel.d.ts +5 -1
- package/dist/add/add-channel.js +51 -32
- package/dist/add/add-cli.d.ts +4 -0
- package/dist/add/add-cli.js +128 -23
- package/dist/add/add-file-extends-core-type.js +3 -2
- package/dist/add/add-file-with-factory.d.ts +2 -2
- package/dist/add/add-file-with-factory.js +34 -1
- package/dist/add/add-functions.js +52 -5
- package/dist/add/add-http-route.js +19 -12
- package/dist/add/add-mcp-prompt.js +20 -13
- package/dist/add/add-mcp-resource.js +24 -14
- package/dist/add/add-mcp-tool.js +23 -13
- package/dist/add/add-middleware.js +51 -12
- package/dist/add/add-permission.d.ts +1 -2
- package/dist/add/add-permission.js +275 -19
- package/dist/add/add-queue-worker.js +10 -12
- package/dist/add/add-schedule.js +9 -10
- package/dist/error-codes.d.ts +35 -0
- package/dist/error-codes.js +40 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/inspector.js +20 -1
- package/dist/types.d.ts +31 -3
- package/dist/utils/ensure-function-metadata.d.ts +6 -0
- package/dist/utils/ensure-function-metadata.js +18 -0
- package/dist/utils/extract-function-name.d.ts +2 -2
- package/dist/utils/extract-function-name.js +13 -8
- package/dist/utils/filter-inspector-state.d.ts +6 -0
- package/dist/utils/filter-inspector-state.js +382 -0
- package/dist/utils/filter-utils.d.ts +10 -0
- package/dist/utils/filter-utils.js +66 -2
- package/dist/utils/find-root-dir.d.ts +23 -0
- package/dist/utils/find-root-dir.js +55 -0
- package/dist/utils/get-files-and-methods.d.ts +2 -1
- package/dist/utils/get-files-and-methods.js +2 -1
- package/dist/utils/get-property-value.d.ts +9 -0
- package/dist/utils/get-property-value.js +20 -0
- package/dist/utils/middleware.d.ts +1 -1
- package/dist/utils/middleware.js +7 -7
- package/dist/utils/permissions.d.ts +43 -0
- package/dist/utils/permissions.js +178 -0
- package/dist/utils/post-process.d.ts +16 -0
- package/dist/utils/post-process.js +132 -0
- package/dist/utils/serialize-inspector-state.d.ts +179 -0
- package/dist/utils/serialize-inspector-state.js +170 -0
- package/dist/visit.js +3 -2
- package/package.json +4 -4
- package/src/add/add-channel.ts +92 -40
- package/src/add/add-cli.ts +188 -29
- package/src/add/add-file-extends-core-type.ts +5 -2
- package/src/add/add-file-with-factory.ts +45 -2
- package/src/add/add-functions.ts +60 -5
- package/src/add/add-http-route.ts +46 -21
- package/src/add/add-mcp-prompt.ts +42 -21
- package/src/add/add-mcp-prompt.ts.tmp +0 -0
- package/src/add/add-mcp-resource.ts +50 -24
- package/src/add/add-mcp-resource.ts.tmp +0 -0
- package/src/add/add-mcp-tool.ts +48 -21
- package/src/add/add-middleware.ts +74 -15
- package/src/add/add-permission.ts +364 -22
- package/src/add/add-queue-worker.ts +22 -25
- package/src/add/add-schedule.ts +19 -20
- package/src/error-codes.ts +43 -0
- package/src/index.ts +7 -0
- package/src/inspector.ts +22 -1
- package/src/types.ts +38 -3
- package/src/utils/ensure-function-metadata.ts +24 -0
- package/src/utils/extract-function-name.ts +20 -8
- package/src/utils/filter-inspector-state.test.ts +1433 -0
- package/src/utils/filter-inspector-state.ts +526 -0
- package/src/utils/filter-utils.test.ts +350 -1
- package/src/utils/filter-utils.ts +82 -2
- package/src/utils/find-root-dir.ts +68 -0
- package/src/utils/get-files-and-methods.ts +8 -0
- package/src/utils/get-property-value.ts +27 -0
- package/src/utils/middleware.ts +14 -7
- package/src/utils/permissions.test.ts +327 -0
- package/src/utils/permissions.ts +262 -0
- package/src/utils/post-process.ts +178 -0
- package/src/utils/serialize-inspector-state.ts +375 -0
- package/src/utils/test-data/inspector-state.json +1680 -0
- package/src/visit.ts +4 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,1433 @@
|
|
|
1
|
+
import { test, describe } from 'node:test'
|
|
2
|
+
import { strict as assert } from 'node:assert'
|
|
3
|
+
import { filterInspectorState } from './filter-inspector-state.js'
|
|
4
|
+
import { InspectorState, InspectorFilters } from '../types.js'
|
|
5
|
+
import {
|
|
6
|
+
deserializeInspectorState,
|
|
7
|
+
SerializableInspectorState,
|
|
8
|
+
} from './serialize-inspector-state.js'
|
|
9
|
+
import { readFileSync } from 'node:fs'
|
|
10
|
+
import { fileURLToPath } from 'node:url'
|
|
11
|
+
import { dirname, join } from 'node:path'
|
|
12
|
+
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
14
|
+
const __dirname = dirname(__filename)
|
|
15
|
+
|
|
16
|
+
// Load the real inspector state from templates/functions
|
|
17
|
+
let realState: Omit<InspectorState, 'typesLookup'>
|
|
18
|
+
try {
|
|
19
|
+
const stateJson = readFileSync(
|
|
20
|
+
join(__dirname, 'test-data/inspector-state.json'),
|
|
21
|
+
'utf-8'
|
|
22
|
+
)
|
|
23
|
+
const serialized = JSON.parse(stateJson) as SerializableInspectorState
|
|
24
|
+
realState = deserializeInspectorState(serialized)
|
|
25
|
+
} catch (e) {
|
|
26
|
+
console.error('Failed to load real inspector state:', e)
|
|
27
|
+
throw e
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Helper to create a minimal mock InspectorState for testing (kept for compatibility)
|
|
31
|
+
function createMockInspectorState(): Omit<InspectorState, 'typesLookup'> {
|
|
32
|
+
return {
|
|
33
|
+
rootDir: '/test/project',
|
|
34
|
+
singletonServicesTypeImportMap: new Map(),
|
|
35
|
+
sessionServicesTypeImportMap: new Map(),
|
|
36
|
+
userSessionTypeImportMap: new Map(),
|
|
37
|
+
configTypeImportMap: new Map(),
|
|
38
|
+
singletonServicesFactories: new Map(),
|
|
39
|
+
sessionServicesFactories: new Map(),
|
|
40
|
+
sessionServicesMeta: new Map(),
|
|
41
|
+
configFactories: new Map(),
|
|
42
|
+
filesAndMethods: {},
|
|
43
|
+
filesAndMethodsErrors: new Map(),
|
|
44
|
+
http: {
|
|
45
|
+
metaInputTypes: new Map(),
|
|
46
|
+
meta: {
|
|
47
|
+
get: {
|
|
48
|
+
'/api/users': {
|
|
49
|
+
pikkuFuncName: 'getUsers',
|
|
50
|
+
route: '/api/users',
|
|
51
|
+
method: 'GET',
|
|
52
|
+
tags: ['api', 'public'],
|
|
53
|
+
middleware: [],
|
|
54
|
+
permissions: [],
|
|
55
|
+
},
|
|
56
|
+
'/admin/settings': {
|
|
57
|
+
pikkuFuncName: 'getAdminSettings',
|
|
58
|
+
route: '/admin/settings',
|
|
59
|
+
method: 'GET',
|
|
60
|
+
tags: ['admin'],
|
|
61
|
+
middleware: [{ type: 'wire', name: 'authMiddleware' }],
|
|
62
|
+
permissions: [{ type: 'wire', name: 'adminPermission' }],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
post: {
|
|
66
|
+
'/api/users': {
|
|
67
|
+
pikkuFuncName: 'createUser',
|
|
68
|
+
route: '/api/users',
|
|
69
|
+
method: 'POST',
|
|
70
|
+
tags: ['api'],
|
|
71
|
+
middleware: [],
|
|
72
|
+
permissions: [],
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
put: {},
|
|
76
|
+
patch: {},
|
|
77
|
+
delete: {},
|
|
78
|
+
head: {},
|
|
79
|
+
options: {},
|
|
80
|
+
},
|
|
81
|
+
files: new Set(['/test/project/src/api/users.ts']),
|
|
82
|
+
routeMiddleware: new Map(),
|
|
83
|
+
routePermissions: new Map(),
|
|
84
|
+
},
|
|
85
|
+
functions: {
|
|
86
|
+
typesMap: new Map(),
|
|
87
|
+
meta: {
|
|
88
|
+
getUsers: {
|
|
89
|
+
services: [],
|
|
90
|
+
optimized: false,
|
|
91
|
+
},
|
|
92
|
+
createUser: {
|
|
93
|
+
services: [],
|
|
94
|
+
optimized: false,
|
|
95
|
+
},
|
|
96
|
+
getAdminSettings: {
|
|
97
|
+
services: [],
|
|
98
|
+
optimized: false,
|
|
99
|
+
},
|
|
100
|
+
sendEmailWorker: {
|
|
101
|
+
services: [],
|
|
102
|
+
optimized: false,
|
|
103
|
+
},
|
|
104
|
+
dailyReport: {
|
|
105
|
+
services: [],
|
|
106
|
+
optimized: false,
|
|
107
|
+
},
|
|
108
|
+
mcpSearchTool: {
|
|
109
|
+
services: [],
|
|
110
|
+
optimized: false,
|
|
111
|
+
},
|
|
112
|
+
cliCommand: {
|
|
113
|
+
services: [],
|
|
114
|
+
optimized: false,
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
files: new Map([
|
|
118
|
+
[
|
|
119
|
+
'getUsers',
|
|
120
|
+
{ path: '/test/project/src/api/users.ts', exportedName: 'getUsers' },
|
|
121
|
+
],
|
|
122
|
+
[
|
|
123
|
+
'createUser',
|
|
124
|
+
{
|
|
125
|
+
path: '/test/project/src/api/users.ts',
|
|
126
|
+
exportedName: 'createUser',
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
[
|
|
130
|
+
'getAdminSettings',
|
|
131
|
+
{
|
|
132
|
+
path: '/test/project/src/admin/settings.ts',
|
|
133
|
+
exportedName: 'getAdminSettings',
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
[
|
|
137
|
+
'sendEmailWorker',
|
|
138
|
+
{
|
|
139
|
+
path: '/test/project/src/workers/email.ts',
|
|
140
|
+
exportedName: 'sendEmailWorker',
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
[
|
|
144
|
+
'dailyReport',
|
|
145
|
+
{
|
|
146
|
+
path: '/test/project/src/tasks/reports.ts',
|
|
147
|
+
exportedName: 'dailyReport',
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
]),
|
|
151
|
+
},
|
|
152
|
+
channels: {
|
|
153
|
+
meta: {
|
|
154
|
+
'chat-channel': {
|
|
155
|
+
pikkuFuncName: 'handleChatMessage',
|
|
156
|
+
tags: ['realtime', 'public'],
|
|
157
|
+
middleware: [],
|
|
158
|
+
permissions: [],
|
|
159
|
+
},
|
|
160
|
+
'admin-channel': {
|
|
161
|
+
pikkuFuncName: 'handleAdminMessage',
|
|
162
|
+
tags: ['realtime', 'admin'],
|
|
163
|
+
middleware: [{ type: 'wire', name: 'authMiddleware' }],
|
|
164
|
+
permissions: [],
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
files: new Set(['/test/project/src/channels/chat.ts']),
|
|
168
|
+
},
|
|
169
|
+
scheduledTasks: {
|
|
170
|
+
meta: {
|
|
171
|
+
'daily-report': {
|
|
172
|
+
pikkuFuncName: 'dailyReport',
|
|
173
|
+
schedule: '0 0 * * *',
|
|
174
|
+
tags: ['cron', 'reports'],
|
|
175
|
+
middleware: [],
|
|
176
|
+
},
|
|
177
|
+
'hourly-cleanup': {
|
|
178
|
+
pikkuFuncName: 'hourlyCleanup',
|
|
179
|
+
schedule: '0 * * * *',
|
|
180
|
+
tags: ['cron', 'maintenance'],
|
|
181
|
+
middleware: [],
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
files: new Set(['/test/project/src/tasks/reports.ts']),
|
|
185
|
+
},
|
|
186
|
+
queueWorkers: {
|
|
187
|
+
meta: {
|
|
188
|
+
'email-worker': {
|
|
189
|
+
pikkuFuncName: 'sendEmailWorker',
|
|
190
|
+
queueName: 'email-queue',
|
|
191
|
+
tags: ['queue', 'email'],
|
|
192
|
+
middleware: [],
|
|
193
|
+
},
|
|
194
|
+
'notification-worker': {
|
|
195
|
+
pikkuFuncName: 'sendNotificationWorker',
|
|
196
|
+
queueName: 'notification-queue',
|
|
197
|
+
tags: ['queue', 'notifications'],
|
|
198
|
+
middleware: [],
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
files: new Set(['/test/project/src/workers/email.ts']),
|
|
202
|
+
},
|
|
203
|
+
rpc: {
|
|
204
|
+
internalMeta: {},
|
|
205
|
+
internalFiles: new Map(),
|
|
206
|
+
exposedMeta: {},
|
|
207
|
+
exposedFiles: new Map(),
|
|
208
|
+
invokedFunctions: new Set(),
|
|
209
|
+
},
|
|
210
|
+
mcpEndpoints: {
|
|
211
|
+
toolsMeta: {
|
|
212
|
+
'search-tool': {
|
|
213
|
+
name: 'search-tool',
|
|
214
|
+
description: 'Search tool',
|
|
215
|
+
pikkuFuncName: 'mcpSearchTool',
|
|
216
|
+
tags: ['mcp', 'search'],
|
|
217
|
+
middleware: [],
|
|
218
|
+
permissions: [],
|
|
219
|
+
} as any,
|
|
220
|
+
'analyze-tool': {
|
|
221
|
+
name: 'analyze-tool',
|
|
222
|
+
description: 'Analyze tool',
|
|
223
|
+
pikkuFuncName: 'mcpAnalyzeTool',
|
|
224
|
+
tags: ['mcp', 'analytics'],
|
|
225
|
+
middleware: [],
|
|
226
|
+
permissions: [],
|
|
227
|
+
} as any,
|
|
228
|
+
},
|
|
229
|
+
resourcesMeta: {
|
|
230
|
+
'docs-resource': {
|
|
231
|
+
title: 'Docs Resource',
|
|
232
|
+
description: 'Documentation resource',
|
|
233
|
+
uri: 'docs://resource',
|
|
234
|
+
pikkuFuncName: 'mcpDocsResource',
|
|
235
|
+
tags: ['mcp', 'docs'],
|
|
236
|
+
middleware: [],
|
|
237
|
+
permissions: [],
|
|
238
|
+
} as any,
|
|
239
|
+
},
|
|
240
|
+
promptsMeta: {
|
|
241
|
+
'help-prompt': {
|
|
242
|
+
name: 'help-prompt',
|
|
243
|
+
description: 'Help prompt',
|
|
244
|
+
pikkuFuncName: 'mcpHelpPrompt',
|
|
245
|
+
tags: ['mcp', 'help'],
|
|
246
|
+
middleware: [],
|
|
247
|
+
permissions: [],
|
|
248
|
+
} as any,
|
|
249
|
+
},
|
|
250
|
+
files: new Set(['/test/project/src/mcp/tools.ts']),
|
|
251
|
+
},
|
|
252
|
+
cli: {
|
|
253
|
+
meta: {
|
|
254
|
+
programs: {
|
|
255
|
+
'my-cli': {
|
|
256
|
+
commands: {
|
|
257
|
+
build: {
|
|
258
|
+
pikkuFuncName: 'cliCommand',
|
|
259
|
+
tags: ['cli', 'build'],
|
|
260
|
+
middleware: [],
|
|
261
|
+
positionals: [],
|
|
262
|
+
options: {},
|
|
263
|
+
} as any,
|
|
264
|
+
test: {
|
|
265
|
+
pikkuFuncName: 'cliTestCommand',
|
|
266
|
+
tags: ['cli', 'test'],
|
|
267
|
+
middleware: [],
|
|
268
|
+
positionals: [],
|
|
269
|
+
options: {},
|
|
270
|
+
} as any,
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
files: new Set(['/test/project/src/cli/commands.ts']),
|
|
276
|
+
},
|
|
277
|
+
middleware: {
|
|
278
|
+
meta: {},
|
|
279
|
+
tagMiddleware: new Map(),
|
|
280
|
+
},
|
|
281
|
+
permissions: {
|
|
282
|
+
meta: {},
|
|
283
|
+
tagPermissions: new Map(),
|
|
284
|
+
},
|
|
285
|
+
serviceAggregation: {
|
|
286
|
+
requiredServices: new Set(),
|
|
287
|
+
usedFunctions: new Set(),
|
|
288
|
+
usedMiddleware: new Set(),
|
|
289
|
+
usedPermissions: new Set(),
|
|
290
|
+
},
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Mock logger for testing
|
|
295
|
+
const mockLogger = {
|
|
296
|
+
info: () => {},
|
|
297
|
+
error: () => {},
|
|
298
|
+
warn: () => {},
|
|
299
|
+
debug: () => {},
|
|
300
|
+
critical: () => {},
|
|
301
|
+
hasCriticalErrors: () => false,
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
describe('filterInspectorState', () => {
|
|
305
|
+
describe('No filters - returns original state', () => {
|
|
306
|
+
test('should return original state when no filters provided', () => {
|
|
307
|
+
const state = createMockInspectorState()
|
|
308
|
+
const filters: InspectorFilters = {}
|
|
309
|
+
|
|
310
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
311
|
+
|
|
312
|
+
assert.equal(result, state) // Should be the same reference
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
test('should return original state when all filter arrays are empty', () => {
|
|
316
|
+
const state = createMockInspectorState()
|
|
317
|
+
const filters: InspectorFilters = {
|
|
318
|
+
names: [],
|
|
319
|
+
tags: [],
|
|
320
|
+
types: [],
|
|
321
|
+
directories: [],
|
|
322
|
+
httpRoutes: [],
|
|
323
|
+
httpMethods: [],
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
327
|
+
|
|
328
|
+
assert.equal(result, state)
|
|
329
|
+
})
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
describe('HTTP filtering', () => {
|
|
333
|
+
test('should filter HTTP routes by type', () => {
|
|
334
|
+
const state = createMockInspectorState()
|
|
335
|
+
const filters: InspectorFilters = {
|
|
336
|
+
types: ['channel'], // Only channels, not HTTP
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
340
|
+
|
|
341
|
+
// HTTP routes should be empty
|
|
342
|
+
assert.equal(Object.keys(result.http.meta.get).length, 0)
|
|
343
|
+
assert.equal(Object.keys(result.http.meta.post).length, 0)
|
|
344
|
+
|
|
345
|
+
// Channels should still exist
|
|
346
|
+
assert.equal(Object.keys(result.channels.meta).length, 2)
|
|
347
|
+
})
|
|
348
|
+
|
|
349
|
+
test('should filter HTTP routes by tags', () => {
|
|
350
|
+
const state = createMockInspectorState()
|
|
351
|
+
const filters: InspectorFilters = {
|
|
352
|
+
types: ['http'],
|
|
353
|
+
tags: ['admin'],
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
357
|
+
|
|
358
|
+
// Only admin route should remain
|
|
359
|
+
assert.equal(Object.keys(result.http.meta.get).length, 1)
|
|
360
|
+
assert.ok(result.http.meta.get['/admin/settings'])
|
|
361
|
+
assert.equal(Object.keys(result.http.meta.post).length, 0)
|
|
362
|
+
})
|
|
363
|
+
|
|
364
|
+
test('should filter HTTP routes by httpMethod', () => {
|
|
365
|
+
const state = createMockInspectorState()
|
|
366
|
+
const filters: InspectorFilters = {
|
|
367
|
+
httpMethods: ['GET'],
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
371
|
+
|
|
372
|
+
// Only GET routes should remain
|
|
373
|
+
assert.equal(Object.keys(result.http.meta.get).length, 2)
|
|
374
|
+
assert.equal(Object.keys(result.http.meta.post).length, 0)
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
test('should filter HTTP routes by httpRoute pattern', () => {
|
|
378
|
+
const state = createMockInspectorState()
|
|
379
|
+
const filters: InspectorFilters = {
|
|
380
|
+
httpRoutes: ['/api/*'],
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
384
|
+
|
|
385
|
+
// Only /api/* routes should remain
|
|
386
|
+
assert.ok(result.http.meta.get['/api/users'])
|
|
387
|
+
assert.ok(result.http.meta.post['/api/users'])
|
|
388
|
+
assert.ok(!result.http.meta.get['/admin/settings'])
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
test('should filter HTTP routes by directory', () => {
|
|
392
|
+
const state = createMockInspectorState()
|
|
393
|
+
const filters: InspectorFilters = {
|
|
394
|
+
types: ['http'],
|
|
395
|
+
directories: ['src/admin'],
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
399
|
+
|
|
400
|
+
// Only admin routes should remain
|
|
401
|
+
assert.equal(Object.keys(result.http.meta.get).length, 1)
|
|
402
|
+
assert.ok(result.http.meta.get['/admin/settings'])
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
test('should filter HTTP routes by function name', () => {
|
|
406
|
+
const state = createMockInspectorState()
|
|
407
|
+
const filters: InspectorFilters = {
|
|
408
|
+
types: ['http'],
|
|
409
|
+
names: ['getUsers'],
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
413
|
+
|
|
414
|
+
assert.equal(Object.keys(result.http.meta.get).length, 1)
|
|
415
|
+
assert.ok(result.http.meta.get['/api/users'])
|
|
416
|
+
assert.equal(result.http.meta.get['/api/users'].pikkuFuncName, 'getUsers')
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
test('should filter HTTP routes by name wildcard', () => {
|
|
420
|
+
const state = createMockInspectorState()
|
|
421
|
+
const filters: InspectorFilters = {
|
|
422
|
+
types: ['http'],
|
|
423
|
+
names: ['get*'],
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
427
|
+
|
|
428
|
+
// Should match getUsers and getAdminSettings
|
|
429
|
+
assert.equal(Object.keys(result.http.meta.get).length, 2)
|
|
430
|
+
assert.equal(Object.keys(result.http.meta.post).length, 0)
|
|
431
|
+
})
|
|
432
|
+
|
|
433
|
+
test('should track middleware and permissions for filtered HTTP routes', () => {
|
|
434
|
+
const state = createMockInspectorState()
|
|
435
|
+
const filters: InspectorFilters = {
|
|
436
|
+
types: ['http'],
|
|
437
|
+
tags: ['admin'],
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
441
|
+
|
|
442
|
+
// Check that service aggregation includes the middleware and permissions
|
|
443
|
+
assert.ok(result.serviceAggregation.usedMiddleware.has('authMiddleware'))
|
|
444
|
+
assert.ok(
|
|
445
|
+
result.serviceAggregation.usedPermissions.has('adminPermission')
|
|
446
|
+
)
|
|
447
|
+
assert.ok(result.serviceAggregation.usedFunctions.has('getAdminSettings'))
|
|
448
|
+
})
|
|
449
|
+
})
|
|
450
|
+
|
|
451
|
+
describe('Channel filtering', () => {
|
|
452
|
+
test('should filter channels by type', () => {
|
|
453
|
+
const state = createMockInspectorState()
|
|
454
|
+
const filters: InspectorFilters = {
|
|
455
|
+
types: ['channel'],
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
459
|
+
|
|
460
|
+
// Channels should exist
|
|
461
|
+
assert.equal(Object.keys(result.channels.meta).length, 2)
|
|
462
|
+
|
|
463
|
+
// HTTP routes should be empty
|
|
464
|
+
assert.equal(Object.keys(result.http.meta.get).length, 0)
|
|
465
|
+
assert.equal(Object.keys(result.http.meta.post).length, 0)
|
|
466
|
+
})
|
|
467
|
+
|
|
468
|
+
test('should filter channels by tags', () => {
|
|
469
|
+
const state = createMockInspectorState()
|
|
470
|
+
const filters: InspectorFilters = {
|
|
471
|
+
types: ['channel'],
|
|
472
|
+
tags: ['admin'],
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
476
|
+
|
|
477
|
+
assert.equal(Object.keys(result.channels.meta).length, 1)
|
|
478
|
+
assert.ok(result.channels.meta['admin-channel'])
|
|
479
|
+
})
|
|
480
|
+
|
|
481
|
+
test('should filter channels by name', () => {
|
|
482
|
+
const state = createMockInspectorState()
|
|
483
|
+
const filters: InspectorFilters = {
|
|
484
|
+
names: ['chat-channel'],
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
488
|
+
|
|
489
|
+
assert.equal(Object.keys(result.channels.meta).length, 1)
|
|
490
|
+
assert.ok(result.channels.meta['chat-channel'])
|
|
491
|
+
})
|
|
492
|
+
|
|
493
|
+
test('should filter channels by name wildcard', () => {
|
|
494
|
+
const state = createMockInspectorState()
|
|
495
|
+
const filters: InspectorFilters = {
|
|
496
|
+
names: ['*-channel'],
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
500
|
+
|
|
501
|
+
assert.equal(Object.keys(result.channels.meta).length, 2)
|
|
502
|
+
})
|
|
503
|
+
|
|
504
|
+
test('should track middleware for filtered channels', () => {
|
|
505
|
+
const state = createMockInspectorState()
|
|
506
|
+
const filters: InspectorFilters = {
|
|
507
|
+
types: ['channel'],
|
|
508
|
+
tags: ['admin'],
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
512
|
+
|
|
513
|
+
assert.ok(result.serviceAggregation.usedMiddleware.has('authMiddleware'))
|
|
514
|
+
assert.ok(
|
|
515
|
+
result.serviceAggregation.usedFunctions.has('handleAdminMessage')
|
|
516
|
+
)
|
|
517
|
+
})
|
|
518
|
+
})
|
|
519
|
+
|
|
520
|
+
describe('Scheduled task filtering', () => {
|
|
521
|
+
test('should filter scheduled tasks by type', () => {
|
|
522
|
+
const state = createMockInspectorState()
|
|
523
|
+
const filters: InspectorFilters = {
|
|
524
|
+
types: ['scheduler'],
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
528
|
+
|
|
529
|
+
assert.equal(Object.keys(result.scheduledTasks.meta).length, 2)
|
|
530
|
+
|
|
531
|
+
// Other types should be empty
|
|
532
|
+
assert.equal(Object.keys(result.http.meta.get).length, 0)
|
|
533
|
+
assert.equal(Object.keys(result.channels.meta).length, 0)
|
|
534
|
+
})
|
|
535
|
+
|
|
536
|
+
test('should filter scheduled tasks by tags', () => {
|
|
537
|
+
const state = createMockInspectorState()
|
|
538
|
+
const filters: InspectorFilters = {
|
|
539
|
+
types: ['scheduler'],
|
|
540
|
+
tags: ['reports'],
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
544
|
+
|
|
545
|
+
assert.equal(Object.keys(result.scheduledTasks.meta).length, 1)
|
|
546
|
+
assert.ok(result.scheduledTasks.meta['daily-report'])
|
|
547
|
+
})
|
|
548
|
+
|
|
549
|
+
test('should filter scheduled tasks by name', () => {
|
|
550
|
+
const state = createMockInspectorState()
|
|
551
|
+
const filters: InspectorFilters = {
|
|
552
|
+
names: ['daily-report'],
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
556
|
+
|
|
557
|
+
assert.equal(Object.keys(result.scheduledTasks.meta).length, 1)
|
|
558
|
+
assert.ok(result.scheduledTasks.meta['daily-report'])
|
|
559
|
+
})
|
|
560
|
+
|
|
561
|
+
test('should filter scheduled tasks by name wildcard', () => {
|
|
562
|
+
const state = createMockInspectorState()
|
|
563
|
+
const filters: InspectorFilters = {
|
|
564
|
+
names: ['*-cleanup'],
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
568
|
+
|
|
569
|
+
assert.equal(Object.keys(result.scheduledTasks.meta).length, 1)
|
|
570
|
+
assert.ok(result.scheduledTasks.meta['hourly-cleanup'])
|
|
571
|
+
})
|
|
572
|
+
|
|
573
|
+
test('should track functions for filtered scheduled tasks', () => {
|
|
574
|
+
const state = createMockInspectorState()
|
|
575
|
+
const filters: InspectorFilters = {
|
|
576
|
+
types: ['scheduler'],
|
|
577
|
+
tags: ['reports'],
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
581
|
+
|
|
582
|
+
assert.ok(result.serviceAggregation.usedFunctions.has('dailyReport'))
|
|
583
|
+
})
|
|
584
|
+
})
|
|
585
|
+
|
|
586
|
+
describe('Queue worker filtering', () => {
|
|
587
|
+
test('should filter queue workers by type', () => {
|
|
588
|
+
const state = createMockInspectorState()
|
|
589
|
+
const filters: InspectorFilters = {
|
|
590
|
+
types: ['queue'],
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
594
|
+
|
|
595
|
+
assert.equal(Object.keys(result.queueWorkers.meta).length, 2)
|
|
596
|
+
|
|
597
|
+
// Other types should be empty
|
|
598
|
+
assert.equal(Object.keys(result.http.meta.get).length, 0)
|
|
599
|
+
assert.equal(Object.keys(result.channels.meta).length, 0)
|
|
600
|
+
})
|
|
601
|
+
|
|
602
|
+
test('should filter queue workers by tags', () => {
|
|
603
|
+
const state = createMockInspectorState()
|
|
604
|
+
const filters: InspectorFilters = {
|
|
605
|
+
types: ['queue'],
|
|
606
|
+
tags: ['email'],
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
610
|
+
|
|
611
|
+
assert.equal(Object.keys(result.queueWorkers.meta).length, 1)
|
|
612
|
+
assert.ok(result.queueWorkers.meta['email-worker'])
|
|
613
|
+
})
|
|
614
|
+
|
|
615
|
+
test('should filter queue workers by name', () => {
|
|
616
|
+
const state = createMockInspectorState()
|
|
617
|
+
const filters: InspectorFilters = {
|
|
618
|
+
names: ['email-worker'],
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
622
|
+
|
|
623
|
+
assert.equal(Object.keys(result.queueWorkers.meta).length, 1)
|
|
624
|
+
assert.ok(result.queueWorkers.meta['email-worker'])
|
|
625
|
+
})
|
|
626
|
+
|
|
627
|
+
test('should filter queue workers by name wildcard', () => {
|
|
628
|
+
const state = createMockInspectorState()
|
|
629
|
+
const filters: InspectorFilters = {
|
|
630
|
+
names: ['*-worker'],
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
634
|
+
|
|
635
|
+
assert.equal(Object.keys(result.queueWorkers.meta).length, 2)
|
|
636
|
+
})
|
|
637
|
+
|
|
638
|
+
test('should track functions for filtered queue workers', () => {
|
|
639
|
+
const state = createMockInspectorState()
|
|
640
|
+
const filters: InspectorFilters = {
|
|
641
|
+
types: ['queue'],
|
|
642
|
+
tags: ['email'],
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
646
|
+
|
|
647
|
+
assert.ok(result.serviceAggregation.usedFunctions.has('sendEmailWorker'))
|
|
648
|
+
})
|
|
649
|
+
})
|
|
650
|
+
|
|
651
|
+
describe('MCP endpoint filtering', () => {
|
|
652
|
+
test('should filter MCP tools by type', () => {
|
|
653
|
+
const state = createMockInspectorState()
|
|
654
|
+
const filters: InspectorFilters = {
|
|
655
|
+
types: ['mcp'],
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
659
|
+
|
|
660
|
+
assert.equal(Object.keys(result.mcpEndpoints.toolsMeta).length, 2)
|
|
661
|
+
assert.equal(Object.keys(result.mcpEndpoints.resourcesMeta).length, 1)
|
|
662
|
+
assert.equal(Object.keys(result.mcpEndpoints.promptsMeta).length, 1)
|
|
663
|
+
|
|
664
|
+
// Other types should be empty
|
|
665
|
+
assert.equal(Object.keys(result.http.meta.get).length, 0)
|
|
666
|
+
})
|
|
667
|
+
|
|
668
|
+
test('should filter MCP endpoints by tags', () => {
|
|
669
|
+
const state = createMockInspectorState()
|
|
670
|
+
const filters: InspectorFilters = {
|
|
671
|
+
types: ['mcp'],
|
|
672
|
+
tags: ['search'],
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
676
|
+
|
|
677
|
+
assert.equal(Object.keys(result.mcpEndpoints.toolsMeta).length, 1)
|
|
678
|
+
assert.ok(result.mcpEndpoints.toolsMeta['search-tool'])
|
|
679
|
+
assert.equal(Object.keys(result.mcpEndpoints.resourcesMeta).length, 0)
|
|
680
|
+
})
|
|
681
|
+
|
|
682
|
+
test('should filter MCP endpoints by name', () => {
|
|
683
|
+
const state = createMockInspectorState()
|
|
684
|
+
const filters: InspectorFilters = {
|
|
685
|
+
names: ['search-tool'],
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
689
|
+
|
|
690
|
+
assert.equal(Object.keys(result.mcpEndpoints.toolsMeta).length, 1)
|
|
691
|
+
assert.ok(result.mcpEndpoints.toolsMeta['search-tool'])
|
|
692
|
+
})
|
|
693
|
+
|
|
694
|
+
test('should filter MCP endpoints by name wildcard', () => {
|
|
695
|
+
const state = createMockInspectorState()
|
|
696
|
+
const filters: InspectorFilters = {
|
|
697
|
+
names: ['*-tool'],
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
701
|
+
|
|
702
|
+
assert.equal(Object.keys(result.mcpEndpoints.toolsMeta).length, 2)
|
|
703
|
+
assert.equal(Object.keys(result.mcpEndpoints.resourcesMeta).length, 0)
|
|
704
|
+
assert.equal(Object.keys(result.mcpEndpoints.promptsMeta).length, 0)
|
|
705
|
+
})
|
|
706
|
+
|
|
707
|
+
test('should track functions for filtered MCP endpoints', () => {
|
|
708
|
+
const state = createMockInspectorState()
|
|
709
|
+
const filters: InspectorFilters = {
|
|
710
|
+
types: ['mcp'],
|
|
711
|
+
tags: ['search'],
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
715
|
+
|
|
716
|
+
assert.ok(result.serviceAggregation.usedFunctions.has('mcpSearchTool'))
|
|
717
|
+
})
|
|
718
|
+
})
|
|
719
|
+
|
|
720
|
+
describe('CLI filtering', () => {
|
|
721
|
+
test('should filter CLI commands by type', () => {
|
|
722
|
+
const state = createMockInspectorState()
|
|
723
|
+
const filters: InspectorFilters = {
|
|
724
|
+
types: ['cli'],
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
728
|
+
|
|
729
|
+
assert.equal(
|
|
730
|
+
Object.keys(result.cli.meta.programs['my-cli'].commands).length,
|
|
731
|
+
2
|
|
732
|
+
)
|
|
733
|
+
|
|
734
|
+
// Other types should be empty
|
|
735
|
+
assert.equal(Object.keys(result.http.meta.get).length, 0)
|
|
736
|
+
})
|
|
737
|
+
|
|
738
|
+
test('should filter CLI commands by tags', () => {
|
|
739
|
+
const state = createMockInspectorState()
|
|
740
|
+
const filters: InspectorFilters = {
|
|
741
|
+
types: ['cli'],
|
|
742
|
+
tags: ['build'],
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
746
|
+
|
|
747
|
+
assert.equal(
|
|
748
|
+
Object.keys(result.cli.meta.programs['my-cli'].commands).length,
|
|
749
|
+
1
|
|
750
|
+
)
|
|
751
|
+
assert.ok(result.cli.meta.programs['my-cli'].commands['build'])
|
|
752
|
+
})
|
|
753
|
+
|
|
754
|
+
test('should filter CLI commands by name', () => {
|
|
755
|
+
const state = createMockInspectorState()
|
|
756
|
+
const filters: InspectorFilters = {
|
|
757
|
+
names: ['build'],
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
761
|
+
|
|
762
|
+
assert.equal(
|
|
763
|
+
Object.keys(result.cli.meta.programs['my-cli'].commands).length,
|
|
764
|
+
1
|
|
765
|
+
)
|
|
766
|
+
assert.ok(result.cli.meta.programs['my-cli'].commands['build'])
|
|
767
|
+
})
|
|
768
|
+
|
|
769
|
+
test('should remove program if all commands are filtered out', () => {
|
|
770
|
+
const state = createMockInspectorState()
|
|
771
|
+
const filters: InspectorFilters = {
|
|
772
|
+
types: ['cli'],
|
|
773
|
+
tags: ['non-existent'],
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
777
|
+
|
|
778
|
+
// Program should be removed
|
|
779
|
+
assert.equal(Object.keys(result.cli.meta.programs).length, 0)
|
|
780
|
+
})
|
|
781
|
+
|
|
782
|
+
test('should track functions for filtered CLI commands', () => {
|
|
783
|
+
const state = createMockInspectorState()
|
|
784
|
+
const filters: InspectorFilters = {
|
|
785
|
+
types: ['cli'],
|
|
786
|
+
tags: ['build'],
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
790
|
+
|
|
791
|
+
assert.ok(result.serviceAggregation.usedFunctions.has('cliCommand'))
|
|
792
|
+
})
|
|
793
|
+
})
|
|
794
|
+
|
|
795
|
+
describe('Combined filtering', () => {
|
|
796
|
+
test('should filter multiple types at once', () => {
|
|
797
|
+
const state = createMockInspectorState()
|
|
798
|
+
const filters: InspectorFilters = {
|
|
799
|
+
types: ['http', 'channel'],
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
803
|
+
|
|
804
|
+
// HTTP and channels should exist
|
|
805
|
+
assert.equal(Object.keys(result.http.meta.get).length, 2)
|
|
806
|
+
assert.equal(Object.keys(result.channels.meta).length, 2)
|
|
807
|
+
|
|
808
|
+
// Other types should be empty
|
|
809
|
+
assert.equal(Object.keys(result.scheduledTasks.meta).length, 0)
|
|
810
|
+
assert.equal(Object.keys(result.queueWorkers.meta).length, 0)
|
|
811
|
+
})
|
|
812
|
+
|
|
813
|
+
test('should filter by tags across all types', () => {
|
|
814
|
+
const state = createMockInspectorState()
|
|
815
|
+
const filters: InspectorFilters = {
|
|
816
|
+
tags: ['admin'],
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
820
|
+
|
|
821
|
+
// Only admin-tagged items should remain
|
|
822
|
+
assert.equal(Object.keys(result.http.meta.get).length, 1)
|
|
823
|
+
assert.ok(result.http.meta.get['/admin/settings'])
|
|
824
|
+
assert.equal(Object.keys(result.channels.meta).length, 1)
|
|
825
|
+
assert.ok(result.channels.meta['admin-channel'])
|
|
826
|
+
assert.equal(Object.keys(result.scheduledTasks.meta).length, 0)
|
|
827
|
+
})
|
|
828
|
+
|
|
829
|
+
test('should handle complex combined filters', () => {
|
|
830
|
+
const state = createMockInspectorState()
|
|
831
|
+
const filters: InspectorFilters = {
|
|
832
|
+
types: ['http'],
|
|
833
|
+
tags: ['api'],
|
|
834
|
+
httpMethods: ['POST'],
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
838
|
+
|
|
839
|
+
// Only POST /api/users should remain
|
|
840
|
+
assert.equal(Object.keys(result.http.meta.get).length, 0)
|
|
841
|
+
assert.equal(Object.keys(result.http.meta.post).length, 1)
|
|
842
|
+
assert.ok(result.http.meta.post['/api/users'])
|
|
843
|
+
})
|
|
844
|
+
})
|
|
845
|
+
|
|
846
|
+
describe('Service aggregation', () => {
|
|
847
|
+
test('should reset and recalculate service aggregation', () => {
|
|
848
|
+
const state = createMockInspectorState()
|
|
849
|
+
|
|
850
|
+
// Pre-populate with some old data
|
|
851
|
+
state.serviceAggregation.usedFunctions.add('oldFunction')
|
|
852
|
+
state.serviceAggregation.usedMiddleware.add('oldMiddleware')
|
|
853
|
+
|
|
854
|
+
const filters: InspectorFilters = {
|
|
855
|
+
types: ['http'],
|
|
856
|
+
tags: ['admin'],
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
860
|
+
|
|
861
|
+
// Old data should be gone, new data should be present
|
|
862
|
+
assert.ok(!result.serviceAggregation.usedFunctions.has('oldFunction'))
|
|
863
|
+
assert.ok(!result.serviceAggregation.usedMiddleware.has('oldMiddleware'))
|
|
864
|
+
assert.ok(result.serviceAggregation.usedFunctions.has('getAdminSettings'))
|
|
865
|
+
assert.ok(result.serviceAggregation.usedMiddleware.has('authMiddleware'))
|
|
866
|
+
})
|
|
867
|
+
|
|
868
|
+
test('should track all used functions across different wiring types', () => {
|
|
869
|
+
const state = createMockInspectorState()
|
|
870
|
+
const filters: InspectorFilters = {
|
|
871
|
+
tags: ['admin'], // Filter for admin-tagged items across all types
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
875
|
+
|
|
876
|
+
// Should include functions from HTTP and channels
|
|
877
|
+
assert.ok(result.serviceAggregation.usedFunctions.has('getAdminSettings'))
|
|
878
|
+
assert.ok(
|
|
879
|
+
result.serviceAggregation.usedFunctions.has('handleAdminMessage')
|
|
880
|
+
)
|
|
881
|
+
})
|
|
882
|
+
})
|
|
883
|
+
|
|
884
|
+
describe('State immutability', () => {
|
|
885
|
+
test('should not mutate original state when filtering', () => {
|
|
886
|
+
const state = createMockInspectorState()
|
|
887
|
+
const originalHttpCount = Object.keys(state.http.meta.get).length
|
|
888
|
+
const originalChannelCount = Object.keys(state.channels.meta).length
|
|
889
|
+
|
|
890
|
+
const filters: InspectorFilters = {
|
|
891
|
+
types: ['http'],
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
filterInspectorState(state, filters, mockLogger)
|
|
895
|
+
|
|
896
|
+
// Original state should not be modified
|
|
897
|
+
assert.equal(Object.keys(state.http.meta.get).length, originalHttpCount)
|
|
898
|
+
assert.equal(
|
|
899
|
+
Object.keys(state.channels.meta).length,
|
|
900
|
+
originalChannelCount
|
|
901
|
+
)
|
|
902
|
+
})
|
|
903
|
+
|
|
904
|
+
test('should create deep copies of metadata', () => {
|
|
905
|
+
const state = createMockInspectorState()
|
|
906
|
+
const filters: InspectorFilters = {
|
|
907
|
+
types: ['http'],
|
|
908
|
+
tags: ['api'],
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
912
|
+
|
|
913
|
+
// Modify filtered state
|
|
914
|
+
delete result.http.meta.get['/api/users']
|
|
915
|
+
|
|
916
|
+
// Original should still have the route
|
|
917
|
+
assert.ok(state.http.meta.get['/api/users'])
|
|
918
|
+
})
|
|
919
|
+
})
|
|
920
|
+
|
|
921
|
+
describe('Edge cases', () => {
|
|
922
|
+
test('should handle empty state', () => {
|
|
923
|
+
const state = createMockInspectorState()
|
|
924
|
+
state.http.meta = {
|
|
925
|
+
get: {},
|
|
926
|
+
post: {},
|
|
927
|
+
put: {},
|
|
928
|
+
patch: {},
|
|
929
|
+
delete: {},
|
|
930
|
+
head: {},
|
|
931
|
+
options: {},
|
|
932
|
+
}
|
|
933
|
+
state.channels.meta = {}
|
|
934
|
+
state.scheduledTasks.meta = {}
|
|
935
|
+
state.queueWorkers.meta = {}
|
|
936
|
+
|
|
937
|
+
const filters: InspectorFilters = {
|
|
938
|
+
types: ['http'],
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
942
|
+
|
|
943
|
+
assert.equal(Object.keys(result.http.meta.get).length, 0)
|
|
944
|
+
})
|
|
945
|
+
|
|
946
|
+
test('should handle filters that match nothing', () => {
|
|
947
|
+
const state = createMockInspectorState()
|
|
948
|
+
const filters: InspectorFilters = {
|
|
949
|
+
tags: ['non-existent-tag'],
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
953
|
+
|
|
954
|
+
// Everything should be filtered out
|
|
955
|
+
assert.equal(Object.keys(result.http.meta.get).length, 0)
|
|
956
|
+
assert.equal(Object.keys(result.channels.meta).length, 0)
|
|
957
|
+
assert.equal(Object.keys(result.scheduledTasks.meta).length, 0)
|
|
958
|
+
assert.equal(Object.keys(result.queueWorkers.meta).length, 0)
|
|
959
|
+
})
|
|
960
|
+
|
|
961
|
+
test('should handle missing optional metadata fields', () => {
|
|
962
|
+
const state = createMockInspectorState()
|
|
963
|
+
// Remove tags from one route
|
|
964
|
+
delete state.http.meta.get['/api/users'].tags
|
|
965
|
+
|
|
966
|
+
const filters: InspectorFilters = {
|
|
967
|
+
tags: ['api'],
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
const result = filterInspectorState(state, filters, mockLogger)
|
|
971
|
+
|
|
972
|
+
// Route without tags should not match
|
|
973
|
+
assert.ok(!result.http.meta.get['/api/users'])
|
|
974
|
+
// Route with tags should match
|
|
975
|
+
assert.ok(result.http.meta.post['/api/users'])
|
|
976
|
+
})
|
|
977
|
+
})
|
|
978
|
+
|
|
979
|
+
describe('Real data tests (from templates/functions)', () => {
|
|
980
|
+
test('should have loaded real state correctly', () => {
|
|
981
|
+
assert.ok(realState)
|
|
982
|
+
assert.ok(realState.http)
|
|
983
|
+
assert.ok(realState.functions)
|
|
984
|
+
assert.ok(realState.channels)
|
|
985
|
+
assert.ok(realState.scheduledTasks)
|
|
986
|
+
assert.ok(realState.queueWorkers)
|
|
987
|
+
assert.ok(realState.mcpEndpoints)
|
|
988
|
+
assert.ok(realState.cli)
|
|
989
|
+
})
|
|
990
|
+
|
|
991
|
+
test('should filter HTTP routes by type in real data', () => {
|
|
992
|
+
// BEFORE: Check what we have in the real state
|
|
993
|
+
const beforeHttpCount = Object.values(
|
|
994
|
+
realState.http.meta as Record<string, any>
|
|
995
|
+
).flatMap((m) => Object.keys(m)).length
|
|
996
|
+
const beforeChannelCount = Object.keys(realState.channels.meta).length
|
|
997
|
+
const beforeTaskCount = Object.keys(realState.scheduledTasks.meta).length
|
|
998
|
+
const beforeQueueCount = Object.keys(realState.queueWorkers.meta).length
|
|
999
|
+
|
|
1000
|
+
assert.ok(beforeHttpCount > 0, 'Real state should have HTTP routes')
|
|
1001
|
+
assert.ok(beforeChannelCount > 0, 'Real state should have channels')
|
|
1002
|
+
assert.ok(beforeTaskCount > 0, 'Real state should have scheduled tasks')
|
|
1003
|
+
assert.ok(beforeQueueCount > 0, 'Real state should have queue workers')
|
|
1004
|
+
|
|
1005
|
+
// FILTER: Apply HTTP type filter
|
|
1006
|
+
const filters: InspectorFilters = {
|
|
1007
|
+
types: ['http'],
|
|
1008
|
+
}
|
|
1009
|
+
const result = filterInspectorState(realState, filters, mockLogger)
|
|
1010
|
+
|
|
1011
|
+
// AFTER: Check filtered result
|
|
1012
|
+
const afterHttpCount = Object.values(
|
|
1013
|
+
result.http.meta as Record<string, any>
|
|
1014
|
+
).flatMap((m) => Object.keys(m)).length
|
|
1015
|
+
const afterChannelCount = Object.keys(result.channels.meta).length
|
|
1016
|
+
const afterTaskCount = Object.keys(result.scheduledTasks.meta).length
|
|
1017
|
+
const afterQueueCount = Object.keys(result.queueWorkers.meta).length
|
|
1018
|
+
|
|
1019
|
+
// HTTP routes should remain
|
|
1020
|
+
assert.equal(
|
|
1021
|
+
afterHttpCount,
|
|
1022
|
+
beforeHttpCount,
|
|
1023
|
+
'HTTP routes should be preserved'
|
|
1024
|
+
)
|
|
1025
|
+
|
|
1026
|
+
// Other types should be filtered out
|
|
1027
|
+
assert.equal(afterChannelCount, 0, 'Channels should be filtered out')
|
|
1028
|
+
assert.equal(afterTaskCount, 0, 'Scheduled tasks should be filtered out')
|
|
1029
|
+
assert.equal(afterQueueCount, 0, 'Queue workers should be filtered out')
|
|
1030
|
+
})
|
|
1031
|
+
|
|
1032
|
+
test('should filter channels by type in real data', () => {
|
|
1033
|
+
const filters: InspectorFilters = {
|
|
1034
|
+
types: ['channel'],
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
const result = filterInspectorState(realState, filters, mockLogger)
|
|
1038
|
+
|
|
1039
|
+
// Should have channels
|
|
1040
|
+
assert.ok(
|
|
1041
|
+
Object.keys(result.channels.meta).length > 0,
|
|
1042
|
+
'Should have channels'
|
|
1043
|
+
)
|
|
1044
|
+
|
|
1045
|
+
// Other types should be filtered out
|
|
1046
|
+
const httpRouteCount = Object.values(result.http.meta).flatMap((m) =>
|
|
1047
|
+
Object.keys(m)
|
|
1048
|
+
).length
|
|
1049
|
+
assert.equal(httpRouteCount, 0)
|
|
1050
|
+
assert.equal(Object.keys(result.scheduledTasks.meta).length, 0)
|
|
1051
|
+
assert.equal(Object.keys(result.queueWorkers.meta).length, 0)
|
|
1052
|
+
})
|
|
1053
|
+
|
|
1054
|
+
test('should filter scheduler tasks by type in real data', () => {
|
|
1055
|
+
// BEFORE: Check what we have in the real state
|
|
1056
|
+
const beforeHttpCount = Object.values(
|
|
1057
|
+
realState.http.meta as Record<string, any>
|
|
1058
|
+
).flatMap((m) => Object.keys(m)).length
|
|
1059
|
+
const beforeChannelCount = Object.keys(realState.channels.meta).length
|
|
1060
|
+
const beforeTaskCount = Object.keys(realState.scheduledTasks.meta).length
|
|
1061
|
+
const beforeQueueCount = Object.keys(realState.queueWorkers.meta).length
|
|
1062
|
+
|
|
1063
|
+
assert.ok(beforeHttpCount > 0, 'Real state should have HTTP routes')
|
|
1064
|
+
assert.ok(beforeChannelCount > 0, 'Real state should have channels')
|
|
1065
|
+
assert.ok(beforeTaskCount > 0, 'Real state should have scheduled tasks')
|
|
1066
|
+
assert.ok(beforeQueueCount > 0, 'Real state should have queue workers')
|
|
1067
|
+
|
|
1068
|
+
// FILTER: Apply scheduler type filter
|
|
1069
|
+
const filters: InspectorFilters = {
|
|
1070
|
+
types: ['scheduler'],
|
|
1071
|
+
}
|
|
1072
|
+
const result = filterInspectorState(realState, filters, mockLogger)
|
|
1073
|
+
|
|
1074
|
+
// AFTER: Check filtered result
|
|
1075
|
+
const afterHttpCount = Object.values(
|
|
1076
|
+
result.http.meta as Record<string, any>
|
|
1077
|
+
).flatMap((m) => Object.keys(m)).length
|
|
1078
|
+
const afterChannelCount = Object.keys(result.channels.meta).length
|
|
1079
|
+
const afterTaskCount = Object.keys(result.scheduledTasks.meta).length
|
|
1080
|
+
const afterQueueCount = Object.keys(result.queueWorkers.meta).length
|
|
1081
|
+
|
|
1082
|
+
// Scheduled tasks should remain
|
|
1083
|
+
assert.equal(
|
|
1084
|
+
afterTaskCount,
|
|
1085
|
+
beforeTaskCount,
|
|
1086
|
+
'Scheduled tasks should be preserved'
|
|
1087
|
+
)
|
|
1088
|
+
|
|
1089
|
+
// Other types should be filtered out
|
|
1090
|
+
assert.equal(afterHttpCount, 0, 'HTTP routes should be filtered out')
|
|
1091
|
+
assert.equal(afterChannelCount, 0, 'Channels should be filtered out')
|
|
1092
|
+
assert.equal(afterQueueCount, 0, 'Queue workers should be filtered out')
|
|
1093
|
+
})
|
|
1094
|
+
|
|
1095
|
+
test('should filter queue workers by type in real data', () => {
|
|
1096
|
+
// BEFORE: Check what we have in the real state
|
|
1097
|
+
const beforeHttpCount = Object.values(
|
|
1098
|
+
realState.http.meta as Record<string, any>
|
|
1099
|
+
).flatMap((m) => Object.keys(m)).length
|
|
1100
|
+
const beforeChannelCount = Object.keys(realState.channels.meta).length
|
|
1101
|
+
const beforeTaskCount = Object.keys(realState.scheduledTasks.meta).length
|
|
1102
|
+
const beforeQueueCount = Object.keys(realState.queueWorkers.meta).length
|
|
1103
|
+
|
|
1104
|
+
assert.ok(beforeHttpCount > 0, 'Real state should have HTTP routes')
|
|
1105
|
+
assert.ok(beforeChannelCount > 0, 'Real state should have channels')
|
|
1106
|
+
assert.ok(beforeTaskCount > 0, 'Real state should have scheduled tasks')
|
|
1107
|
+
assert.ok(beforeQueueCount > 0, 'Real state should have queue workers')
|
|
1108
|
+
|
|
1109
|
+
// FILTER: Apply queue type filter
|
|
1110
|
+
const filters: InspectorFilters = {
|
|
1111
|
+
types: ['queue'],
|
|
1112
|
+
}
|
|
1113
|
+
const result = filterInspectorState(realState, filters, mockLogger)
|
|
1114
|
+
|
|
1115
|
+
// AFTER: Check filtered result
|
|
1116
|
+
const afterHttpCount = Object.values(
|
|
1117
|
+
result.http.meta as Record<string, any>
|
|
1118
|
+
).flatMap((m) => Object.keys(m)).length
|
|
1119
|
+
const afterChannelCount = Object.keys(result.channels.meta).length
|
|
1120
|
+
const afterTaskCount = Object.keys(result.scheduledTasks.meta).length
|
|
1121
|
+
const afterQueueCount = Object.keys(result.queueWorkers.meta).length
|
|
1122
|
+
|
|
1123
|
+
// Queue workers should remain
|
|
1124
|
+
assert.equal(
|
|
1125
|
+
afterQueueCount,
|
|
1126
|
+
beforeQueueCount,
|
|
1127
|
+
'Queue workers should be preserved'
|
|
1128
|
+
)
|
|
1129
|
+
|
|
1130
|
+
// Other types should be filtered out
|
|
1131
|
+
assert.equal(afterHttpCount, 0, 'HTTP routes should be filtered out')
|
|
1132
|
+
assert.equal(afterChannelCount, 0, 'Channels should be filtered out')
|
|
1133
|
+
assert.equal(afterTaskCount, 0, 'Scheduled tasks should be filtered out')
|
|
1134
|
+
})
|
|
1135
|
+
|
|
1136
|
+
test('should filter MCP endpoints by type in real data', () => {
|
|
1137
|
+
// BEFORE: Check what we have in the real state
|
|
1138
|
+
const beforeHttpCount = Object.values(
|
|
1139
|
+
realState.http.meta as Record<string, any>
|
|
1140
|
+
).flatMap((m) => Object.keys(m)).length
|
|
1141
|
+
const beforeChannelCount = Object.keys(realState.channels.meta).length
|
|
1142
|
+
const beforeTaskCount = Object.keys(realState.scheduledTasks.meta).length
|
|
1143
|
+
const beforeQueueCount = Object.keys(realState.queueWorkers.meta).length
|
|
1144
|
+
const beforeMcpToolsCount = Object.keys(
|
|
1145
|
+
realState.mcpEndpoints.toolsMeta
|
|
1146
|
+
).length
|
|
1147
|
+
const beforeMcpResourcesCount = Object.keys(
|
|
1148
|
+
realState.mcpEndpoints.resourcesMeta
|
|
1149
|
+
).length
|
|
1150
|
+
const beforeMcpPromptsCount = Object.keys(
|
|
1151
|
+
realState.mcpEndpoints.promptsMeta
|
|
1152
|
+
).length
|
|
1153
|
+
|
|
1154
|
+
assert.ok(beforeHttpCount > 0, 'Real state should have HTTP routes')
|
|
1155
|
+
assert.ok(beforeChannelCount > 0, 'Real state should have channels')
|
|
1156
|
+
assert.ok(beforeTaskCount > 0, 'Real state should have scheduled tasks')
|
|
1157
|
+
assert.ok(beforeQueueCount > 0, 'Real state should have queue workers')
|
|
1158
|
+
assert.ok(
|
|
1159
|
+
beforeMcpToolsCount + beforeMcpResourcesCount + beforeMcpPromptsCount >
|
|
1160
|
+
0,
|
|
1161
|
+
'Real state should have MCP endpoints'
|
|
1162
|
+
)
|
|
1163
|
+
|
|
1164
|
+
// FILTER: Apply MCP type filter
|
|
1165
|
+
const filters: InspectorFilters = {
|
|
1166
|
+
types: ['mcp'],
|
|
1167
|
+
}
|
|
1168
|
+
const result = filterInspectorState(realState, filters, mockLogger)
|
|
1169
|
+
|
|
1170
|
+
// AFTER: Check filtered result
|
|
1171
|
+
const afterHttpCount = Object.values(
|
|
1172
|
+
result.http.meta as Record<string, any>
|
|
1173
|
+
).flatMap((m) => Object.keys(m)).length
|
|
1174
|
+
const afterChannelCount = Object.keys(result.channels.meta).length
|
|
1175
|
+
const afterTaskCount = Object.keys(result.scheduledTasks.meta).length
|
|
1176
|
+
const afterQueueCount = Object.keys(result.queueWorkers.meta).length
|
|
1177
|
+
const afterMcpToolsCount = Object.keys(
|
|
1178
|
+
result.mcpEndpoints.toolsMeta
|
|
1179
|
+
).length
|
|
1180
|
+
const afterMcpResourcesCount = Object.keys(
|
|
1181
|
+
result.mcpEndpoints.resourcesMeta
|
|
1182
|
+
).length
|
|
1183
|
+
const afterMcpPromptsCount = Object.keys(
|
|
1184
|
+
result.mcpEndpoints.promptsMeta
|
|
1185
|
+
).length
|
|
1186
|
+
|
|
1187
|
+
// MCP endpoints should remain
|
|
1188
|
+
assert.equal(
|
|
1189
|
+
afterMcpToolsCount,
|
|
1190
|
+
beforeMcpToolsCount,
|
|
1191
|
+
'MCP tools should be preserved'
|
|
1192
|
+
)
|
|
1193
|
+
assert.equal(
|
|
1194
|
+
afterMcpResourcesCount,
|
|
1195
|
+
beforeMcpResourcesCount,
|
|
1196
|
+
'MCP resources should be preserved'
|
|
1197
|
+
)
|
|
1198
|
+
assert.equal(
|
|
1199
|
+
afterMcpPromptsCount,
|
|
1200
|
+
beforeMcpPromptsCount,
|
|
1201
|
+
'MCP prompts should be preserved'
|
|
1202
|
+
)
|
|
1203
|
+
|
|
1204
|
+
// Other types should be filtered out
|
|
1205
|
+
assert.equal(afterHttpCount, 0, 'HTTP routes should be filtered out')
|
|
1206
|
+
assert.equal(afterChannelCount, 0, 'Channels should be filtered out')
|
|
1207
|
+
assert.equal(afterTaskCount, 0, 'Scheduled tasks should be filtered out')
|
|
1208
|
+
assert.equal(afterQueueCount, 0, 'Queue workers should be filtered out')
|
|
1209
|
+
})
|
|
1210
|
+
|
|
1211
|
+
test('should filter CLI programs by type in real data', () => {
|
|
1212
|
+
// BEFORE: Check what we have in the real state
|
|
1213
|
+
const beforeHttpCount = Object.values(
|
|
1214
|
+
realState.http.meta as Record<string, any>
|
|
1215
|
+
).flatMap((m) => Object.keys(m)).length
|
|
1216
|
+
const beforeChannelCount = Object.keys(realState.channels.meta).length
|
|
1217
|
+
const beforeTaskCount = Object.keys(realState.scheduledTasks.meta).length
|
|
1218
|
+
const beforeQueueCount = Object.keys(realState.queueWorkers.meta).length
|
|
1219
|
+
const beforeCliProgramCount = Object.keys(
|
|
1220
|
+
realState.cli.meta.programs
|
|
1221
|
+
).length
|
|
1222
|
+
|
|
1223
|
+
assert.ok(beforeHttpCount > 0, 'Real state should have HTTP routes')
|
|
1224
|
+
assert.ok(beforeChannelCount > 0, 'Real state should have channels')
|
|
1225
|
+
assert.ok(beforeTaskCount > 0, 'Real state should have scheduled tasks')
|
|
1226
|
+
assert.ok(beforeQueueCount > 0, 'Real state should have queue workers')
|
|
1227
|
+
assert.ok(
|
|
1228
|
+
beforeCliProgramCount > 0,
|
|
1229
|
+
'Real state should have CLI programs'
|
|
1230
|
+
)
|
|
1231
|
+
|
|
1232
|
+
// FILTER: Apply CLI type filter
|
|
1233
|
+
const filters: InspectorFilters = {
|
|
1234
|
+
types: ['cli'],
|
|
1235
|
+
}
|
|
1236
|
+
const result = filterInspectorState(realState, filters, mockLogger)
|
|
1237
|
+
|
|
1238
|
+
// AFTER: Check filtered result
|
|
1239
|
+
const afterHttpCount = Object.values(
|
|
1240
|
+
result.http.meta as Record<string, any>
|
|
1241
|
+
).flatMap((m) => Object.keys(m)).length
|
|
1242
|
+
const afterChannelCount = Object.keys(result.channels.meta).length
|
|
1243
|
+
const afterTaskCount = Object.keys(result.scheduledTasks.meta).length
|
|
1244
|
+
const afterQueueCount = Object.keys(result.queueWorkers.meta).length
|
|
1245
|
+
const afterCliProgramCount = Object.keys(result.cli.meta.programs).length
|
|
1246
|
+
|
|
1247
|
+
// CLI programs should remain
|
|
1248
|
+
assert.equal(
|
|
1249
|
+
afterCliProgramCount,
|
|
1250
|
+
beforeCliProgramCount,
|
|
1251
|
+
'CLI programs should be preserved'
|
|
1252
|
+
)
|
|
1253
|
+
|
|
1254
|
+
// Other types should be filtered out
|
|
1255
|
+
assert.equal(afterHttpCount, 0, 'HTTP routes should be filtered out')
|
|
1256
|
+
assert.equal(afterChannelCount, 0, 'Channels should be filtered out')
|
|
1257
|
+
assert.equal(afterTaskCount, 0, 'Scheduled tasks should be filtered out')
|
|
1258
|
+
assert.equal(afterQueueCount, 0, 'Queue workers should be filtered out')
|
|
1259
|
+
})
|
|
1260
|
+
|
|
1261
|
+
test('should filter by HTTP method in real data', () => {
|
|
1262
|
+
// BEFORE: Check what HTTP methods exist
|
|
1263
|
+
const beforeGetCount = Object.keys(realState.http.meta.get || {}).length
|
|
1264
|
+
const beforePostCount = Object.keys(realState.http.meta.post || {}).length
|
|
1265
|
+
const beforePutCount = Object.keys(realState.http.meta.put || {}).length
|
|
1266
|
+
const beforeDeleteCount = Object.keys(
|
|
1267
|
+
realState.http.meta.delete || {}
|
|
1268
|
+
).length
|
|
1269
|
+
|
|
1270
|
+
assert.ok(
|
|
1271
|
+
beforeGetCount + beforePostCount + beforePutCount + beforeDeleteCount >
|
|
1272
|
+
0,
|
|
1273
|
+
'Real state should have HTTP routes'
|
|
1274
|
+
)
|
|
1275
|
+
|
|
1276
|
+
// FILTER: Apply GET method filter
|
|
1277
|
+
const filters: InspectorFilters = {
|
|
1278
|
+
types: ['http'],
|
|
1279
|
+
httpMethods: ['GET'],
|
|
1280
|
+
}
|
|
1281
|
+
const result = filterInspectorState(realState, filters, mockLogger)
|
|
1282
|
+
|
|
1283
|
+
// AFTER: Check filtered result
|
|
1284
|
+
const afterGetCount = Object.keys(result.http.meta.get || {}).length
|
|
1285
|
+
const afterPostCount = Object.keys(result.http.meta.post || {}).length
|
|
1286
|
+
const afterPutCount = Object.keys(result.http.meta.put || {}).length
|
|
1287
|
+
const afterDeleteCount = Object.keys(result.http.meta.delete || {}).length
|
|
1288
|
+
|
|
1289
|
+
// GET routes should remain
|
|
1290
|
+
assert.equal(
|
|
1291
|
+
afterGetCount,
|
|
1292
|
+
beforeGetCount,
|
|
1293
|
+
'GET routes should be preserved'
|
|
1294
|
+
)
|
|
1295
|
+
|
|
1296
|
+
// Other methods should be filtered out
|
|
1297
|
+
assert.equal(afterPostCount, 0, 'POST routes should be filtered out')
|
|
1298
|
+
assert.equal(afterPutCount, 0, 'PUT routes should be filtered out')
|
|
1299
|
+
assert.equal(afterDeleteCount, 0, 'DELETE routes should be filtered out')
|
|
1300
|
+
})
|
|
1301
|
+
|
|
1302
|
+
test('should filter by name pattern in real data', () => {
|
|
1303
|
+
// BEFORE: Count all endpoints
|
|
1304
|
+
const beforeHttpCount = Object.values(
|
|
1305
|
+
realState.http.meta as Record<string, any>
|
|
1306
|
+
).flatMap((m) => Object.keys(m)).length
|
|
1307
|
+
const beforeChannelCount = Object.keys(realState.channels.meta).length
|
|
1308
|
+
const beforeTaskCount = Object.keys(realState.scheduledTasks.meta).length
|
|
1309
|
+
const beforeQueueCount = Object.keys(realState.queueWorkers.meta).length
|
|
1310
|
+
const beforeTotal =
|
|
1311
|
+
beforeHttpCount +
|
|
1312
|
+
beforeChannelCount +
|
|
1313
|
+
beforeTaskCount +
|
|
1314
|
+
beforeQueueCount
|
|
1315
|
+
|
|
1316
|
+
assert.ok(beforeTotal > 0, 'Real state should have endpoints')
|
|
1317
|
+
|
|
1318
|
+
// FILTER: Apply name pattern filter for functions with "http" in their name
|
|
1319
|
+
const filters: InspectorFilters = {
|
|
1320
|
+
names: ['*http*'],
|
|
1321
|
+
}
|
|
1322
|
+
const result = filterInspectorState(realState, filters, mockLogger)
|
|
1323
|
+
|
|
1324
|
+
// AFTER: Count all filtered endpoints
|
|
1325
|
+
const afterHttpCount = Object.values(
|
|
1326
|
+
result.http.meta as Record<string, any>
|
|
1327
|
+
).flatMap((m) => Object.keys(m)).length
|
|
1328
|
+
const afterChannelCount = Object.keys(result.channels.meta).length
|
|
1329
|
+
const afterTaskCount = Object.keys(result.scheduledTasks.meta).length
|
|
1330
|
+
const afterQueueCount = Object.keys(result.queueWorkers.meta).length
|
|
1331
|
+
const afterTotal =
|
|
1332
|
+
afterHttpCount + afterChannelCount + afterTaskCount + afterQueueCount
|
|
1333
|
+
|
|
1334
|
+
// After filtering by name pattern, we should have fewer or equal items
|
|
1335
|
+
assert.ok(
|
|
1336
|
+
afterTotal <= beforeTotal,
|
|
1337
|
+
'Filtered count should be less than or equal to original'
|
|
1338
|
+
)
|
|
1339
|
+
})
|
|
1340
|
+
|
|
1341
|
+
test('should not mutate real state when filtering', () => {
|
|
1342
|
+
const originalHttpCount = Object.values(
|
|
1343
|
+
realState.http.meta as Record<string, any>
|
|
1344
|
+
).flatMap((m) => Object.keys(m)).length
|
|
1345
|
+
const originalChannelCount = Object.keys(realState.channels.meta).length
|
|
1346
|
+
|
|
1347
|
+
const filters: InspectorFilters = {
|
|
1348
|
+
types: ['http'],
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
filterInspectorState(realState, filters, mockLogger)
|
|
1352
|
+
|
|
1353
|
+
// Original should not be modified
|
|
1354
|
+
const afterHttpCount = Object.values(
|
|
1355
|
+
realState.http.meta as Record<string, any>
|
|
1356
|
+
).flatMap((m) => Object.keys(m)).length
|
|
1357
|
+
const afterChannelCount = Object.keys(realState.channels.meta).length
|
|
1358
|
+
|
|
1359
|
+
assert.equal(afterHttpCount, originalHttpCount)
|
|
1360
|
+
assert.equal(afterChannelCount, originalChannelCount)
|
|
1361
|
+
})
|
|
1362
|
+
|
|
1363
|
+
test('should aggregate services correctly with real data', () => {
|
|
1364
|
+
const filters: InspectorFilters = {
|
|
1365
|
+
types: ['http'],
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
const result = filterInspectorState(realState, filters, mockLogger)
|
|
1369
|
+
|
|
1370
|
+
// Service aggregation should be recalculated
|
|
1371
|
+
assert.ok(result.serviceAggregation)
|
|
1372
|
+
assert.ok(result.serviceAggregation.usedFunctions instanceof Set)
|
|
1373
|
+
assert.ok(result.serviceAggregation.usedMiddleware instanceof Set)
|
|
1374
|
+
assert.ok(result.serviceAggregation.usedPermissions instanceof Set)
|
|
1375
|
+
assert.ok(result.serviceAggregation.requiredServices instanceof Set)
|
|
1376
|
+
})
|
|
1377
|
+
|
|
1378
|
+
test('should handle combined filters with real data', () => {
|
|
1379
|
+
// BEFORE: Check what we have
|
|
1380
|
+
const beforeGetCount = Object.keys(realState.http.meta.get || {}).length
|
|
1381
|
+
const beforePostCount = Object.keys(realState.http.meta.post || {}).length
|
|
1382
|
+
const beforePutCount = Object.keys(realState.http.meta.put || {}).length
|
|
1383
|
+
const beforeChannelCount = Object.keys(realState.channels.meta).length
|
|
1384
|
+
const beforeTaskCount = Object.keys(realState.scheduledTasks.meta).length
|
|
1385
|
+
const beforeQueueCount = Object.keys(realState.queueWorkers.meta).length
|
|
1386
|
+
|
|
1387
|
+
assert.ok(
|
|
1388
|
+
beforeGetCount + beforePostCount > 0,
|
|
1389
|
+
'Real state should have GET/POST routes'
|
|
1390
|
+
)
|
|
1391
|
+
assert.ok(beforeChannelCount > 0, 'Real state should have channels')
|
|
1392
|
+
|
|
1393
|
+
// FILTER: Apply combined filters (HTTP and channels, GET/POST methods only)
|
|
1394
|
+
const filters: InspectorFilters = {
|
|
1395
|
+
types: ['http', 'channel'],
|
|
1396
|
+
httpMethods: ['GET', 'POST'],
|
|
1397
|
+
}
|
|
1398
|
+
const result = filterInspectorState(realState, filters, mockLogger)
|
|
1399
|
+
|
|
1400
|
+
// AFTER: Check filtered result
|
|
1401
|
+
const afterGetCount = Object.keys(result.http.meta.get || {}).length
|
|
1402
|
+
const afterPostCount = Object.keys(result.http.meta.post || {}).length
|
|
1403
|
+
const afterPutCount = Object.keys(result.http.meta.put || {}).length
|
|
1404
|
+
const afterChannelCount = Object.keys(result.channels.meta).length
|
|
1405
|
+
const afterTaskCount = Object.keys(result.scheduledTasks.meta).length
|
|
1406
|
+
const afterQueueCount = Object.keys(result.queueWorkers.meta).length
|
|
1407
|
+
|
|
1408
|
+
// GET and POST routes should be preserved
|
|
1409
|
+
assert.equal(
|
|
1410
|
+
afterGetCount,
|
|
1411
|
+
beforeGetCount,
|
|
1412
|
+
'GET routes should be preserved'
|
|
1413
|
+
)
|
|
1414
|
+
assert.equal(
|
|
1415
|
+
afterPostCount,
|
|
1416
|
+
beforePostCount,
|
|
1417
|
+
'POST routes should be preserved'
|
|
1418
|
+
)
|
|
1419
|
+
|
|
1420
|
+
// Channels should be preserved (no HTTP method filter applies)
|
|
1421
|
+
assert.equal(
|
|
1422
|
+
afterChannelCount,
|
|
1423
|
+
beforeChannelCount,
|
|
1424
|
+
'Channels should be preserved'
|
|
1425
|
+
)
|
|
1426
|
+
|
|
1427
|
+
// Other methods/types should be filtered out
|
|
1428
|
+
assert.equal(afterPutCount, 0, 'PUT routes should be filtered out')
|
|
1429
|
+
assert.equal(afterTaskCount, 0, 'Scheduled tasks should be filtered out')
|
|
1430
|
+
assert.equal(afterQueueCount, 0, 'Queue workers should be filtered out')
|
|
1431
|
+
})
|
|
1432
|
+
})
|
|
1433
|
+
})
|