|
1 | 1 | /* eslint-disable @typescript-eslint/unbound-method */
|
2 | 2 | import type { WorkflowEvent, WorkflowStep, WorkflowStepConfig } from 'cloudflare:workers';
|
3 | 3 | import { beforeEach, describe, expect, test, vi } from 'vitest';
|
4 |
| -import { instrumentWorkflowWithSentry } from '../src/workflows'; |
| 4 | +import { deterministicTraceIdFromInstanceId, instrumentWorkflowWithSentry } from '../src/workflows'; |
| 5 | + |
| 6 | +const NODE_MAJOR_VERSION = parseInt(process.versions.node.split('.')[0]!); |
5 | 7 |
|
6 | 8 | const mockStep: WorkflowStep = {
|
7 | 9 | do: vi
|
@@ -63,11 +65,18 @@ const INSTANCE_ID = 'ae0ee067-61b3-4852-9219-5d62282270f0';
|
63 | 65 | const SAMPLE_RAND = '0.44116884107728693';
|
64 | 66 | const TRACE_ID = INSTANCE_ID.replace(/-/g, '');
|
65 | 67 |
|
66 |
| -describe('workflows', () => { |
| 68 | +describe.skipIf(NODE_MAJOR_VERSION < 20)('workflows', () => { |
67 | 69 | beforeEach(() => {
|
68 | 70 | vi.clearAllMocks();
|
69 | 71 | });
|
70 | 72 |
|
| 73 | + test('hashStringToUuid hashes a string to a UUID for Sentry trace ID', async () => { |
| 74 | + const UUID_WITHOUT_HYPHENS_REGEX = /^[0-9a-f]{32}$/i; |
| 75 | + expect(await deterministicTraceIdFromInstanceId('s')).toMatch(UUID_WITHOUT_HYPHENS_REGEX); |
| 76 | + expect(await deterministicTraceIdFromInstanceId('test-string')).toMatch(UUID_WITHOUT_HYPHENS_REGEX); |
| 77 | + expect(await deterministicTraceIdFromInstanceId(INSTANCE_ID)).toMatch(UUID_WITHOUT_HYPHENS_REGEX); |
| 78 | + }); |
| 79 | + |
71 | 80 | test('Calls expected functions', async () => {
|
72 | 81 | class BasicTestWorkflow {
|
73 | 82 | constructor(_ctx: ExecutionContext, _env: unknown) {}
|
@@ -133,6 +142,71 @@ describe('workflows', () => {
|
133 | 142 | ]);
|
134 | 143 | });
|
135 | 144 |
|
| 145 | + test('Calls expected functions with non-uuid instance id', async () => { |
| 146 | + class BasicTestWorkflow { |
| 147 | + constructor(_ctx: ExecutionContext, _env: unknown) {} |
| 148 | + |
| 149 | + async run(_event: Readonly<WorkflowEvent<Params>>, step: WorkflowStep): Promise<void> { |
| 150 | + // eslint-disable-next-line @typescript-eslint/no-unused-vars |
| 151 | + const files = await step.do('first step', async () => { |
| 152 | + return { files: ['doc_7392_rev3.pdf', 'report_x29_final.pdf'] }; |
| 153 | + }); |
| 154 | + } |
| 155 | + } |
| 156 | + |
| 157 | + const TestWorkflowInstrumented = instrumentWorkflowWithSentry(getSentryOptions, BasicTestWorkflow as any); |
| 158 | + const workflow = new TestWorkflowInstrumented(mockContext, {}) as BasicTestWorkflow; |
| 159 | + const event = { payload: {}, timestamp: new Date(), instanceId: 'ae0ee067' }; |
| 160 | + await workflow.run(event, mockStep); |
| 161 | + |
| 162 | + expect(mockStep.do).toHaveBeenCalledTimes(1); |
| 163 | + expect(mockStep.do).toHaveBeenCalledWith('first step', expect.any(Function)); |
| 164 | + expect(mockContext.waitUntil).toHaveBeenCalledTimes(1); |
| 165 | + expect(mockContext.waitUntil).toHaveBeenCalledWith(expect.any(Promise)); |
| 166 | + expect(mockTransport.send).toHaveBeenCalledTimes(1); |
| 167 | + expect(mockTransport.send).toHaveBeenCalledWith([ |
| 168 | + expect.objectContaining({ |
| 169 | + trace: expect.objectContaining({ |
| 170 | + transaction: 'first step', |
| 171 | + trace_id: '0d2b6d1743ce6d53af4f5ee416ad5d1b', |
| 172 | + sample_rand: '0.3636987869077592', |
| 173 | + }), |
| 174 | + }), |
| 175 | + [ |
| 176 | + [ |
| 177 | + { |
| 178 | + type: 'transaction', |
| 179 | + }, |
| 180 | + expect.objectContaining({ |
| 181 | + event_id: expect.any(String), |
| 182 | + contexts: { |
| 183 | + trace: { |
| 184 | + parent_span_id: undefined, |
| 185 | + span_id: expect.any(String), |
| 186 | + trace_id: '0d2b6d1743ce6d53af4f5ee416ad5d1b', |
| 187 | + data: { |
| 188 | + 'sentry.origin': 'auto.faas.cloudflare.workflow', |
| 189 | + 'sentry.op': 'function.step.do', |
| 190 | + 'sentry.source': 'task', |
| 191 | + 'sentry.sample_rate': 1, |
| 192 | + }, |
| 193 | + op: 'function.step.do', |
| 194 | + status: 'ok', |
| 195 | + origin: 'auto.faas.cloudflare.workflow', |
| 196 | + }, |
| 197 | + cloud_resource: { 'cloud.provider': 'cloudflare' }, |
| 198 | + runtime: { name: 'cloudflare' }, |
| 199 | + }, |
| 200 | + type: 'transaction', |
| 201 | + transaction_info: { source: 'task' }, |
| 202 | + start_timestamp: expect.any(Number), |
| 203 | + timestamp: expect.any(Number), |
| 204 | + }), |
| 205 | + ], |
| 206 | + ], |
| 207 | + ]); |
| 208 | + }); |
| 209 | + |
136 | 210 | class ErrorTestWorkflow {
|
137 | 211 | count = 0;
|
138 | 212 | constructor(_ctx: ExecutionContext, _env: unknown) {}
|
|
0 commit comments