@ocpp-debugkit/toolkit 0.2.1 → 0.3.1

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.
Files changed (67) hide show
  1. package/README.md +234 -12
  2. package/dist/cli/commands/anonymize.d.ts +15 -0
  3. package/dist/cli/commands/anonymize.d.ts.map +1 -0
  4. package/dist/cli/commands/anonymize.js +104 -0
  5. package/dist/cli/commands/anonymize.js.map +1 -0
  6. package/dist/cli/commands/ci.d.ts +10 -0
  7. package/dist/cli/commands/ci.d.ts.map +1 -0
  8. package/dist/cli/commands/ci.js +96 -0
  9. package/dist/cli/commands/ci.js.map +1 -0
  10. package/dist/cli/commands/diff.d.ts +10 -0
  11. package/dist/cli/commands/diff.d.ts.map +1 -0
  12. package/dist/cli/commands/diff.js +71 -0
  13. package/dist/cli/commands/diff.js.map +1 -0
  14. package/dist/cli/index.js +27 -0
  15. package/dist/cli/index.js.map +1 -1
  16. package/dist/core/assertions.d.ts +36 -0
  17. package/dist/core/assertions.d.ts.map +1 -0
  18. package/dist/core/assertions.js +335 -0
  19. package/dist/core/assertions.js.map +1 -0
  20. package/dist/core/detection.d.ts +9 -1
  21. package/dist/core/detection.d.ts.map +1 -1
  22. package/dist/core/detection.js +344 -1
  23. package/dist/core/detection.js.map +1 -1
  24. package/dist/core/diff.d.ts +68 -0
  25. package/dist/core/diff.d.ts.map +1 -0
  26. package/dist/core/diff.js +199 -0
  27. package/dist/core/diff.js.map +1 -0
  28. package/dist/core/index.d.ts +4 -0
  29. package/dist/core/index.d.ts.map +1 -1
  30. package/dist/core/index.js +4 -0
  31. package/dist/core/index.js.map +1 -1
  32. package/dist/core/types.d.ts +77 -2
  33. package/dist/core/types.d.ts.map +1 -1
  34. package/dist/index.d.ts +3 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +2 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/scenarios/__scenarios__/heartbeat-irregular.d.ts +51 -0
  39. package/dist/scenarios/__scenarios__/heartbeat-irregular.d.ts.map +1 -0
  40. package/dist/scenarios/__scenarios__/heartbeat-irregular.js +81 -0
  41. package/dist/scenarios/__scenarios__/heartbeat-irregular.js.map +1 -0
  42. package/dist/scenarios/__scenarios__/meter-anomaly.d.ts +115 -0
  43. package/dist/scenarios/__scenarios__/meter-anomaly.d.ts.map +1 -0
  44. package/dist/scenarios/__scenarios__/meter-anomaly.js +152 -0
  45. package/dist/scenarios/__scenarios__/meter-anomaly.js.map +1 -0
  46. package/dist/scenarios/__scenarios__/short-session.d.ts +111 -0
  47. package/dist/scenarios/__scenarios__/short-session.d.ts.map +1 -0
  48. package/dist/scenarios/__scenarios__/short-session.js +129 -0
  49. package/dist/scenarios/__scenarios__/short-session.js.map +1 -0
  50. package/dist/scenarios/__scenarios__/slow-csms-response.d.ts +52 -0
  51. package/dist/scenarios/__scenarios__/slow-csms-response.d.ts.map +1 -0
  52. package/dist/scenarios/__scenarios__/slow-csms-response.js +61 -0
  53. package/dist/scenarios/__scenarios__/slow-csms-response.js.map +1 -0
  54. package/dist/scenarios/__scenarios__/unexpected-start.js +3 -3
  55. package/dist/scenarios/__scenarios__/unresponsive-csms.d.ts +53 -0
  56. package/dist/scenarios/__scenarios__/unresponsive-csms.d.ts.map +1 -0
  57. package/dist/scenarios/__scenarios__/unresponsive-csms.js +53 -0
  58. package/dist/scenarios/__scenarios__/unresponsive-csms.js.map +1 -0
  59. package/dist/scenarios/compare.d.ts +39 -0
  60. package/dist/scenarios/compare.d.ts.map +1 -0
  61. package/dist/scenarios/compare.js +77 -0
  62. package/dist/scenarios/compare.js.map +1 -0
  63. package/dist/scenarios/index.d.ts +10 -3
  64. package/dist/scenarios/index.d.ts.map +1 -1
  65. package/dist/scenarios/index.js +22 -1
  66. package/dist/scenarios/index.js.map +1 -1
  67. package/package.json +4 -4
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Scenario assertions — declarative assertions for scenario evaluation.
3
+ *
4
+ * Supports 8 assertion types:
5
+ * - event_order: verify events appear in a specific order
6
+ * - event_count: verify the count of events (optionally filtered by action)
7
+ * - payload_field: verify a payload field value on a specific action
8
+ * - timing: verify timing gaps between two actions
9
+ * - session_state: verify session status
10
+ * - failure_severity: verify a specific failure has the expected severity
11
+ * - no_failures: verify no failures are detected
12
+ * - failure_count: verify the count of detected failures
13
+ *
14
+ * @module @ocpp-debugkit/toolkit/core
15
+ */
16
+ import type { AssertionResult, Event, Failure, Scenario, ScenarioAssertion, ScenarioEvalResult, Session } from './types.js';
17
+ /** Input for assertion evaluation. */
18
+ export interface AssertionContext {
19
+ events: Event[];
20
+ sessions: Session[];
21
+ failures: Failure[];
22
+ }
23
+ /**
24
+ * Evaluate a single assertion against the analysis context.
25
+ */
26
+ export declare function runAssertion(assertion: ScenarioAssertion, ctx: AssertionContext): AssertionResult;
27
+ /**
28
+ * Evaluate multiple assertions against the analysis context.
29
+ */
30
+ export declare function runAssertions(ctx: AssertionContext, assertions: ScenarioAssertion[]): AssertionResult[];
31
+ /**
32
+ * Evaluate a scenario: parse the trace, run detection, evaluate assertions,
33
+ * and compare detected vs expected failures.
34
+ */
35
+ export declare function evaluateScenario(scenario: Scenario): ScenarioEvalResult;
36
+ //# sourceMappingURL=assertions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertions.d.ts","sourceRoot":"","sources":["../../src/core/assertions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,KAAK,EACL,OAAO,EAGP,QAAQ,EACR,iBAAiB,EACjB,kBAAkB,EAClB,OAAO,EACR,MAAM,YAAY,CAAC;AA+CpB,sCAAsC;AACtC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,iBAAiB,EAAE,GAAG,EAAE,gBAAgB,GAAG,eAAe,CAyBjG;AA+RD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,gBAAgB,EACrB,UAAU,EAAE,iBAAiB,EAAE,GAC9B,eAAe,EAAE,CAEnB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,GAAG,kBAAkB,CA4BvE"}
@@ -0,0 +1,335 @@
1
+ /**
2
+ * Scenario assertions — declarative assertions for scenario evaluation.
3
+ *
4
+ * Supports 8 assertion types:
5
+ * - event_order: verify events appear in a specific order
6
+ * - event_count: verify the count of events (optionally filtered by action)
7
+ * - payload_field: verify a payload field value on a specific action
8
+ * - timing: verify timing gaps between two actions
9
+ * - session_state: verify session status
10
+ * - failure_severity: verify a specific failure has the expected severity
11
+ * - no_failures: verify no failures are detected
12
+ * - failure_count: verify the count of detected failures
13
+ *
14
+ * @module @ocpp-debugkit/toolkit/core
15
+ */
16
+ import { parseTrace } from './parser.js';
17
+ import { buildSessionTimeline } from './timeline.js';
18
+ import { detectFailures } from './detection.js';
19
+ import { summarizeSessions } from './summarizer.js';
20
+ // ---------------------------------------------------------------------------
21
+ // Deep equality (same limited implementation as diff.ts)
22
+ // ---------------------------------------------------------------------------
23
+ function deepEqual(a, b) {
24
+ if (a === b)
25
+ return true;
26
+ if (a === null || b === null)
27
+ return false;
28
+ if (typeof a !== typeof b)
29
+ return false;
30
+ if (Array.isArray(a) && Array.isArray(b)) {
31
+ if (a.length !== b.length)
32
+ return false;
33
+ return a.every((item, i) => deepEqual(item, b[i]));
34
+ }
35
+ if (typeof a === 'object' && typeof b === 'object') {
36
+ const objA = a;
37
+ const objB = b;
38
+ const keysA = Object.keys(objA);
39
+ const keysB = Object.keys(objB);
40
+ if (keysA.length !== keysB.length)
41
+ return false;
42
+ return keysA.every((key) => deepEqual(objA[key], objB[key]));
43
+ }
44
+ return false;
45
+ }
46
+ /** Safely access a nested field via dot notation (e.g., "idTagInfo.status"). */
47
+ function getNestedValue(obj, path) {
48
+ const parts = path.split('.');
49
+ let current = obj;
50
+ for (const part of parts) {
51
+ if (current === null || typeof current !== 'object')
52
+ return undefined;
53
+ current = current[part];
54
+ }
55
+ return current;
56
+ }
57
+ /**
58
+ * Evaluate a single assertion against the analysis context.
59
+ */
60
+ export function runAssertion(assertion, ctx) {
61
+ switch (assertion.type) {
62
+ case 'event_order':
63
+ return evalEventOrder(assertion, ctx);
64
+ case 'event_count':
65
+ return evalEventCount(assertion, ctx);
66
+ case 'payload_field':
67
+ return evalPayloadField(assertion, ctx);
68
+ case 'timing':
69
+ return evalTiming(assertion, ctx);
70
+ case 'session_state':
71
+ return evalSessionState(assertion, ctx);
72
+ case 'failure_severity':
73
+ return evalFailureSeverity(assertion, ctx);
74
+ case 'no_failures':
75
+ return evalNoFailures(assertion, ctx);
76
+ case 'failure_count':
77
+ return evalFailureCount(assertion, ctx);
78
+ default:
79
+ return {
80
+ assertion,
81
+ passed: false,
82
+ message: `Unknown assertion type: ${assertion.type}`,
83
+ };
84
+ }
85
+ }
86
+ function evalEventOrder(assertion, ctx) {
87
+ const { actions } = assertion.params;
88
+ const callActions = ctx.events
89
+ .filter((e) => e.messageType === 'Call' && e.action !== null)
90
+ .map((e) => e.action);
91
+ // Check if actions appear in order (not necessarily consecutive)
92
+ let searchFrom = 0;
93
+ for (const action of actions) {
94
+ const foundIndex = callActions.indexOf(action, searchFrom);
95
+ if (foundIndex === -1) {
96
+ return {
97
+ assertion,
98
+ passed: false,
99
+ message: `Expected action "${action}" in order after previous actions, but not found`,
100
+ };
101
+ }
102
+ searchFrom = foundIndex + 1;
103
+ }
104
+ return {
105
+ assertion,
106
+ passed: true,
107
+ message: `Actions [${actions.join(', ')}] appear in the correct order`,
108
+ };
109
+ }
110
+ function evalEventCount(assertion, ctx) {
111
+ const { min, max, action } = assertion.params;
112
+ const count = action
113
+ ? ctx.events.filter((e) => e.messageType === 'Call' && e.action === action).length
114
+ : ctx.events.length;
115
+ if (min !== undefined && count < min) {
116
+ return {
117
+ assertion,
118
+ passed: false,
119
+ message: `Expected at least ${min} ${action ? `"${action}" ` : ''}events, got ${count}`,
120
+ };
121
+ }
122
+ if (max !== undefined && count > max) {
123
+ return {
124
+ assertion,
125
+ passed: false,
126
+ message: `Expected at most ${max} ${action ? `"${action}" ` : ''}events, got ${count}`,
127
+ };
128
+ }
129
+ return {
130
+ assertion,
131
+ passed: true,
132
+ message: `Event count ${count} is within range [${min ?? 0}, ${max ?? '∞'}]${action ? ` for "${action}"` : ''}`,
133
+ };
134
+ }
135
+ function evalPayloadField(assertion, ctx) {
136
+ const { action, field, equals, contains } = assertion.params;
137
+ const matchingEvents = ctx.events.filter((e) => e.messageType === 'Call' && e.action === action);
138
+ if (matchingEvents.length === 0) {
139
+ return {
140
+ assertion,
141
+ passed: false,
142
+ message: `No events with action "${action}" found`,
143
+ };
144
+ }
145
+ for (const event of matchingEvents) {
146
+ const value = getNestedValue(event.payload, field);
147
+ if (value === undefined) {
148
+ return {
149
+ assertion,
150
+ passed: false,
151
+ message: `Field "${field}" not found in payload of "${action}" event`,
152
+ };
153
+ }
154
+ if (equals !== undefined && !deepEqual(value, equals)) {
155
+ return {
156
+ assertion,
157
+ passed: false,
158
+ message: `Field "${field}" in "${action}" expected to equal ${JSON.stringify(equals)}, got ${JSON.stringify(value)}`,
159
+ };
160
+ }
161
+ if (contains !== undefined) {
162
+ if (Array.isArray(value) && !value.some((v) => deepEqual(v, contains))) {
163
+ return {
164
+ assertion,
165
+ passed: false,
166
+ message: `Field "${field}" in "${action}" expected to contain ${JSON.stringify(contains)}, got ${JSON.stringify(value)}`,
167
+ };
168
+ }
169
+ if (typeof value === 'string' && !value.includes(String(contains))) {
170
+ return {
171
+ assertion,
172
+ passed: false,
173
+ message: `Field "${field}" in "${action}" expected to contain "${contains}", got "${value}"`,
174
+ };
175
+ }
176
+ }
177
+ }
178
+ return {
179
+ assertion,
180
+ passed: true,
181
+ message: `Payload field "${field}" in "${action}" matches expectations`,
182
+ };
183
+ }
184
+ function evalTiming(assertion, ctx) {
185
+ const { actionA, actionB, maxGapMs, minGapMs } = assertion.params;
186
+ const eventA = ctx.events.find((e) => e.messageType === 'Call' && e.action === actionA && e.timestamp !== null);
187
+ const eventB = ctx.events.find((e) => e.messageType === 'Call' && e.action === actionB && e.timestamp !== null);
188
+ if (!eventA || eventA.timestamp === null) {
189
+ return {
190
+ assertion,
191
+ passed: false,
192
+ message: `Action "${actionA}" not found or has no timestamp`,
193
+ };
194
+ }
195
+ if (!eventB || eventB.timestamp === null) {
196
+ return {
197
+ assertion,
198
+ passed: false,
199
+ message: `Action "${actionB}" not found or has no timestamp`,
200
+ };
201
+ }
202
+ const gap = eventB.timestamp - eventA.timestamp;
203
+ if (maxGapMs !== undefined && gap > maxGapMs) {
204
+ return {
205
+ assertion,
206
+ passed: false,
207
+ message: `Gap between "${actionA}" and "${actionB}" is ${gap}ms, exceeds max ${maxGapMs}ms`,
208
+ };
209
+ }
210
+ if (minGapMs !== undefined && gap < minGapMs) {
211
+ return {
212
+ assertion,
213
+ passed: false,
214
+ message: `Gap between "${actionA}" and "${actionB}" is ${gap}ms, below min ${minGapMs}ms`,
215
+ };
216
+ }
217
+ return {
218
+ assertion,
219
+ passed: true,
220
+ message: `Gap between "${actionA}" and "${actionB}" is ${gap}ms (within range)`,
221
+ };
222
+ }
223
+ function evalSessionState(assertion, ctx) {
224
+ const { expected } = assertion.params;
225
+ if (ctx.sessions.length === 0) {
226
+ return { assertion, passed: false, message: 'No sessions found' };
227
+ }
228
+ for (const session of ctx.sessions) {
229
+ if (session.status !== expected) {
230
+ return {
231
+ assertion,
232
+ passed: false,
233
+ message: `Session ${session.sessionId} has status "${session.status}", expected "${expected}"`,
234
+ };
235
+ }
236
+ }
237
+ return {
238
+ assertion,
239
+ passed: true,
240
+ message: `All sessions have status "${expected}"`,
241
+ };
242
+ }
243
+ function evalFailureSeverity(assertion, ctx) {
244
+ const { code, severity } = assertion.params;
245
+ const matching = ctx.failures.find((f) => f.code === code);
246
+ if (!matching) {
247
+ return {
248
+ assertion,
249
+ passed: false,
250
+ message: `Failure with code "${code}" not detected`,
251
+ };
252
+ }
253
+ if (matching.severity !== severity) {
254
+ return {
255
+ assertion,
256
+ passed: false,
257
+ message: `Failure "${code}" has severity "${matching.severity}", expected "${severity}"`,
258
+ };
259
+ }
260
+ return {
261
+ assertion,
262
+ passed: true,
263
+ message: `Failure "${code}" has severity "${severity}" as expected`,
264
+ };
265
+ }
266
+ function evalNoFailures(assertion, ctx) {
267
+ if (ctx.failures.length > 0) {
268
+ return {
269
+ assertion,
270
+ passed: false,
271
+ message: `Expected no failures, but ${ctx.failures.length} detected: ${ctx.failures.map((f) => f.code).join(', ')}`,
272
+ };
273
+ }
274
+ return { assertion, passed: true, message: 'No failures detected as expected' };
275
+ }
276
+ function evalFailureCount(assertion, ctx) {
277
+ const { min, max, code } = assertion.params;
278
+ const count = code ? ctx.failures.filter((f) => f.code === code).length : ctx.failures.length;
279
+ if (min !== undefined && count < min) {
280
+ return {
281
+ assertion,
282
+ passed: false,
283
+ message: `Expected at least ${min} ${code ? `"${code}" ` : ''}failures, got ${count}`,
284
+ };
285
+ }
286
+ if (max !== undefined && count > max) {
287
+ return {
288
+ assertion,
289
+ passed: false,
290
+ message: `Expected at most ${max} ${code ? `"${code}" ` : ''}failures, got ${count}`,
291
+ };
292
+ }
293
+ return {
294
+ assertion,
295
+ passed: true,
296
+ message: `Failure count ${count} ${code ? `for "${code}" ` : ''}is within range [${min ?? 0}, ${max ?? '∞'}]`,
297
+ };
298
+ }
299
+ // ---------------------------------------------------------------------------
300
+ // Batch evaluation
301
+ // ---------------------------------------------------------------------------
302
+ /**
303
+ * Evaluate multiple assertions against the analysis context.
304
+ */
305
+ export function runAssertions(ctx, assertions) {
306
+ return assertions.map((assertion) => runAssertion(assertion, ctx));
307
+ }
308
+ /**
309
+ * Evaluate a scenario: parse the trace, run detection, evaluate assertions,
310
+ * and compare detected vs expected failures.
311
+ */
312
+ export function evaluateScenario(scenario) {
313
+ const { events } = parseTrace(JSON.stringify(scenario.trace));
314
+ const sessions = buildSessionTimeline(events);
315
+ const failures = detectFailures(events, sessions);
316
+ const detectedFailureCodes = [...new Set(failures.map((f) => f.code))];
317
+ // Compare detected vs expected failures (deduplicated)
318
+ const sortedDetected = [...detectedFailureCodes].sort();
319
+ const sortedExpected = [...scenario.expectedFailures].sort();
320
+ const expectedFailuresPassed = JSON.stringify(sortedDetected) === JSON.stringify(sortedExpected);
321
+ // Evaluate assertions
322
+ const ctx = { events, sessions, failures };
323
+ const assertions = scenario.assertions ? runAssertions(ctx, scenario.assertions) : [];
324
+ // Use summaries to ensure sessions are properly evaluated
325
+ summarizeSessions(sessions, failures);
326
+ const allPassed = expectedFailuresPassed && (assertions.length === 0 || assertions.every((a) => a.passed));
327
+ return {
328
+ assertions,
329
+ allPassed,
330
+ failures,
331
+ detectedFailureCodes,
332
+ expectedFailuresPassed,
333
+ };
334
+ }
335
+ //# sourceMappingURL=assertions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertions.js","sourceRoot":"","sources":["../../src/core/assertions.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Failure detection — analyzes events and sessions for known failure patterns.
3
3
  *
