@forgehive/task 0.2.3 → 0.2.4
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/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -9
- package/dist/index.js.map +1 -1
- package/dist/test/add-listener-with-boundaries.test.js +78 -7
- package/dist/test/add-listener-with-boundaries.test.js.map +1 -1
- package/dist/test/add-listener.test.js +36 -0
- package/dist/test/add-listener.test.js.map +1 -1
- package/dist/test/boundary-modes.test.js +45 -5
- package/dist/test/boundary-modes.test.js.map +1 -1
- package/dist/test/execution-record-boundaries.test.js +12 -2
- package/dist/test/execution-record-boundaries.test.js.map +1 -1
- package/dist/test/integration-enhanced-records.test.d.ts +2 -0
- package/dist/test/integration-enhanced-records.test.d.ts.map +1 -0
- package/dist/test/integration-enhanced-records.test.js +467 -0
- package/dist/test/integration-enhanced-records.test.js.map +1 -0
- package/dist/test/metrics-collection.test.d.ts +2 -0
- package/dist/test/metrics-collection.test.d.ts.map +1 -0
- package/dist/test/metrics-collection.test.js +409 -0
- package/dist/test/metrics-collection.test.js.map +1 -0
- package/dist/test/performance-edge-cases.test.d.ts +2 -0
- package/dist/test/performance-edge-cases.test.d.ts.map +1 -0
- package/dist/test/performance-edge-cases.test.js +502 -0
- package/dist/test/performance-edge-cases.test.js.map +1 -0
- package/dist/test/run-boundary.test.js +27 -3
- package/dist/test/run-boundary.test.js.map +1 -1
- package/dist/test/safe-replay-complex-boundary.test.js +110 -9
- package/dist/test/safe-replay-complex-boundary.test.js.map +1 -1
- package/dist/test/safe-replay.test.js +35 -5
- package/dist/test/safe-replay.test.js.map +1 -1
- package/dist/test/safe-run.test.js +46 -4
- package/dist/test/safe-run.test.js.map +1 -1
- package/dist/test/setmetrics-boundary.test.d.ts +2 -0
- package/dist/test/setmetrics-boundary.test.d.ts.map +1 -0
- package/dist/test/setmetrics-boundary.test.js +195 -0
- package/dist/test/setmetrics-boundary.test.js.map +1 -0
- package/dist/test/task-with-boundaries.test.js +63 -2
- package/dist/test/task-with-boundaries.test.js.map +1 -1
- package/dist/test/timing-capture.test.d.ts +2 -0
- package/dist/test/timing-capture.test.d.ts.map +1 -0
- package/dist/test/timing-capture.test.js +304 -0
- package/dist/test/timing-capture.test.js.map +1 -0
- package/dist/test/timing-utilities.test.d.ts +2 -0
- package/dist/test/timing-utilities.test.d.ts.map +1 -0
- package/dist/test/timing-utilities.test.js +127 -0
- package/dist/test/timing-utilities.test.js.map +1 -0
- package/dist/types.d.ts +93 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +78 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/boundary.d.ts +3 -0
- package/dist/utils/boundary.d.ts.map +1 -1
- package/dist/utils/boundary.js +11 -2
- package/dist/utils/boundary.js.map +1 -1
- package/package.json +3 -2
- package/src/index.ts +63 -8
- package/src/test/add-listener-with-boundaries.test.ts +78 -7
- package/src/test/add-listener.test.ts +36 -0
- package/src/test/boundary-modes.test.ts +45 -5
- package/src/test/execution-record-boundaries.test.ts +12 -2
- package/src/test/metrics-collection.test.ts +476 -0
- package/src/test/performance-edge-cases.test.ts +596 -0
- package/src/test/run-boundary.test.ts +27 -3
- package/src/test/safe-replay-complex-boundary.test.ts +115 -10
- package/src/test/safe-replay.test.ts +35 -5
- package/src/test/safe-run.test.ts +46 -4
- package/src/test/setmetrics-boundary.test.ts +223 -0
- package/src/test/task-with-boundaries.test.ts +71 -5
- package/src/test/timing-capture.test.ts +348 -0
- package/src/test/timing-utilities.test.ts +145 -0
- package/src/types.ts +139 -0
- package/src/utils/boundary.ts +15 -2
package/dist/utils/boundary.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TimingInfo } from '../types';
|
|
1
2
|
type BaseBoundary = (...args: unknown[]) => unknown;
|
|
2
3
|
export type Mode = 'proxy' | 'proxy-pass' | 'proxy-catch' | 'replay';
|
|
3
4
|
/**
|
|
@@ -15,6 +16,7 @@ export type BoundarySuccessRecord<TInput = unknown[], TOutput = unknown> = {
|
|
|
15
16
|
input: TInput;
|
|
16
17
|
output: TOutput;
|
|
17
18
|
error?: null;
|
|
19
|
+
timing: TimingInfo;
|
|
18
20
|
};
|
|
19
21
|
/**
|
|
20
22
|
* Error record for a boundary function call
|
|
@@ -24,6 +26,7 @@ export type BoundaryErrorRecord<TInput = unknown[]> = {
|
|
|
24
26
|
input: TInput;
|
|
25
27
|
output?: null;
|
|
26
28
|
error: string;
|
|
29
|
+
timing: TimingInfo;
|
|
27
30
|
};
|
|
28
31
|
/**
|
|
29
32
|
* Represents a record of a boundary function call - either success or error
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"boundary.d.ts","sourceRoot":"","sources":["../../src/utils/boundary.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"boundary.d.ts","sourceRoot":"","sources":["../../src/utils/boundary.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAiB,MAAM,UAAU,CAAA;AAGpD,KAAK,YAAY,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAA;AAEnD,MAAM,MAAM,IAAI,GAAG,OAAO,GAAG,YAAY,GAAG,aAAa,GAAG,QAAQ,CAAA;AAEpE;;;;GAIG;AAEH,MAAM,MAAM,gBAAgB,CAAC,OAAO,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAElF;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,CAAC,MAAM,GAAG,OAAO,EAAE,EAAE,OAAO,GAAG,OAAO,IAAI;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;CACpB,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,mBAAmB,CAAC,MAAM,GAAG,OAAO,EAAE,IAAI;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;CACpB,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,cAAc,CAAC,MAAM,GAAG,OAAO,EAAE,EAAE,OAAO,GAAG,OAAO,IAC9D,qBAAqB,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAEvE;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,uBAAuB,CAAC,IAAI,SAAS,gBAAgB,GAAG,gBAAgB;IACvF,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;IACtD,OAAO,EAAE,MAAM,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;IACjF,OAAO,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IAC9F,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,OAAO,EAAE,CAAC,OAAO,EAAE,IAAI,KAAK,IAAI,CAAA;IAChC,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,UAAU,EAAE,MAAM,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;CACrF;AAED;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;AAEzD;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,IAAI;KAChE,CAAC,IAAI,MAAM,CAAC,GAAG,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC9C,CAAA;AAED,eAAO,MAAM,cAAc,GAAI,IAAI,SAAS,YAAY,EAAE,IAAI,IAAI,KAAG,uBAAuB,CAAC,IAAI,SAAS,gBAAgB,GAAG,IAAI,GAAG,KAAK,CA2IxI,CAAA"}
|
package/dist/utils/boundary.js
CHANGED
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.createBoundary = void 0;
|
|
37
37
|
const assert = __importStar(require("assert"));
|
|
38
|
+
const types_1 = require("../types");
|
|
38
39
|
const createBoundary = (fn) => {
|
|
39
40
|
let runLog = [];
|
|
40
41
|
let cacheTape = [];
|
|
@@ -79,6 +80,8 @@ const createBoundary = (fn) => {
|
|
|
79
80
|
})();
|
|
80
81
|
}
|
|
81
82
|
return await (async () => {
|
|
83
|
+
const timer = types_1.TimingTracker.create();
|
|
84
|
+
timer.start();
|
|
82
85
|
let result, error;
|
|
83
86
|
try {
|
|
84
87
|
result = await fn(...args);
|
|
@@ -86,6 +89,10 @@ const createBoundary = (fn) => {
|
|
|
86
89
|
catch (e) {
|
|
87
90
|
error = e;
|
|
88
91
|
}
|
|
92
|
+
const timing = timer.end();
|
|
93
|
+
if (!timing) {
|
|
94
|
+
throw new Error('Failed to capture timing information');
|
|
95
|
+
}
|
|
89
96
|
if (typeof error !== 'undefined') {
|
|
90
97
|
const prevRecord = findRecord(args, cacheTape);
|
|
91
98
|
if (mode === 'proxy-catch' && typeof prevRecord !== 'undefined') {
|
|
@@ -97,7 +104,8 @@ const createBoundary = (fn) => {
|
|
|
97
104
|
// Create an error record
|
|
98
105
|
const errorRecord = {
|
|
99
106
|
input: args,
|
|
100
|
-
error: error.message
|
|
107
|
+
error: error.message,
|
|
108
|
+
timing
|
|
101
109
|
};
|
|
102
110
|
if (hasRun) {
|
|
103
111
|
runLog.push(errorRecord);
|
|
@@ -110,7 +118,8 @@ const createBoundary = (fn) => {
|
|
|
110
118
|
// Create a success record
|
|
111
119
|
const successRecord = {
|
|
112
120
|
input: args,
|
|
113
|
-
output: result
|
|
121
|
+
output: result,
|
|
122
|
+
timing
|
|
114
123
|
};
|
|
115
124
|
if (hasRun) {
|
|
116
125
|
runLog.push(successRecord);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"boundary.js","sourceRoot":"","sources":["../../src/utils/boundary.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAgC;
|
|
1
|
+
{"version":3,"file":"boundary.js","sourceRoot":"","sources":["../../src/utils/boundary.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgehive/task",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"build": "tsc",
|
|
26
26
|
"dev": "tsc --watch",
|
|
27
27
|
"clean": "rm -rf dist",
|
|
28
|
-
"test": "jest"
|
|
28
|
+
"test": "jest",
|
|
29
|
+
"lint:fix": "eslint src --ext .ts --fix"
|
|
29
30
|
}
|
|
30
31
|
}
|
package/src/index.ts
CHANGED
|
@@ -8,6 +8,13 @@ import {
|
|
|
8
8
|
type BoundaryRecord,
|
|
9
9
|
type BoundaryTapeData
|
|
10
10
|
} from './utils/boundary'
|
|
11
|
+
import {
|
|
12
|
+
TimingTracker,
|
|
13
|
+
type Metric,
|
|
14
|
+
type TimingInfo,
|
|
15
|
+
validateMetric,
|
|
16
|
+
createMetric
|
|
17
|
+
} from './types'
|
|
11
18
|
|
|
12
19
|
export interface Task {
|
|
13
20
|
id: string;
|
|
@@ -31,6 +38,17 @@ export type {
|
|
|
31
38
|
BoundaryTapeData
|
|
32
39
|
} from './utils/boundary'
|
|
33
40
|
|
|
41
|
+
// Re-export timing and metrics types for external use
|
|
42
|
+
export type {
|
|
43
|
+
TimingInfo,
|
|
44
|
+
Metric,
|
|
45
|
+
BoundaryTimingRecord,
|
|
46
|
+
BaseExecutionRecord
|
|
47
|
+
} from './types'
|
|
48
|
+
|
|
49
|
+
// Re-export timing and metrics utilities for external use
|
|
50
|
+
export { TimingTracker, validateMetric, createMetric }
|
|
51
|
+
|
|
34
52
|
// Re-export Schema for external use
|
|
35
53
|
export { Schema }
|
|
36
54
|
|
|
@@ -76,6 +94,10 @@ export interface ExecutionRecord<InputType = unknown, OutputType = unknown, B ex
|
|
|
76
94
|
taskName?: string
|
|
77
95
|
/** Additional context metadata */
|
|
78
96
|
metadata?: Record<string, string>
|
|
97
|
+
/** Array of collected metrics */
|
|
98
|
+
metrics?: Metric[]
|
|
99
|
+
/** Main function execution timing */
|
|
100
|
+
timing?: TimingInfo
|
|
79
101
|
/** The type of execution record - computed from output/error state */
|
|
80
102
|
type: 'success' | 'error' | 'pending'
|
|
81
103
|
}
|
|
@@ -140,6 +162,7 @@ export type InferSchemaType<S> = S extends Schema<any> ? InferSchema<S> : Record
|
|
|
140
162
|
// When adding new execution boundaries, add their types here
|
|
141
163
|
export type ExecutionRecordBoundaries = {
|
|
142
164
|
setMetadata: (key: string, value: string) => Promise<void>
|
|
165
|
+
setMetrics: (metric: Metric) => Promise<void>
|
|
143
166
|
// Future execution boundaries can be added here:
|
|
144
167
|
// setContext: (context: Record<string, unknown>) => Promise<void>
|
|
145
168
|
// addTag: (tag: string) => Promise<void>
|
|
@@ -401,16 +424,29 @@ export const Task = class Task<
|
|
|
401
424
|
* 2. Update the ExecutionRecordBoundaries type to include the new boundary
|
|
402
425
|
* 3. That's it! The boundary will be available in all tasks automatically
|
|
403
426
|
*/
|
|
404
|
-
_createExecutionBoundaries(metadata: Record<string, string
|
|
427
|
+
_createExecutionBoundaries(metadata: Record<string, string>, metrics: Metric[]): Record<string, WrappedBoundaryFunction> {
|
|
405
428
|
return {
|
|
406
429
|
// Allows setting metadata key-value pairs from within task execution
|
|
407
430
|
setMetadata: createBoundary(async (...args: unknown[]): Promise<void> => {
|
|
408
431
|
const [key, value] = args as [string, string]
|
|
409
432
|
metadata[key] = value
|
|
433
|
+
}),
|
|
434
|
+
|
|
435
|
+
// Allows setting metrics from within task execution
|
|
436
|
+
setMetrics: createBoundary(async (...args: unknown[]): Promise<void> => {
|
|
437
|
+
const [metric] = args as [Metric]
|
|
438
|
+
|
|
439
|
+
// Validate the metric
|
|
440
|
+
if (!validateMetric(metric)) {
|
|
441
|
+
throw new Error(`Invalid metric provided: ${JSON.stringify(metric)}`)
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Add to metrics array
|
|
445
|
+
metrics.push(metric)
|
|
410
446
|
})
|
|
411
447
|
|
|
412
448
|
// Future execution boundaries can be added here:
|
|
413
|
-
//
|
|
449
|
+
// setContext: createBoundary(async (...args: unknown[]): Promise<void> => { ... }),
|
|
414
450
|
}
|
|
415
451
|
}
|
|
416
452
|
|
|
@@ -469,12 +505,16 @@ export const Task = class Task<
|
|
|
469
505
|
// Need to implement that task have a ctx and setMetadata({key, value}) boundary
|
|
470
506
|
const metadata = {} as Record<string, string>
|
|
471
507
|
|
|
508
|
+
// Metrics array is empty at start. Then will be populated during task execution
|
|
509
|
+
const metrics: Metric[] = []
|
|
510
|
+
|
|
472
511
|
// Initialize log item (without type initially)
|
|
473
512
|
const logItemBase = {
|
|
474
513
|
input: argv as Parameters<Func>[0],
|
|
475
514
|
boundaries: {} as BoundaryLogsFor<B>,
|
|
476
515
|
taskName: this._name,
|
|
477
|
-
metadata: metadata || {}
|
|
516
|
+
metadata: metadata || {},
|
|
517
|
+
metrics
|
|
478
518
|
}
|
|
479
519
|
|
|
480
520
|
// Create the log item with computed type
|
|
@@ -490,8 +530,8 @@ export const Task = class Task<
|
|
|
490
530
|
mode: this._mode
|
|
491
531
|
})
|
|
492
532
|
|
|
493
|
-
// Create and inject execution record boundaries (setMetadata, etc.)
|
|
494
|
-
const executionRecordBoundaries = this._createExecutionBoundaries(metadata)
|
|
533
|
+
// Create and inject execution record boundaries (setMetadata, setMetrics, etc.)
|
|
534
|
+
const executionRecordBoundaries = this._createExecutionBoundaries(metadata, metrics)
|
|
495
535
|
const allBoundaries = {
|
|
496
536
|
...executionBoundaries,
|
|
497
537
|
...executionRecordBoundaries
|
|
@@ -532,6 +572,10 @@ export const Task = class Task<
|
|
|
532
572
|
let output: Awaited<ReturnType<Func>> | null = null
|
|
533
573
|
let error: Error | null = null
|
|
534
574
|
|
|
575
|
+
// Start timing for main function execution
|
|
576
|
+
const timer = TimingTracker.create()
|
|
577
|
+
timer.start()
|
|
578
|
+
|
|
535
579
|
try {
|
|
536
580
|
// Execute the task function
|
|
537
581
|
output = await this._fn(
|
|
@@ -548,6 +592,12 @@ export const Task = class Task<
|
|
|
548
592
|
error = new Error(errorMessage)
|
|
549
593
|
}
|
|
550
594
|
|
|
595
|
+
// Capture timing for main function execution
|
|
596
|
+
const timing = timer.end()
|
|
597
|
+
if (timing) {
|
|
598
|
+
logItem.timing = timing
|
|
599
|
+
}
|
|
600
|
+
|
|
551
601
|
// Process boundary data after execution (both success and error cases)
|
|
552
602
|
const boundariesRunLog: BoundaryLogsFor<B> = {} as BoundaryLogsFor<B>
|
|
553
603
|
|
|
@@ -599,12 +649,17 @@ export const Task = class Task<
|
|
|
599
649
|
// Extract the input from the execution log
|
|
600
650
|
const argv = executionLog.input
|
|
601
651
|
|
|
652
|
+
// Initialize metrics array for replay - start with original metrics if any
|
|
653
|
+
const metrics: Metric[] = executionLog.metrics ? [...executionLog.metrics] : []
|
|
654
|
+
|
|
602
655
|
// Initialize log item for this replay (without type initially)
|
|
603
656
|
const logItemBase = {
|
|
604
657
|
input: argv,
|
|
605
658
|
boundaries: {} as BoundaryLogsFor<B>,
|
|
606
659
|
taskName: this._name,
|
|
607
|
-
metadata: executionLog.metadata || {}
|
|
660
|
+
metadata: executionLog.metadata || {},
|
|
661
|
+
metrics,
|
|
662
|
+
timing: executionLog.timing // Preserve original timing
|
|
608
663
|
}
|
|
609
664
|
|
|
610
665
|
// Create the log item with computed type
|
|
@@ -635,10 +690,10 @@ export const Task = class Task<
|
|
|
635
690
|
boundaryModes: config.boundaries
|
|
636
691
|
})
|
|
637
692
|
|
|
638
|
-
// Create and inject execution record boundaries (setMetadata, etc.)
|
|
693
|
+
// Create and inject execution record boundaries (setMetadata, setMetrics, etc.)
|
|
639
694
|
// Clone the metadata to avoid mutating the original metadata
|
|
640
695
|
const replayMetadata = { ...(logItem.metadata || {}) }
|
|
641
|
-
const executionRecordBoundaries = this._createExecutionBoundaries(replayMetadata)
|
|
696
|
+
const executionRecordBoundaries = this._createExecutionBoundaries(replayMetadata, metrics)
|
|
642
697
|
const allBoundaries = {
|
|
643
698
|
...executionBoundaries,
|
|
644
699
|
...executionRecordBoundaries
|
|
@@ -30,11 +30,22 @@ describe('Listener with boundaries', () => {
|
|
|
30
30
|
boundaries: {
|
|
31
31
|
getTen: [{
|
|
32
32
|
input: [],
|
|
33
|
-
output: 10
|
|
33
|
+
output: 10,
|
|
34
|
+
timing: expect.objectContaining({
|
|
35
|
+
startTime: expect.any(Number),
|
|
36
|
+
endTime: expect.any(Number),
|
|
37
|
+
duration: expect.any(Number)
|
|
38
|
+
})
|
|
34
39
|
}]
|
|
35
40
|
},
|
|
36
41
|
taskName: 'test',
|
|
37
42
|
metadata: {},
|
|
43
|
+
metrics: [],
|
|
44
|
+
timing: expect.objectContaining({
|
|
45
|
+
startTime: expect.any(Number),
|
|
46
|
+
endTime: expect.any(Number),
|
|
47
|
+
duration: expect.any(Number)
|
|
48
|
+
}),
|
|
38
49
|
type: 'success'
|
|
39
50
|
}])
|
|
40
51
|
})
|
|
@@ -73,11 +84,22 @@ describe('Listener with boundaries', () => {
|
|
|
73
84
|
boundaries: {
|
|
74
85
|
getTen: [{
|
|
75
86
|
input: [],
|
|
76
|
-
error: 'Network error'
|
|
87
|
+
error: 'Network error',
|
|
88
|
+
timing: expect.objectContaining({
|
|
89
|
+
startTime: expect.any(Number),
|
|
90
|
+
endTime: expect.any(Number),
|
|
91
|
+
duration: expect.any(Number)
|
|
92
|
+
})
|
|
77
93
|
}]
|
|
78
94
|
},
|
|
79
95
|
taskName: 'test',
|
|
80
96
|
metadata: {},
|
|
97
|
+
metrics: [],
|
|
98
|
+
timing: expect.objectContaining({
|
|
99
|
+
startTime: expect.any(Number),
|
|
100
|
+
endTime: expect.any(Number),
|
|
101
|
+
duration: expect.any(Number)
|
|
102
|
+
}),
|
|
81
103
|
type: 'error'
|
|
82
104
|
}])
|
|
83
105
|
})
|
|
@@ -109,11 +131,22 @@ describe('Listener with boundaries', () => {
|
|
|
109
131
|
boundaries: {
|
|
110
132
|
addNumbers: [{
|
|
111
133
|
input: [3, 7],
|
|
112
|
-
output: 10
|
|
134
|
+
output: 10,
|
|
135
|
+
timing: expect.objectContaining({
|
|
136
|
+
startTime: expect.any(Number),
|
|
137
|
+
endTime: expect.any(Number),
|
|
138
|
+
duration: expect.any(Number)
|
|
139
|
+
})
|
|
113
140
|
}]
|
|
114
141
|
},
|
|
115
142
|
taskName: 'test',
|
|
116
143
|
metadata: {},
|
|
144
|
+
metrics: [],
|
|
145
|
+
timing: expect.objectContaining({
|
|
146
|
+
startTime: expect.any(Number),
|
|
147
|
+
endTime: expect.any(Number),
|
|
148
|
+
duration: expect.any(Number)
|
|
149
|
+
}),
|
|
117
150
|
type: 'success'
|
|
118
151
|
}])
|
|
119
152
|
})
|
|
@@ -147,11 +180,22 @@ describe('Listener with boundaries', () => {
|
|
|
147
180
|
boundaries: {
|
|
148
181
|
processValue: [{
|
|
149
182
|
input: [undefined],
|
|
150
|
-
output: 0
|
|
183
|
+
output: 0,
|
|
184
|
+
timing: expect.objectContaining({
|
|
185
|
+
startTime: expect.any(Number),
|
|
186
|
+
endTime: expect.any(Number),
|
|
187
|
+
duration: expect.any(Number)
|
|
188
|
+
})
|
|
151
189
|
}]
|
|
152
190
|
},
|
|
153
191
|
taskName: 'test',
|
|
154
192
|
metadata: {},
|
|
193
|
+
metrics: [],
|
|
194
|
+
timing: expect.objectContaining({
|
|
195
|
+
startTime: expect.any(Number),
|
|
196
|
+
endTime: expect.any(Number),
|
|
197
|
+
duration: expect.any(Number)
|
|
198
|
+
}),
|
|
155
199
|
type: 'success'
|
|
156
200
|
}])
|
|
157
201
|
})
|
|
@@ -187,16 +231,32 @@ describe('Listener with boundaries', () => {
|
|
|
187
231
|
multiplyByTwo: [
|
|
188
232
|
{
|
|
189
233
|
input: [3],
|
|
190
|
-
output: 6
|
|
234
|
+
output: 6,
|
|
235
|
+
timing: expect.objectContaining({
|
|
236
|
+
startTime: expect.any(Number),
|
|
237
|
+
endTime: expect.any(Number),
|
|
238
|
+
duration: expect.any(Number)
|
|
239
|
+
})
|
|
191
240
|
},
|
|
192
241
|
{
|
|
193
242
|
input: [6],
|
|
194
|
-
output: 12
|
|
243
|
+
output: 12,
|
|
244
|
+
timing: expect.objectContaining({
|
|
245
|
+
startTime: expect.any(Number),
|
|
246
|
+
endTime: expect.any(Number),
|
|
247
|
+
duration: expect.any(Number)
|
|
248
|
+
})
|
|
195
249
|
}
|
|
196
250
|
]
|
|
197
251
|
},
|
|
198
252
|
taskName: 'test',
|
|
199
253
|
metadata: {},
|
|
254
|
+
metrics: [],
|
|
255
|
+
timing: expect.objectContaining({
|
|
256
|
+
startTime: expect.any(Number),
|
|
257
|
+
endTime: expect.any(Number),
|
|
258
|
+
duration: expect.any(Number)
|
|
259
|
+
}),
|
|
200
260
|
type: 'success'
|
|
201
261
|
}])
|
|
202
262
|
})
|
|
@@ -238,11 +298,22 @@ describe('Listener with boundaries', () => {
|
|
|
238
298
|
boundaries: {
|
|
239
299
|
getResult: [{
|
|
240
300
|
input: [3],
|
|
241
|
-
error: 'Number too small'
|
|
301
|
+
error: 'Number too small',
|
|
302
|
+
timing: expect.objectContaining({
|
|
303
|
+
startTime: expect.any(Number),
|
|
304
|
+
endTime: expect.any(Number),
|
|
305
|
+
duration: expect.any(Number)
|
|
306
|
+
})
|
|
242
307
|
}]
|
|
243
308
|
},
|
|
244
309
|
taskName: 'test',
|
|
245
310
|
metadata: {},
|
|
311
|
+
metrics: [],
|
|
312
|
+
timing: expect.objectContaining({
|
|
313
|
+
startTime: expect.any(Number),
|
|
314
|
+
endTime: expect.any(Number),
|
|
315
|
+
duration: expect.any(Number)
|
|
316
|
+
}),
|
|
246
317
|
type: 'success'
|
|
247
318
|
}])
|
|
248
319
|
})
|
|
@@ -18,6 +18,12 @@ describe('Add listener', () => {
|
|
|
18
18
|
boundaries: {},
|
|
19
19
|
taskName: undefined,
|
|
20
20
|
metadata: {},
|
|
21
|
+
metrics: [],
|
|
22
|
+
timing: expect.objectContaining({
|
|
23
|
+
startTime: expect.any(Number),
|
|
24
|
+
endTime: expect.any(Number),
|
|
25
|
+
duration: expect.any(Number)
|
|
26
|
+
}),
|
|
21
27
|
type: 'success'
|
|
22
28
|
}])
|
|
23
29
|
})
|
|
@@ -44,6 +50,12 @@ describe('Add listener', () => {
|
|
|
44
50
|
boundaries: {},
|
|
45
51
|
taskName: undefined,
|
|
46
52
|
metadata: {},
|
|
53
|
+
metrics: [],
|
|
54
|
+
timing: expect.objectContaining({
|
|
55
|
+
startTime: expect.any(Number),
|
|
56
|
+
endTime: expect.any(Number),
|
|
57
|
+
duration: expect.any(Number)
|
|
58
|
+
}),
|
|
47
59
|
type: 'error'
|
|
48
60
|
}])
|
|
49
61
|
})
|
|
@@ -73,6 +85,12 @@ describe('Add listener', () => {
|
|
|
73
85
|
boundaries: {},
|
|
74
86
|
taskName: undefined,
|
|
75
87
|
metadata: {},
|
|
88
|
+
metrics: [],
|
|
89
|
+
timing: expect.objectContaining({
|
|
90
|
+
startTime: expect.any(Number),
|
|
91
|
+
endTime: expect.any(Number),
|
|
92
|
+
duration: expect.any(Number)
|
|
93
|
+
}),
|
|
76
94
|
type: 'error'
|
|
77
95
|
}])
|
|
78
96
|
})
|
|
@@ -97,6 +115,12 @@ describe('Add listener', () => {
|
|
|
97
115
|
boundaries: {},
|
|
98
116
|
taskName: undefined,
|
|
99
117
|
metadata: {},
|
|
118
|
+
metrics: [],
|
|
119
|
+
timing: expect.objectContaining({
|
|
120
|
+
startTime: expect.any(Number),
|
|
121
|
+
endTime: expect.any(Number),
|
|
122
|
+
duration: expect.any(Number)
|
|
123
|
+
}),
|
|
100
124
|
type: 'success'
|
|
101
125
|
},
|
|
102
126
|
{
|
|
@@ -105,6 +129,12 @@ describe('Add listener', () => {
|
|
|
105
129
|
boundaries: {},
|
|
106
130
|
taskName: undefined,
|
|
107
131
|
metadata: {},
|
|
132
|
+
metrics: [],
|
|
133
|
+
timing: expect.objectContaining({
|
|
134
|
+
startTime: expect.any(Number),
|
|
135
|
+
endTime: expect.any(Number),
|
|
136
|
+
duration: expect.any(Number)
|
|
137
|
+
}),
|
|
108
138
|
type: 'success'
|
|
109
139
|
}
|
|
110
140
|
])
|
|
@@ -132,6 +162,12 @@ describe('Add listener', () => {
|
|
|
132
162
|
boundaries: {},
|
|
133
163
|
taskName: undefined,
|
|
134
164
|
metadata: {},
|
|
165
|
+
metrics: [],
|
|
166
|
+
timing: expect.objectContaining({
|
|
167
|
+
startTime: expect.any(Number),
|
|
168
|
+
endTime: expect.any(Number),
|
|
169
|
+
duration: expect.any(Number)
|
|
170
|
+
}),
|
|
135
171
|
type: 'success'
|
|
136
172
|
}])
|
|
137
173
|
})
|
|
@@ -47,7 +47,15 @@ describe('Proxy pass mode', function () {
|
|
|
47
47
|
},
|
|
48
48
|
boundariesData: {
|
|
49
49
|
fetchIncrement: [
|
|
50
|
-
{
|
|
50
|
+
{
|
|
51
|
+
input: [{ value: 5 }],
|
|
52
|
+
output: 5,
|
|
53
|
+
timing: {
|
|
54
|
+
startTime: 1000,
|
|
55
|
+
endTime: 1100,
|
|
56
|
+
duration: 100
|
|
57
|
+
}
|
|
58
|
+
}
|
|
51
59
|
]
|
|
52
60
|
},
|
|
53
61
|
mode: 'proxy-pass'
|
|
@@ -76,7 +84,15 @@ describe('Proxy pass mode', function () {
|
|
|
76
84
|
},
|
|
77
85
|
boundariesData: {
|
|
78
86
|
fetchIncrement: [
|
|
79
|
-
{
|
|
87
|
+
{
|
|
88
|
+
input: [{ value: 6 }],
|
|
89
|
+
output: 5,
|
|
90
|
+
timing: {
|
|
91
|
+
startTime: 1000,
|
|
92
|
+
endTime: 1100,
|
|
93
|
+
duration: 100
|
|
94
|
+
}
|
|
95
|
+
}
|
|
80
96
|
]
|
|
81
97
|
},
|
|
82
98
|
mode: 'proxy-pass'
|
|
@@ -108,7 +124,15 @@ describe('Proxy catch mode', function () {
|
|
|
108
124
|
},
|
|
109
125
|
boundariesData: {
|
|
110
126
|
fetchIncrement: [
|
|
111
|
-
{
|
|
127
|
+
{
|
|
128
|
+
input: [{ value: 5 }],
|
|
129
|
+
output: 5,
|
|
130
|
+
timing: {
|
|
131
|
+
startTime: 1000,
|
|
132
|
+
endTime: 1100,
|
|
133
|
+
duration: 100
|
|
134
|
+
}
|
|
135
|
+
}
|
|
112
136
|
]
|
|
113
137
|
},
|
|
114
138
|
mode: 'proxy-catch'
|
|
@@ -137,7 +161,15 @@ describe('Proxy catch mode', function () {
|
|
|
137
161
|
},
|
|
138
162
|
boundariesData: {
|
|
139
163
|
fetchIncrement: [
|
|
140
|
-
{
|
|
164
|
+
{
|
|
165
|
+
input: [{ value: 5 }],
|
|
166
|
+
output: 5,
|
|
167
|
+
timing: {
|
|
168
|
+
startTime: 1000,
|
|
169
|
+
endTime: 1100,
|
|
170
|
+
duration: 100
|
|
171
|
+
}
|
|
172
|
+
}
|
|
141
173
|
]
|
|
142
174
|
},
|
|
143
175
|
mode: 'proxy-catch'
|
|
@@ -169,7 +201,15 @@ describe('Replay mode', function () {
|
|
|
169
201
|
},
|
|
170
202
|
boundariesData: {
|
|
171
203
|
fetchIncrement: [
|
|
172
|
-
{
|
|
204
|
+
{
|
|
205
|
+
input: [{ value: 5 }],
|
|
206
|
+
output: 5,
|
|
207
|
+
timing: {
|
|
208
|
+
startTime: 1000,
|
|
209
|
+
endTime: 1100,
|
|
210
|
+
duration: 100
|
|
211
|
+
}
|
|
212
|
+
}
|
|
173
213
|
]
|
|
174
214
|
},
|
|
175
215
|
mode: 'replay'
|
|
@@ -92,13 +92,23 @@ describe('execution-record-boundaries', () => {
|
|
|
92
92
|
expect(record.boundaries.multiply).toHaveLength(1)
|
|
93
93
|
expect(record.boundaries.multiply[0]).toEqual({
|
|
94
94
|
input: [3],
|
|
95
|
-
output: 6
|
|
95
|
+
output: 6,
|
|
96
|
+
timing: expect.objectContaining({
|
|
97
|
+
startTime: expect.any(Number),
|
|
98
|
+
endTime: expect.any(Number),
|
|
99
|
+
duration: expect.any(Number)
|
|
100
|
+
})
|
|
96
101
|
})
|
|
97
102
|
|
|
98
103
|
expect(record.boundaries.fetchData).toHaveLength(1)
|
|
99
104
|
expect(record.boundaries.fetchData[0]).toEqual({
|
|
100
105
|
input: ['test'],
|
|
101
|
-
output: 'fetched-test'
|
|
106
|
+
output: 'fetched-test',
|
|
107
|
+
timing: expect.objectContaining({
|
|
108
|
+
startTime: expect.any(Number),
|
|
109
|
+
endTime: expect.any(Number),
|
|
110
|
+
duration: expect.any(Number)
|
|
111
|
+
})
|
|
102
112
|
})
|
|
103
113
|
})
|
|
104
114
|
|