autotel 4.1.0 → 4.2.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.
- package/dist/auto.cjs +5 -3
- package/dist/auto.cjs.map +1 -1
- package/dist/auto.js +3 -3
- package/dist/auto.js.map +1 -1
- package/dist/chunk-C_NdSu1c.cjs +34 -0
- package/dist/correlation-id.cjs +1 -1
- package/dist/correlation-id.d.cts.map +1 -1
- package/dist/correlation-id.d.ts.map +1 -1
- package/dist/correlation-id.js +1 -1
- package/dist/decorators.cjs +1 -1
- package/dist/decorators.js +1 -1
- package/dist/{event-ByBTV9M2.js → event-531asIM6.js} +4 -4
- package/dist/{event-ByBTV9M2.js.map → event-531asIM6.js.map} +1 -1
- package/dist/{event-BhHREDJk.cjs → event-CcZYwp50.cjs} +4 -4
- package/dist/{event-BhHREDJk.cjs.map → event-CcZYwp50.cjs.map} +1 -1
- package/dist/event.cjs +1 -1
- package/dist/event.js +1 -1
- package/dist/{functional-zpzNLhky.cjs → functional-C8B0Qa7o.cjs} +10 -7
- package/dist/functional-C8B0Qa7o.cjs.map +1 -0
- package/dist/{functional-DtI0u4vx.js → functional-r-AUIRy_.js} +9 -9
- package/dist/functional-r-AUIRy_.js.map +1 -0
- package/dist/functional.cjs +1 -1
- package/dist/functional.js +1 -1
- package/dist/http.cjs +1 -1
- package/dist/http.js +1 -1
- package/dist/index.cjs +15 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -14
- package/dist/index.js.map +1 -1
- package/dist/{init-D-jnNMix.js → init-BS2JVkrL.js} +2 -2
- package/dist/{init-D-jnNMix.js.map → init-BS2JVkrL.js.map} +1 -1
- package/dist/{init-BX7AmFRl.cjs → init-BXiuPK6j.cjs} +3 -3
- package/dist/{init-BX7AmFRl.cjs.map → init-BXiuPK6j.cjs.map} +1 -1
- package/dist/instrumentation.cjs +2 -2
- package/dist/instrumentation.js +2 -2
- package/dist/logger.cjs +236 -8
- package/dist/logger.cjs.map +1 -0
- package/dist/messaging.cjs +1 -1
- package/dist/messaging.js +1 -1
- package/dist/{node-require-DF5QBX6z.cjs → node-require-CZ_PU448.cjs} +6 -4
- package/dist/node-require-CZ_PU448.cjs.map +1 -0
- package/dist/{node-require-Db1oDpLj.js → node-require-vROmTeJ8.js} +5 -5
- package/dist/node-require-vROmTeJ8.js.map +1 -0
- package/dist/{operation-context-C-2hmmtP.js → operation-context-CKBoA4Qy.js} +3 -3
- package/dist/operation-context-CKBoA4Qy.js.map +1 -0
- package/dist/{operation-context-n4_obUwq.cjs → operation-context-D6LDf4W_.cjs} +3 -1
- package/dist/operation-context-D6LDf4W_.cjs.map +1 -0
- package/dist/register.cjs +3 -1
- package/dist/register.cjs.map +1 -1
- package/dist/register.js +2 -2
- package/dist/register.js.map +1 -1
- package/dist/semantic-helpers.cjs +1 -1
- package/dist/semantic-helpers.js +1 -1
- package/dist/{stable-hash-Cg5cT34Q.js → stable-hash-ChFBIhNt.js} +3 -3
- package/dist/stable-hash-ChFBIhNt.js.map +1 -0
- package/dist/{stable-hash-BNTMrmdB.cjs → stable-hash-brKISGf1.cjs} +4 -2
- package/dist/stable-hash-brKISGf1.cjs.map +1 -0
- package/dist/trace-context-Cijqoi6e.d.cts.map +1 -1
- package/dist/trace-context-Cijqoi6e.d.ts.map +1 -1
- package/dist/trace-helpers.cjs +1 -1
- package/dist/trace-helpers.js +1 -1
- package/dist/{track-wc0HafS_.js → track-COUuU48p.js} +5 -5
- package/dist/track-COUuU48p.js.map +1 -0
- package/dist/{track-D59FfpL0.cjs → track-Cb3Q4QmS.cjs} +4 -2
- package/dist/track-Cb3Q4QmS.cjs.map +1 -0
- package/dist/validate.cjs +1 -1
- package/dist/validate.js +1 -1
- package/dist/webhook.cjs +1 -1
- package/dist/webhook.js +1 -1
- package/dist/workflow-distributed.cjs +1 -1
- package/dist/workflow-distributed.js +1 -1
- package/dist/workflow.cjs +3 -1
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts.map +1 -1
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +3 -3
- package/dist/workflow.js.map +1 -1
- package/dist/yaml-config.cjs +233 -4
- package/dist/yaml-config.cjs.map +1 -0
- package/dist/yaml-config.d.cts.map +1 -1
- package/dist/yaml-config.d.ts.map +1 -1
- package/dist/yaml-config.js +8 -7
- package/dist/yaml-config.js.map +1 -1
- package/package.json +1 -2
- package/dist/functional-DtI0u4vx.js.map +0 -1
- package/dist/functional-zpzNLhky.cjs.map +0 -1
- package/dist/logger-thMPLpOG.cjs +0 -487
- package/dist/logger-thMPLpOG.cjs.map +0 -1
- package/dist/node-require-DF5QBX6z.cjs.map +0 -1
- package/dist/node-require-Db1oDpLj.js.map +0 -1
- package/dist/operation-context-C-2hmmtP.js.map +0 -1
- package/dist/operation-context-n4_obUwq.cjs.map +0 -1
- package/dist/stable-hash-BNTMrmdB.cjs.map +0 -1
- package/dist/stable-hash-Cg5cT34Q.js.map +0 -1
- package/dist/track-D59FfpL0.cjs.map +0 -1
- package/dist/track-wc0HafS_.js.map +0 -1
- package/dist/yaml-config-Ck2uB0Dp.cjs +0 -273
- package/dist/yaml-config-Ck2uB0Dp.cjs.map +0 -1
- package/src/attribute-redacting-processor.test.ts +0 -763
- package/src/attribute-redacting-processor.ts +0 -621
- package/src/attributes/attachers.ts +0 -161
- package/src/attributes/builders.ts +0 -529
- package/src/attributes/domains.ts +0 -42
- package/src/attributes/index.ts +0 -81
- package/src/attributes/registry.ts +0 -323
- package/src/attributes/types.ts +0 -211
- package/src/attributes/utils.ts +0 -64
- package/src/attributes/validators.ts +0 -266
- package/src/attributes.test.ts +0 -292
- package/src/auto.ts +0 -67
- package/src/autotel-logger.test.ts +0 -548
- package/src/autotel-logger.ts +0 -364
- package/src/baggage-span-processor.test.ts +0 -202
- package/src/baggage-span-processor.ts +0 -100
- package/src/business-baggage.test.ts +0 -500
- package/src/business-baggage.ts +0 -669
- package/src/circuit-breaker.test.ts +0 -341
- package/src/circuit-breaker.ts +0 -184
- package/src/config.test.ts +0 -94
- package/src/config.ts +0 -172
- package/src/correlated-events.test.ts +0 -151
- package/src/correlated-events.ts +0 -47
- package/src/correlation-id.test.ts +0 -163
- package/src/correlation-id.ts +0 -206
- package/src/db.test.ts +0 -252
- package/src/db.ts +0 -447
- package/src/decorators.test.ts +0 -153
- package/src/decorators.ts +0 -188
- package/src/define-event.test.ts +0 -41
- package/src/define-event.ts +0 -58
- package/src/devtools.ts +0 -60
- package/src/drain-pipeline.test.ts +0 -68
- package/src/drain-pipeline.ts +0 -199
- package/src/drain-toolkit.test.ts +0 -113
- package/src/drain-toolkit.ts +0 -129
- package/src/enricher-toolkit.test.ts +0 -67
- package/src/enricher-toolkit.ts +0 -79
- package/src/enrichers.test.ts +0 -150
- package/src/enrichers.ts +0 -145
- package/src/env-config.test.ts +0 -323
- package/src/env-config.ts +0 -309
- package/src/error-catalog.test.ts +0 -133
- package/src/error-catalog.ts +0 -262
- package/src/event-queue.test.ts +0 -864
- package/src/event-queue.ts +0 -699
- package/src/event-subscriber.ts +0 -262
- package/src/event-testing.ts +0 -197
- package/src/event.test.ts +0 -1104
- package/src/event.ts +0 -988
- package/src/events-config.ts +0 -235
- package/src/exporters.ts +0 -165
- package/src/filtering-span-processor.test.ts +0 -281
- package/src/filtering-span-processor.ts +0 -111
- package/src/flatten-attributes.test.ts +0 -76
- package/src/flatten-attributes.ts +0 -80
- package/src/functional.strict-types.typecheck.ts +0 -53
- package/src/functional.test.ts +0 -1464
- package/src/functional.ts +0 -2539
- package/src/functional.types.test.ts +0 -135
- package/src/hook.mjs +0 -15
- package/src/http.test.ts +0 -485
- package/src/http.ts +0 -424
- package/src/index.ts +0 -433
- package/src/init-auto-redactor.test.ts +0 -53
- package/src/init-redactor.test.ts +0 -8
- package/src/init.customization.test.ts +0 -665
- package/src/init.integrations.test.ts +0 -399
- package/src/init.openllmetry.test.ts +0 -194
- package/src/init.protocol.test.ts +0 -215
- package/src/init.ts +0 -2439
- package/src/instrumentation.test.ts +0 -108
- package/src/instrumentation.ts +0 -319
- package/src/logger.test.ts +0 -125
- package/src/logger.ts +0 -341
- package/src/messaging-adapters.test.ts +0 -595
- package/src/messaging-adapters.ts +0 -583
- package/src/messaging-testing.test.ts +0 -573
- package/src/messaging-testing.ts +0 -935
- package/src/messaging.test.ts +0 -1646
- package/src/messaging.ts +0 -2245
- package/src/metric-helpers.ts +0 -47
- package/src/metric-testing.ts +0 -197
- package/src/metric.ts +0 -446
- package/src/metrics.test.ts +0 -241
- package/src/node-require.ts +0 -123
- package/src/operation-context.ts +0 -93
- package/src/parse-error.test.ts +0 -73
- package/src/parse-error.ts +0 -112
- package/src/posthog-logs.test.ts +0 -115
- package/src/posthog-logs.ts +0 -77
- package/src/pretty-console-exporter.test.ts +0 -545
- package/src/pretty-console-exporter.ts +0 -413
- package/src/pretty-log-formatter.test.ts +0 -123
- package/src/pretty-log-formatter.ts +0 -210
- package/src/processors/canonical-log-line-processor.test.ts +0 -523
- package/src/processors/canonical-log-line-processor.ts +0 -396
- package/src/processors.ts +0 -152
- package/src/rate-limiter.test.ts +0 -199
- package/src/rate-limiter.ts +0 -98
- package/src/redact-values.test.ts +0 -90
- package/src/redact-values.ts +0 -34
- package/src/register.ts +0 -37
- package/src/request-logger.test.ts +0 -545
- package/src/request-logger.ts +0 -342
- package/src/sampling.test.ts +0 -1060
- package/src/sampling.ts +0 -737
- package/src/security-schema.test.ts +0 -45
- package/src/security-schema.ts +0 -107
- package/src/semantic-conventions.ts +0 -15
- package/src/semantic-helpers.test.ts +0 -226
- package/src/semantic-helpers.ts +0 -438
- package/src/shutdown.test.ts +0 -364
- package/src/shutdown.ts +0 -246
- package/src/span-name-normalizer.test.ts +0 -377
- package/src/span-name-normalizer.ts +0 -213
- package/src/stable-hash.ts +0 -27
- package/src/structured-error.test.ts +0 -191
- package/src/structured-error.ts +0 -157
- package/src/stub.integration.test.ts +0 -361
- package/src/tail-sampling-processor.test.ts +0 -230
- package/src/tail-sampling-processor.ts +0 -55
- package/src/test-span-collector.test.ts +0 -234
- package/src/test-span-collector.ts +0 -150
- package/src/testing.ts +0 -705
- package/src/trace-context.test.ts +0 -73
- package/src/trace-context.ts +0 -567
- package/src/trace-helpers.new.test.ts +0 -278
- package/src/trace-helpers.test.ts +0 -290
- package/src/trace-helpers.ts +0 -710
- package/src/trace-hybrid.test.ts +0 -42
- package/src/trace-hybrid.ts +0 -37
- package/src/tracer-provider.test.ts +0 -183
- package/src/tracer-provider.ts +0 -266
- package/src/track.test.ts +0 -154
- package/src/track.ts +0 -216
- package/src/validate.test.ts +0 -287
- package/src/validate.ts +0 -307
- package/src/validation-attributes.ts +0 -43
- package/src/validation.test.ts +0 -330
- package/src/validation.ts +0 -246
- package/src/variable-name-inference.test.ts +0 -178
- package/src/variable-name-inference.ts +0 -242
- package/src/webhook.test.ts +0 -649
- package/src/webhook.ts +0 -637
- package/src/workflow-distributed.test.ts +0 -786
- package/src/workflow-distributed.ts +0 -916
- package/src/workflow.async-safety.integration.test.ts +0 -345
- package/src/workflow.test.ts +0 -647
- package/src/workflow.ts +0 -810
- package/src/yaml-config.test.ts +0 -373
- package/src/yaml-config.ts +0 -351
|
@@ -1,786 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
WorkflowBaggage,
|
|
4
|
-
traceDistributedWorkflow,
|
|
5
|
-
traceDistributedStep,
|
|
6
|
-
generateWorkflowId,
|
|
7
|
-
isInDistributedWorkflow,
|
|
8
|
-
getWorkflowProgress,
|
|
9
|
-
createWorkflowHeaders,
|
|
10
|
-
parseWorkflowFromBaggage,
|
|
11
|
-
type WorkflowBaggageValues,
|
|
12
|
-
type DistributedWorkflowConfig,
|
|
13
|
-
type DistributedWorkflowContext,
|
|
14
|
-
type DistributedStepContext,
|
|
15
|
-
} from './workflow-distributed';
|
|
16
|
-
|
|
17
|
-
// Mock the functional trace
|
|
18
|
-
vi.mock('./functional', () => ({
|
|
19
|
-
trace: vi.fn((options, factory) => {
|
|
20
|
-
return (...args: unknown[]) => {
|
|
21
|
-
const mockCtx = createMockTraceContext();
|
|
22
|
-
const fn = factory(mockCtx);
|
|
23
|
-
return fn(...args);
|
|
24
|
-
};
|
|
25
|
-
}),
|
|
26
|
-
}));
|
|
27
|
-
|
|
28
|
-
// Mock the business-baggage
|
|
29
|
-
const mockBaggageStore = new Map<string, unknown>();
|
|
30
|
-
vi.mock('./business-baggage', () => ({
|
|
31
|
-
createSafeBaggageSchema: vi.fn((_fields, _options) => ({
|
|
32
|
-
set: vi.fn((_ctx, values) => {
|
|
33
|
-
mockBaggageStore.set('workflow', values);
|
|
34
|
-
}),
|
|
35
|
-
get: vi.fn((_ctx) => mockBaggageStore.get('workflow') || {}),
|
|
36
|
-
clear: vi.fn(() => mockBaggageStore.delete('workflow')),
|
|
37
|
-
})),
|
|
38
|
-
}));
|
|
39
|
-
|
|
40
|
-
// Mock OpenTelemetry
|
|
41
|
-
vi.mock('@opentelemetry/api', () => ({
|
|
42
|
-
SpanKind: { INTERNAL: 0, SERVER: 1, CLIENT: 2, PRODUCER: 3, CONSUMER: 4 },
|
|
43
|
-
context: {
|
|
44
|
-
active: vi.fn(() => ({})),
|
|
45
|
-
},
|
|
46
|
-
propagation: {
|
|
47
|
-
inject: vi.fn((ctx, headers) => {
|
|
48
|
-
headers['traceparent'] =
|
|
49
|
-
'00-00000000000000000000000000000001-0000000000000002-01';
|
|
50
|
-
}),
|
|
51
|
-
},
|
|
52
|
-
}));
|
|
53
|
-
|
|
54
|
-
function createMockTraceContext() {
|
|
55
|
-
return {
|
|
56
|
-
setAttribute: vi.fn(),
|
|
57
|
-
setAttributes: vi.fn(),
|
|
58
|
-
addEvent: vi.fn(),
|
|
59
|
-
addLinks: vi.fn(),
|
|
60
|
-
recordException: vi.fn(),
|
|
61
|
-
setStatus: vi.fn(),
|
|
62
|
-
getSpan: vi.fn(),
|
|
63
|
-
getSpanContext: vi.fn(() => ({
|
|
64
|
-
traceId: '00000000000000000000000000000001',
|
|
65
|
-
spanId: '0000000000000002',
|
|
66
|
-
traceFlags: 1,
|
|
67
|
-
})),
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
describe('Workflow Distributed', () => {
|
|
72
|
-
beforeEach(() => {
|
|
73
|
-
vi.clearAllMocks();
|
|
74
|
-
mockBaggageStore.clear();
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
describe('WorkflowBaggage', () => {
|
|
78
|
-
it('should be defined', () => {
|
|
79
|
-
expect(WorkflowBaggage).toBeDefined();
|
|
80
|
-
expect(WorkflowBaggage.set).toBeInstanceOf(Function);
|
|
81
|
-
expect(WorkflowBaggage.get).toBeInstanceOf(Function);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('should set and get workflow baggage', () => {
|
|
85
|
-
const ctx = createMockTraceContext();
|
|
86
|
-
const values: WorkflowBaggageValues = {
|
|
87
|
-
workflowId: 'order-123',
|
|
88
|
-
workflowName: 'OrderFulfillment',
|
|
89
|
-
stepIndex: 0,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
WorkflowBaggage.set(ctx, values);
|
|
93
|
-
const retrieved = WorkflowBaggage.get(ctx);
|
|
94
|
-
|
|
95
|
-
expect(retrieved).toEqual(values);
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
describe('traceDistributedWorkflow', () => {
|
|
100
|
-
it('should create a traced workflow function', async () => {
|
|
101
|
-
const config: DistributedWorkflowConfig = {
|
|
102
|
-
name: 'OrderFulfillment',
|
|
103
|
-
workflowIdFrom: (order) => (order as { id: string }).id,
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
const workflow = traceDistributedWorkflow(config)(
|
|
107
|
-
(ctx) => async (_order: { id: string }) => {
|
|
108
|
-
return { processed: true, workflowId: ctx.workflowId };
|
|
109
|
-
},
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
const result = await workflow({ id: 'order-123' });
|
|
113
|
-
|
|
114
|
-
expect(result.processed).toBe(true);
|
|
115
|
-
expect(result.workflowId).toBe('order-123');
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('should provide workflow context with correct properties', async () => {
|
|
119
|
-
let capturedCtx: DistributedWorkflowContext | null = null;
|
|
120
|
-
|
|
121
|
-
const workflow = traceDistributedWorkflow({
|
|
122
|
-
name: 'TestWorkflow',
|
|
123
|
-
workflowIdFrom: () => 'wf-123',
|
|
124
|
-
version: '1.0.0',
|
|
125
|
-
})((ctx) => async () => {
|
|
126
|
-
capturedCtx = ctx;
|
|
127
|
-
return {};
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
await workflow();
|
|
131
|
-
|
|
132
|
-
expect(capturedCtx).not.toBeNull();
|
|
133
|
-
expect(capturedCtx?.workflowId).toBe('wf-123');
|
|
134
|
-
expect(capturedCtx?.workflowName).toBe('TestWorkflow');
|
|
135
|
-
expect(capturedCtx?.workflowVersion).toBe('1.0.0');
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it('should provide getWorkflowBaggage method', async () => {
|
|
139
|
-
let baggage: WorkflowBaggageValues | null = null;
|
|
140
|
-
|
|
141
|
-
const workflow = traceDistributedWorkflow({
|
|
142
|
-
name: 'TestWorkflow',
|
|
143
|
-
workflowIdFrom: () => 'wf-123',
|
|
144
|
-
version: '2.0.0',
|
|
145
|
-
priority: 'high',
|
|
146
|
-
})((ctx) => async () => {
|
|
147
|
-
baggage = ctx.getWorkflowBaggage();
|
|
148
|
-
return {};
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
await workflow();
|
|
152
|
-
|
|
153
|
-
expect(baggage).not.toBeNull();
|
|
154
|
-
expect(baggage?.workflowId).toBe('wf-123');
|
|
155
|
-
expect(baggage?.workflowName).toBe('TestWorkflow');
|
|
156
|
-
expect(baggage?.workflowVersion).toBe('2.0.0');
|
|
157
|
-
expect(baggage?.priority).toBe('high');
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it('should provide getWorkflowHeaders method', async () => {
|
|
161
|
-
let headers: Record<string, string> | null = null;
|
|
162
|
-
|
|
163
|
-
const workflow = traceDistributedWorkflow({
|
|
164
|
-
name: 'TestWorkflow',
|
|
165
|
-
workflowIdFrom: () => 'wf-123',
|
|
166
|
-
})((ctx) => async () => {
|
|
167
|
-
headers = ctx.getWorkflowHeaders();
|
|
168
|
-
return {};
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
await workflow();
|
|
172
|
-
|
|
173
|
-
expect(headers).not.toBeNull();
|
|
174
|
-
expect(headers?.traceparent).toBeDefined();
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
it('should support recordStepProgress', async () => {
|
|
178
|
-
const _mockCtx = createMockTraceContext();
|
|
179
|
-
|
|
180
|
-
const workflow = traceDistributedWorkflow({
|
|
181
|
-
name: 'TestWorkflow',
|
|
182
|
-
workflowIdFrom: () => 'wf-123',
|
|
183
|
-
})((ctx) => async () => {
|
|
184
|
-
ctx.recordStepProgress('Step1', 0);
|
|
185
|
-
ctx.recordStepProgress('Step2', 1);
|
|
186
|
-
return {};
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
await workflow();
|
|
190
|
-
|
|
191
|
-
// Verify step progress was recorded (via mock)
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('should call onStart callback', async () => {
|
|
195
|
-
const onStart = vi.fn();
|
|
196
|
-
|
|
197
|
-
const workflow = traceDistributedWorkflow({
|
|
198
|
-
name: 'TestWorkflow',
|
|
199
|
-
workflowIdFrom: () => 'wf-123',
|
|
200
|
-
onStart,
|
|
201
|
-
})((_ctx) => async () => ({}));
|
|
202
|
-
|
|
203
|
-
await workflow();
|
|
204
|
-
|
|
205
|
-
expect(onStart).toHaveBeenCalled();
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
it('should call onComplete callback', async () => {
|
|
209
|
-
const onComplete = vi.fn();
|
|
210
|
-
|
|
211
|
-
const workflow = traceDistributedWorkflow({
|
|
212
|
-
name: 'TestWorkflow',
|
|
213
|
-
workflowIdFrom: () => 'wf-123',
|
|
214
|
-
onComplete,
|
|
215
|
-
})((_ctx) => async () => ({ result: 'success' }));
|
|
216
|
-
|
|
217
|
-
await workflow();
|
|
218
|
-
|
|
219
|
-
expect(onComplete).toHaveBeenCalled();
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
it('should call onError callback on failure', async () => {
|
|
223
|
-
const onError = vi.fn();
|
|
224
|
-
const error = new Error('Workflow failed');
|
|
225
|
-
|
|
226
|
-
const workflow = traceDistributedWorkflow({
|
|
227
|
-
name: 'TestWorkflow',
|
|
228
|
-
workflowIdFrom: () => 'wf-123',
|
|
229
|
-
onError,
|
|
230
|
-
})((_ctx) => async () => {
|
|
231
|
-
throw error;
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
await expect(workflow()).rejects.toThrow('Workflow failed');
|
|
235
|
-
expect(onError).toHaveBeenCalled();
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
it('should support custom attributes', async () => {
|
|
239
|
-
const _mockCtx = createMockTraceContext();
|
|
240
|
-
|
|
241
|
-
const workflow = traceDistributedWorkflow({
|
|
242
|
-
name: 'TestWorkflow',
|
|
243
|
-
workflowIdFrom: () => 'wf-123',
|
|
244
|
-
attributes: {
|
|
245
|
-
'custom.attr': 'value',
|
|
246
|
-
'custom.number': 42,
|
|
247
|
-
},
|
|
248
|
-
})((_ctx) => async () => ({}));
|
|
249
|
-
|
|
250
|
-
await workflow();
|
|
251
|
-
|
|
252
|
-
// Custom attributes should be set via mock
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
describe('traceDistributedStep', () => {
|
|
257
|
-
it('should create a traced step function', async () => {
|
|
258
|
-
// Set up workflow baggage first
|
|
259
|
-
mockBaggageStore.set('workflow', {
|
|
260
|
-
workflowId: 'wf-123',
|
|
261
|
-
workflowName: 'TestWorkflow',
|
|
262
|
-
stepIndex: 0,
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
const step = traceDistributedStep({
|
|
266
|
-
name: 'ProcessOrder',
|
|
267
|
-
})((ctx) => async (_data: { orderId: string }) => {
|
|
268
|
-
return { processed: true, stepName: ctx.stepName };
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
const result = await step({ orderId: 'order-456' });
|
|
272
|
-
|
|
273
|
-
expect(result.processed).toBe(true);
|
|
274
|
-
expect(result.stepName).toBe('ProcessOrder');
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
it('should extract workflow context from baggage', async () => {
|
|
278
|
-
mockBaggageStore.set('workflow', {
|
|
279
|
-
workflowId: 'wf-123',
|
|
280
|
-
workflowName: 'OrderFulfillment',
|
|
281
|
-
stepIndex: 2,
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
let capturedCtx: DistributedStepContext | null = null;
|
|
285
|
-
|
|
286
|
-
const step = traceDistributedStep({
|
|
287
|
-
name: 'ChargePayment',
|
|
288
|
-
})((ctx) => async () => {
|
|
289
|
-
capturedCtx = ctx;
|
|
290
|
-
return {};
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
await step();
|
|
294
|
-
|
|
295
|
-
expect(capturedCtx).not.toBeNull();
|
|
296
|
-
expect(capturedCtx?.workflowId).toBe('wf-123');
|
|
297
|
-
expect(capturedCtx?.workflowName).toBe('OrderFulfillment');
|
|
298
|
-
expect(capturedCtx?.stepName).toBe('ChargePayment');
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it('should handle missing workflow context gracefully', async () => {
|
|
302
|
-
mockBaggageStore.clear();
|
|
303
|
-
|
|
304
|
-
let capturedCtx: DistributedStepContext | null = null;
|
|
305
|
-
|
|
306
|
-
const step = traceDistributedStep({
|
|
307
|
-
name: 'StandaloneStep',
|
|
308
|
-
})((ctx) => async () => {
|
|
309
|
-
capturedCtx = ctx;
|
|
310
|
-
return {};
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
await step();
|
|
314
|
-
|
|
315
|
-
expect(capturedCtx).not.toBeNull();
|
|
316
|
-
expect(capturedCtx?.workflowId).toBeNull();
|
|
317
|
-
expect(capturedCtx?.workflowName).toBeNull();
|
|
318
|
-
expect(capturedCtx?.stepName).toBe('StandaloneStep');
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
it('should support custom extractBaggage function', async () => {
|
|
322
|
-
const customExtractor = vi.fn((_args) => ({
|
|
323
|
-
workflowId: 'custom-wf',
|
|
324
|
-
workflowName: 'CustomWorkflow',
|
|
325
|
-
}));
|
|
326
|
-
|
|
327
|
-
const step = traceDistributedStep({
|
|
328
|
-
name: 'CustomStep',
|
|
329
|
-
extractBaggage: customExtractor,
|
|
330
|
-
})((ctx) => async () => {
|
|
331
|
-
return { id: ctx.workflowId };
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
await step();
|
|
335
|
-
|
|
336
|
-
expect(customExtractor).toHaveBeenCalled();
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
it('should disable baggage extraction when extractBaggage is false', async () => {
|
|
340
|
-
mockBaggageStore.set('workflow', {
|
|
341
|
-
workflowId: 'wf-123',
|
|
342
|
-
workflowName: 'TestWorkflow',
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
let capturedCtx: DistributedStepContext | null = null;
|
|
346
|
-
|
|
347
|
-
const step = traceDistributedStep({
|
|
348
|
-
name: 'IsolatedStep',
|
|
349
|
-
extractBaggage: false,
|
|
350
|
-
})((ctx) => async () => {
|
|
351
|
-
capturedCtx = ctx;
|
|
352
|
-
return {};
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
await step();
|
|
356
|
-
|
|
357
|
-
expect(capturedCtx?.workflowId).toBeNull();
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
it('should support idempotent flag', async () => {
|
|
361
|
-
const step = traceDistributedStep({
|
|
362
|
-
name: 'IdempotentStep',
|
|
363
|
-
idempotent: true,
|
|
364
|
-
})((_ctx) => async () => ({}));
|
|
365
|
-
|
|
366
|
-
await step();
|
|
367
|
-
|
|
368
|
-
// idempotent attribute should be set via mock
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
it('should support compensation flag', async () => {
|
|
372
|
-
const step = traceDistributedStep({
|
|
373
|
-
name: 'CompensationStep',
|
|
374
|
-
isCompensation: true,
|
|
375
|
-
})((ctx) => async () => {
|
|
376
|
-
return { isCompensation: ctx.isCompensation };
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
const result = await step();
|
|
380
|
-
|
|
381
|
-
expect(result.isCompensation).toBe(true);
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
it('should support requiresCompensation method', async () => {
|
|
385
|
-
mockBaggageStore.set('workflow', {
|
|
386
|
-
workflowId: 'wf-123',
|
|
387
|
-
workflowName: 'TestWorkflow',
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
const step = traceDistributedStep({
|
|
391
|
-
name: 'ReservationStep',
|
|
392
|
-
})((ctx) => async () => {
|
|
393
|
-
ctx.requiresCompensation({ reservationId: 'res-123' });
|
|
394
|
-
return {};
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
await step();
|
|
398
|
-
|
|
399
|
-
// requiresCompensation should have been called
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
it('should call onStart callback', async () => {
|
|
403
|
-
const onStart = vi.fn();
|
|
404
|
-
|
|
405
|
-
const step = traceDistributedStep({
|
|
406
|
-
name: 'TestStep',
|
|
407
|
-
onStart,
|
|
408
|
-
})((_ctx) => async () => ({}));
|
|
409
|
-
|
|
410
|
-
await step();
|
|
411
|
-
|
|
412
|
-
expect(onStart).toHaveBeenCalled();
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
it('should call onComplete callback', async () => {
|
|
416
|
-
const onComplete = vi.fn();
|
|
417
|
-
|
|
418
|
-
const step = traceDistributedStep({
|
|
419
|
-
name: 'TestStep',
|
|
420
|
-
onComplete,
|
|
421
|
-
})((_ctx) => async () => ({ result: 'done' }));
|
|
422
|
-
|
|
423
|
-
await step();
|
|
424
|
-
|
|
425
|
-
expect(onComplete).toHaveBeenCalled();
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
it('should call onError callback on failure', async () => {
|
|
429
|
-
const onError = vi.fn();
|
|
430
|
-
|
|
431
|
-
const step = traceDistributedStep({
|
|
432
|
-
name: 'FailingStep',
|
|
433
|
-
onError,
|
|
434
|
-
})((_ctx) => async () => {
|
|
435
|
-
throw new Error('Step failed');
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
await expect(step()).rejects.toThrow('Step failed');
|
|
439
|
-
expect(onError).toHaveBeenCalled();
|
|
440
|
-
});
|
|
441
|
-
});
|
|
442
|
-
|
|
443
|
-
describe('Utility Functions', () => {
|
|
444
|
-
describe('generateWorkflowId', () => {
|
|
445
|
-
it('should generate unique IDs', () => {
|
|
446
|
-
const id1 = generateWorkflowId();
|
|
447
|
-
const id2 = generateWorkflowId();
|
|
448
|
-
|
|
449
|
-
expect(id1).not.toBe(id2);
|
|
450
|
-
});
|
|
451
|
-
|
|
452
|
-
it('should include prefix when provided', () => {
|
|
453
|
-
const id = generateWorkflowId('order');
|
|
454
|
-
|
|
455
|
-
expect(id.startsWith('order-')).toBe(true);
|
|
456
|
-
});
|
|
457
|
-
|
|
458
|
-
it('should generate IDs without prefix', () => {
|
|
459
|
-
const id = generateWorkflowId();
|
|
460
|
-
|
|
461
|
-
expect(id).toBeDefined();
|
|
462
|
-
expect(id.length).toBeGreaterThan(10);
|
|
463
|
-
});
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
describe('isInDistributedWorkflow', () => {
|
|
467
|
-
it('should return true when workflow baggage is present', () => {
|
|
468
|
-
mockBaggageStore.set('workflow', {
|
|
469
|
-
workflowId: 'wf-123',
|
|
470
|
-
workflowName: 'TestWorkflow',
|
|
471
|
-
});
|
|
472
|
-
|
|
473
|
-
const ctx = createMockTraceContext();
|
|
474
|
-
const result = isInDistributedWorkflow(ctx);
|
|
475
|
-
|
|
476
|
-
expect(result).toBe(true);
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
it('should return false when workflow baggage is missing', () => {
|
|
480
|
-
mockBaggageStore.clear();
|
|
481
|
-
|
|
482
|
-
const ctx = createMockTraceContext();
|
|
483
|
-
const result = isInDistributedWorkflow(ctx);
|
|
484
|
-
|
|
485
|
-
expect(result).toBe(false);
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
it('should return false when only partial baggage is present', () => {
|
|
489
|
-
mockBaggageStore.set('workflow', {
|
|
490
|
-
workflowId: 'wf-123',
|
|
491
|
-
// Missing workflowName
|
|
492
|
-
});
|
|
493
|
-
|
|
494
|
-
const ctx = createMockTraceContext();
|
|
495
|
-
const result = isInDistributedWorkflow(ctx);
|
|
496
|
-
|
|
497
|
-
expect(result).toBe(false);
|
|
498
|
-
});
|
|
499
|
-
});
|
|
500
|
-
|
|
501
|
-
describe('getWorkflowProgress', () => {
|
|
502
|
-
it('should return progress information', () => {
|
|
503
|
-
mockBaggageStore.set('workflow', {
|
|
504
|
-
workflowId: 'wf-123',
|
|
505
|
-
workflowName: 'OrderFulfillment',
|
|
506
|
-
stepName: 'ChargePayment',
|
|
507
|
-
stepIndex: 2,
|
|
508
|
-
totalSteps: 5,
|
|
509
|
-
});
|
|
510
|
-
|
|
511
|
-
const ctx = createMockTraceContext();
|
|
512
|
-
const progress = getWorkflowProgress(ctx);
|
|
513
|
-
|
|
514
|
-
expect(progress).not.toBeNull();
|
|
515
|
-
expect(progress?.workflowId).toBe('wf-123');
|
|
516
|
-
expect(progress?.workflowName).toBe('OrderFulfillment');
|
|
517
|
-
expect(progress?.currentStep).toBe('ChargePayment');
|
|
518
|
-
expect(progress?.currentStepIndex).toBe(2);
|
|
519
|
-
expect(progress?.totalSteps).toBe(5);
|
|
520
|
-
expect(progress?.percentComplete).toBe(60); // (2+1)/5 * 100
|
|
521
|
-
});
|
|
522
|
-
|
|
523
|
-
it('should return null when not in workflow', () => {
|
|
524
|
-
mockBaggageStore.clear();
|
|
525
|
-
|
|
526
|
-
const ctx = createMockTraceContext();
|
|
527
|
-
const progress = getWorkflowProgress(ctx);
|
|
528
|
-
|
|
529
|
-
expect(progress).toBeNull();
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
it('should return null percent when totalSteps is unknown', () => {
|
|
533
|
-
mockBaggageStore.set('workflow', {
|
|
534
|
-
workflowId: 'wf-123',
|
|
535
|
-
workflowName: 'TestWorkflow',
|
|
536
|
-
stepIndex: 1,
|
|
537
|
-
});
|
|
538
|
-
|
|
539
|
-
const ctx = createMockTraceContext();
|
|
540
|
-
const progress = getWorkflowProgress(ctx);
|
|
541
|
-
|
|
542
|
-
expect(progress?.percentComplete).toBeNull();
|
|
543
|
-
});
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
describe('createWorkflowHeaders', () => {
|
|
547
|
-
it('should create baggage header with workflow values', () => {
|
|
548
|
-
const headers = createWorkflowHeaders({
|
|
549
|
-
workflowId: 'wf-123',
|
|
550
|
-
workflowName: 'OrderFulfillment',
|
|
551
|
-
stepIndex: 2,
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
expect(headers.baggage).toBeDefined();
|
|
555
|
-
expect(headers.baggage).toContain('workflow.workflowId=wf-123');
|
|
556
|
-
expect(headers.baggage).toContain(
|
|
557
|
-
'workflow.workflowName=OrderFulfillment',
|
|
558
|
-
);
|
|
559
|
-
expect(headers.baggage).toContain('workflow.stepIndex=2');
|
|
560
|
-
});
|
|
561
|
-
|
|
562
|
-
it('should URL-encode values', () => {
|
|
563
|
-
const headers = createWorkflowHeaders({
|
|
564
|
-
workflowId: 'wf-123',
|
|
565
|
-
workflowName: 'Order Fulfillment',
|
|
566
|
-
});
|
|
567
|
-
|
|
568
|
-
expect(headers.baggage).toContain('Order%20Fulfillment');
|
|
569
|
-
});
|
|
570
|
-
|
|
571
|
-
it('should return empty object when no values provided', () => {
|
|
572
|
-
const headers = createWorkflowHeaders({});
|
|
573
|
-
|
|
574
|
-
expect(headers.baggage).toBeUndefined();
|
|
575
|
-
});
|
|
576
|
-
|
|
577
|
-
it('should include all workflow fields', () => {
|
|
578
|
-
const headers = createWorkflowHeaders({
|
|
579
|
-
workflowId: 'wf-123',
|
|
580
|
-
workflowName: 'Test',
|
|
581
|
-
workflowVersion: '1.0.0',
|
|
582
|
-
stepName: 'Step1',
|
|
583
|
-
stepIndex: 0,
|
|
584
|
-
totalSteps: 5,
|
|
585
|
-
priority: 'high',
|
|
586
|
-
correlationId: 'corr-456',
|
|
587
|
-
});
|
|
588
|
-
|
|
589
|
-
expect(headers.baggage).toContain('workflow.workflowVersion=1.0.0');
|
|
590
|
-
expect(headers.baggage).toContain('workflow.stepName=Step1');
|
|
591
|
-
expect(headers.baggage).toContain('workflow.totalSteps=5');
|
|
592
|
-
expect(headers.baggage).toContain('workflow.priority=high');
|
|
593
|
-
expect(headers.baggage).toContain('workflow.correlationId=corr-456');
|
|
594
|
-
});
|
|
595
|
-
});
|
|
596
|
-
|
|
597
|
-
describe('parseWorkflowFromBaggage', () => {
|
|
598
|
-
it('should parse workflow values from baggage header', () => {
|
|
599
|
-
const baggage =
|
|
600
|
-
'workflow.workflowId=wf-123,workflow.workflowName=OrderFulfillment,workflow.stepIndex=2';
|
|
601
|
-
|
|
602
|
-
const values = parseWorkflowFromBaggage(baggage);
|
|
603
|
-
|
|
604
|
-
expect(values).not.toBeNull();
|
|
605
|
-
expect(values?.workflowId).toBe('wf-123');
|
|
606
|
-
expect(values?.workflowName).toBe('OrderFulfillment');
|
|
607
|
-
expect(values?.stepIndex).toBe(2);
|
|
608
|
-
});
|
|
609
|
-
|
|
610
|
-
it('should URL-decode values', () => {
|
|
611
|
-
const baggage = 'workflow.workflowName=Order%20Fulfillment';
|
|
612
|
-
|
|
613
|
-
const values = parseWorkflowFromBaggage(baggage);
|
|
614
|
-
|
|
615
|
-
expect(values?.workflowName).toBe('Order Fulfillment');
|
|
616
|
-
});
|
|
617
|
-
|
|
618
|
-
it('should return null for empty baggage', () => {
|
|
619
|
-
const values = parseWorkflowFromBaggage('');
|
|
620
|
-
|
|
621
|
-
expect(values).toBeNull();
|
|
622
|
-
});
|
|
623
|
-
|
|
624
|
-
it('should handle mixed baggage with non-workflow entries', () => {
|
|
625
|
-
const baggage =
|
|
626
|
-
'other.key=value,workflow.workflowId=wf-123,another.key=xyz';
|
|
627
|
-
|
|
628
|
-
const values = parseWorkflowFromBaggage(baggage);
|
|
629
|
-
|
|
630
|
-
expect(values?.workflowId).toBe('wf-123');
|
|
631
|
-
expect((values as Record<string, unknown>)['other']).toBeUndefined();
|
|
632
|
-
});
|
|
633
|
-
|
|
634
|
-
it('should parse all workflow fields', () => {
|
|
635
|
-
const baggage = [
|
|
636
|
-
'workflow.workflowId=wf-123',
|
|
637
|
-
'workflow.workflowName=Test',
|
|
638
|
-
'workflow.workflowVersion=1.0.0',
|
|
639
|
-
'workflow.stepName=Step1',
|
|
640
|
-
'workflow.stepIndex=1',
|
|
641
|
-
'workflow.totalSteps=5',
|
|
642
|
-
'workflow.priority=high',
|
|
643
|
-
'workflow.correlationId=corr-456',
|
|
644
|
-
'workflow.parentWorkflowId=parent-123',
|
|
645
|
-
'workflow.initiatedBy=user-789',
|
|
646
|
-
'workflow.startedAt=2024-01-15T10:30:00Z',
|
|
647
|
-
].join(',');
|
|
648
|
-
|
|
649
|
-
const values = parseWorkflowFromBaggage(baggage);
|
|
650
|
-
|
|
651
|
-
expect(values?.workflowId).toBe('wf-123');
|
|
652
|
-
expect(values?.workflowName).toBe('Test');
|
|
653
|
-
expect(values?.workflowVersion).toBe('1.0.0');
|
|
654
|
-
expect(values?.stepName).toBe('Step1');
|
|
655
|
-
expect(values?.stepIndex).toBe(1);
|
|
656
|
-
expect(values?.totalSteps).toBe(5);
|
|
657
|
-
expect(values?.priority).toBe('high');
|
|
658
|
-
expect(values?.correlationId).toBe('corr-456');
|
|
659
|
-
expect(values?.parentWorkflowId).toBe('parent-123');
|
|
660
|
-
expect(values?.initiatedBy).toBe('user-789');
|
|
661
|
-
expect(values?.startedAt).toBe('2024-01-15T10:30:00Z');
|
|
662
|
-
});
|
|
663
|
-
});
|
|
664
|
-
});
|
|
665
|
-
|
|
666
|
-
describe('Integration Scenarios', () => {
|
|
667
|
-
it('should trace cross-service order fulfillment', async () => {
|
|
668
|
-
// Service A: Create order workflow
|
|
669
|
-
const createOrder = traceDistributedWorkflow({
|
|
670
|
-
name: 'OrderFulfillment',
|
|
671
|
-
workflowIdFrom: (order) => (order as { orderId: string }).orderId,
|
|
672
|
-
version: '1.0.0',
|
|
673
|
-
totalSteps: 4,
|
|
674
|
-
})((ctx) => async (_order: { orderId: string; items: string[] }) => {
|
|
675
|
-
ctx.recordStepProgress('ValidateOrder', 0);
|
|
676
|
-
|
|
677
|
-
// Simulate publishing to inventory service
|
|
678
|
-
const headers = ctx.getWorkflowHeaders();
|
|
679
|
-
|
|
680
|
-
return {
|
|
681
|
-
workflowId: ctx.workflowId,
|
|
682
|
-
status: 'started',
|
|
683
|
-
headers,
|
|
684
|
-
};
|
|
685
|
-
});
|
|
686
|
-
|
|
687
|
-
const orderResult = await createOrder({
|
|
688
|
-
orderId: 'ord-123',
|
|
689
|
-
items: ['item-1'],
|
|
690
|
-
});
|
|
691
|
-
|
|
692
|
-
expect(orderResult.workflowId).toBe('ord-123');
|
|
693
|
-
expect(orderResult.status).toBe('started');
|
|
694
|
-
|
|
695
|
-
// Service B: Process inventory step
|
|
696
|
-
mockBaggageStore.set('workflow', {
|
|
697
|
-
workflowId: 'ord-123',
|
|
698
|
-
workflowName: 'OrderFulfillment',
|
|
699
|
-
stepIndex: 0,
|
|
700
|
-
});
|
|
701
|
-
|
|
702
|
-
const processInventory = traceDistributedStep({
|
|
703
|
-
name: 'ReserveInventory',
|
|
704
|
-
idempotent: true,
|
|
705
|
-
})((ctx) => async () => {
|
|
706
|
-
return {
|
|
707
|
-
workflowId: ctx.workflowId,
|
|
708
|
-
stepName: ctx.stepName,
|
|
709
|
-
};
|
|
710
|
-
});
|
|
711
|
-
|
|
712
|
-
const inventoryResult = await processInventory();
|
|
713
|
-
|
|
714
|
-
expect(inventoryResult.workflowId).toBe('ord-123');
|
|
715
|
-
expect(inventoryResult.stepName).toBe('ReserveInventory');
|
|
716
|
-
});
|
|
717
|
-
|
|
718
|
-
it('should support sub-workflows', async () => {
|
|
719
|
-
// Main workflow
|
|
720
|
-
const mainWorkflow = traceDistributedWorkflow({
|
|
721
|
-
name: 'MainWorkflow',
|
|
722
|
-
workflowIdFrom: () => 'main-wf-123',
|
|
723
|
-
})((ctx) => async () => {
|
|
724
|
-
return { id: ctx.workflowId, name: ctx.workflowName };
|
|
725
|
-
});
|
|
726
|
-
|
|
727
|
-
const mainResult = await mainWorkflow();
|
|
728
|
-
|
|
729
|
-
// Sub-workflow
|
|
730
|
-
const subWorkflow = traceDistributedWorkflow({
|
|
731
|
-
name: 'SubWorkflow',
|
|
732
|
-
workflowIdFrom: () => 'sub-wf-456',
|
|
733
|
-
parentWorkflowId: mainResult.id,
|
|
734
|
-
})((ctx) => async () => {
|
|
735
|
-
const baggage = ctx.getWorkflowBaggage();
|
|
736
|
-
return {
|
|
737
|
-
id: ctx.workflowId,
|
|
738
|
-
parentId: baggage.parentWorkflowId,
|
|
739
|
-
};
|
|
740
|
-
});
|
|
741
|
-
|
|
742
|
-
const subResult = await subWorkflow();
|
|
743
|
-
|
|
744
|
-
expect(subResult.id).toBe('sub-wf-456');
|
|
745
|
-
expect(subResult.parentId).toBe('main-wf-123');
|
|
746
|
-
});
|
|
747
|
-
|
|
748
|
-
it('should track workflow progress across steps', async () => {
|
|
749
|
-
mockBaggageStore.set('workflow', {
|
|
750
|
-
workflowId: 'wf-123',
|
|
751
|
-
workflowName: 'MultiStepWorkflow',
|
|
752
|
-
stepIndex: 0,
|
|
753
|
-
totalSteps: 3,
|
|
754
|
-
});
|
|
755
|
-
|
|
756
|
-
const steps = ['Step1', 'Step2', 'Step3'];
|
|
757
|
-
const results: Array<{ step: string; index: number | null }> = [];
|
|
758
|
-
|
|
759
|
-
for (const [i, step_] of steps.entries()) {
|
|
760
|
-
const step = traceDistributedStep({
|
|
761
|
-
name: step_,
|
|
762
|
-
stepIndex: i,
|
|
763
|
-
})((ctx) => async () => {
|
|
764
|
-
return { step: ctx.stepName, index: ctx.stepIndex };
|
|
765
|
-
});
|
|
766
|
-
|
|
767
|
-
const result = await step();
|
|
768
|
-
results.push(result);
|
|
769
|
-
|
|
770
|
-
// Update baggage for next step
|
|
771
|
-
const currentBaggage = mockBaggageStore.get(
|
|
772
|
-
'workflow',
|
|
773
|
-
) as WorkflowBaggageValues;
|
|
774
|
-
mockBaggageStore.set('workflow', {
|
|
775
|
-
...currentBaggage,
|
|
776
|
-
stepIndex: i + 1,
|
|
777
|
-
stepName: step_,
|
|
778
|
-
});
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
expect(results[0]).toEqual({ step: 'Step1', index: 0 });
|
|
782
|
-
expect(results[1]).toEqual({ step: 'Step2', index: 1 });
|
|
783
|
-
expect(results[2]).toEqual({ step: 'Step3', index: 2 });
|
|
784
|
-
});
|
|
785
|
-
});
|
|
786
|
-
});
|