4
- * 10 detection rules (v0.1 + v0.2):
4
+ * 16 detection rules (v0.1 + v0.2 + v0.3):
5
5
  *
6
6
  * v0.1:
7
7
  * 1. FAILED_AUTHORIZATION — Authorize response with idTagInfo.status = "Invalid"
@@ -17,6 +17,14 @@
17
17
  * 9. DIAGNOSTICS_FAILURE — DiagnosticsStatusNotification indicating failure
18
18
  * 10. FIRMWARE_UPDATE_FAILURE — FirmwareStatusNotification indicating failure
19
19
  *
20
+ * v0.3:
21
+ * 11. SUSPICIOUS_SESSION_DURATION — session < 60s or > 24h
22
+ * 12. SLOW_RESPONSE — gap between Call and matching CallResult/CallError > 10s
23
+ * 13. HEARTBEAT_INTERVAL_VIOLATION — heartbeat intervals deviate >50% from expected
24
+ * 14. METER_VALUE_ANOMALY — non-monotonic or negative meter readings
25
+ * 15. UNRESPONSIVE_CSMS — Call with no matching CallResult or CallError
26
+ * 16. REPEATED_BOOT_NOTIFICATION — 2+ BootNotification calls within 5 minutes
27
+ *
20
28
  * @see ADR-0003
21
29
  */
22
30
  import type { Event, Failure, Session } from './types.js';
@@ -1 +1 @@
1
- {"version":3,"file":"detection.d.ts","sourceRoot":"","sources":["../../src/core/detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAgC,OAAO,EAAE,MAAM,YAAY,CAAC;AAyRxF;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAkB9E"}
1
+ {"version":3,"file":"detection.d.ts","sourceRoot":"","sources":["../../src/core/detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAgC,OAAO,EAAE,MAAM,YAAY,CAAC;AAyUxF;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CA0B9E"}