@devrev/ts-adaas 1.19.4 → 1.19.5

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 (45) hide show
  1. package/dist/attachments-streaming/attachments-streaming-pool.test.js +3 -6
  2. package/dist/common/event-type-translation.test.d.ts +2 -0
  3. package/dist/common/event-type-translation.test.d.ts.map +1 -0
  4. package/dist/common/event-type-translation.test.js +175 -0
  5. package/dist/common/time-value-resolver.test.js +0 -1
  6. package/dist/multithreading/create-worker.test.js +34 -16
  7. package/dist/multithreading/process-task.test.d.ts +2 -0
  8. package/dist/multithreading/process-task.test.d.ts.map +1 -0
  9. package/dist/multithreading/process-task.test.js +166 -0
  10. package/dist/multithreading/spawn/spawn.test.d.ts +2 -0
  11. package/dist/multithreading/spawn/spawn.test.d.ts.map +1 -0
  12. package/dist/multithreading/spawn/spawn.test.js +223 -0
  13. package/dist/multithreading/worker-adapter/worker-adapter.emit.test.d.ts +2 -0
  14. package/dist/multithreading/worker-adapter/worker-adapter.emit.test.d.ts.map +1 -0
  15. package/dist/multithreading/worker-adapter/worker-adapter.emit.test.js +415 -0
  16. package/dist/multithreading/worker-adapter/worker-adapter.extraction.test.d.ts +2 -0
  17. package/dist/multithreading/worker-adapter/worker-adapter.extraction.test.d.ts.map +1 -0
  18. package/dist/multithreading/worker-adapter/worker-adapter.extraction.test.js +801 -0
  19. package/dist/multithreading/worker-adapter/worker-adapter.loading.test.d.ts +2 -0
  20. package/dist/multithreading/worker-adapter/worker-adapter.loading.test.d.ts.map +1 -0
  21. package/dist/multithreading/worker-adapter/worker-adapter.loading.test.js +598 -0
  22. package/dist/multithreading/worker-adapter/worker-adapter.serialization.test.d.ts +2 -0
  23. package/dist/multithreading/worker-adapter/worker-adapter.serialization.test.d.ts.map +1 -0
  24. package/dist/multithreading/worker-adapter/worker-adapter.serialization.test.js +71 -0
  25. package/dist/repo/repo.test.js +41 -0
  26. package/dist/state/state.extract-window.test.d.ts +2 -0
  27. package/dist/state/state.extract-window.test.d.ts.map +1 -0
  28. package/dist/state/state.extract-window.test.js +163 -0
  29. package/dist/state/state.pending-boundaries.test.d.ts +2 -0
  30. package/dist/state/state.pending-boundaries.test.d.ts.map +1 -0
  31. package/dist/state/state.pending-boundaries.test.js +189 -0
  32. package/dist/state/state.post-state.test.d.ts +2 -0
  33. package/dist/state/state.post-state.test.d.ts.map +1 -0
  34. package/dist/state/state.post-state.test.js +77 -0
  35. package/dist/state/state.test.js +23 -506
  36. package/dist/state/state.time-value-resolution.test.d.ts +2 -0
  37. package/dist/state/state.time-value-resolution.test.d.ts.map +1 -0
  38. package/dist/state/state.time-value-resolution.test.js +175 -0
  39. package/dist/types/extraction.test.js +57 -21
  40. package/dist/uploader/uploader.helpers.test.js +0 -11
  41. package/dist/uploader/uploader.test.js +0 -9
  42. package/package.json +7 -6
  43. package/dist/multithreading/worker-adapter/worker-adapter.test.d.ts +0 -2
  44. package/dist/multithreading/worker-adapter/worker-adapter.test.d.ts.map +0 -1
  45. package/dist/multithreading/worker-adapter/worker-adapter.test.js +0 -1243
@@ -44,10 +44,6 @@ describe(attachments_streaming_pool_1.AttachmentsStreamingPool.name, () => {
44
44
  parent_id: 'parent-3',
45
45
  },
46
46
  ];
47
- // Mock console methods
48
- jest.spyOn(console, 'log').mockImplementation();
49
- jest.spyOn(console, 'error').mockImplementation();
50
- jest.spyOn(console, 'warn').mockImplementation();
51
47
  });
52
48
  afterEach(() => {
53
49
  jest.clearAllMocks();
@@ -60,7 +56,6 @@ describe(attachments_streaming_pool_1.AttachmentsStreamingPool.name, () => {
60
56
  attachments: mockAttachments,
61
57
  stream: mockStream,
62
58
  });
63
- expect(pool).toBeDefined();
64
59
  expect(pool['adapter']).toBe(mockAdapter);
65
60
  expect(pool['attachments']).toEqual(mockAttachments);
66
61
  expect(pool['batchSize']).toBe(10);
@@ -227,6 +222,7 @@ describe(attachments_streaming_pool_1.AttachmentsStreamingPool.name, () => {
227
222
  ]);
228
223
  });
229
224
  it('should handle processing errors gracefully', async () => {
225
+ const warnSpy = jest.spyOn(console, 'warn').mockImplementation();
230
226
  const error = new Error('Processing failed');
231
227
  mockAdapter.processAttachment
232
228
  .mockResolvedValueOnce({}) // First attachment succeeds
@@ -238,7 +234,7 @@ describe(attachments_streaming_pool_1.AttachmentsStreamingPool.name, () => {
238
234
  stream: mockStream,
239
235
  });
240
236
  await pool.streamAll();
241
- expect(console.warn).toHaveBeenCalledWith('Skipping attachment with ID attachment-2 with extension jpg due to error in processAttachment function', error);
237
+ expect(warnSpy).toHaveBeenCalledWith('Skipping attachment with ID attachment-2 with extension jpg due to error in processAttachment function', error);
242
238
  expect(mockAdapter.state.toDevRev.attachmentsMetadata
243
239
  .lastProcessedAttachmentsIdsList).toEqual([
244
240
  {
@@ -490,6 +486,7 @@ describe(attachments_streaming_pool_1.AttachmentsStreamingPool.name, () => {
490
486
  const mockStreamFn = jest
491
487
  .fn()
492
488
  .mockImplementation(async () => {
489
+ await Promise.resolve();
493
490
  userCallbackExecuted = true;
494
491
  // Record that the callback executed
495
492
  return Promise.resolve({
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=event-type-translation.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-type-translation.test.d.ts","sourceRoot":"","sources":["../../src/common/event-type-translation.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const extraction_1 = require("../types/extraction");
4
+ const loading_1 = require("../types/loading");
5
+ const event_type_translation_1 = require("./event-type-translation");
6
+ describe(event_type_translation_1.translateIncomingEventType.name, () => {
7
+ it.each([
8
+ [
9
+ extraction_1.EventType.ExtractionExternalSyncUnitsStart,
10
+ extraction_1.EventType.StartExtractingExternalSyncUnits,
11
+ ],
12
+ [extraction_1.EventType.ExtractionMetadataStart, extraction_1.EventType.StartExtractingMetadata],
13
+ [extraction_1.EventType.ExtractionDataStart, extraction_1.EventType.StartExtractingData],
14
+ [extraction_1.EventType.ExtractionDataContinue, extraction_1.EventType.ContinueExtractingData],
15
+ [extraction_1.EventType.ExtractionDataDelete, extraction_1.EventType.StartDeletingExtractorState],
16
+ [
17
+ extraction_1.EventType.ExtractionAttachmentsStart,
18
+ extraction_1.EventType.StartExtractingAttachments,
19
+ ],
20
+ [
21
+ extraction_1.EventType.ExtractionAttachmentsContinue,
22
+ extraction_1.EventType.ContinueExtractingAttachments,
23
+ ],
24
+ [
25
+ extraction_1.EventType.ExtractionAttachmentsDelete,
26
+ extraction_1.EventType.StartDeletingExtractorAttachmentsState,
27
+ ],
28
+ ])('maps legacy extraction event %s to %s', (legacy, modern) => {
29
+ expect((0, event_type_translation_1.translateIncomingEventType)(legacy)).toBe(modern);
30
+ });
31
+ it.each([
32
+ [extraction_1.EventType.StartExtractingExternalSyncUnits],
33
+ [extraction_1.EventType.StartExtractingMetadata],
34
+ [extraction_1.EventType.StartExtractingData],
35
+ [extraction_1.EventType.ContinueExtractingData],
36
+ [extraction_1.EventType.StartDeletingExtractorState],
37
+ [extraction_1.EventType.StartExtractingAttachments],
38
+ [extraction_1.EventType.ContinueExtractingAttachments],
39
+ [extraction_1.EventType.StartDeletingExtractorAttachmentsState],
40
+ [extraction_1.EventType.StartLoadingData],
41
+ [extraction_1.EventType.ContinueLoadingData],
42
+ [extraction_1.EventType.StartLoadingAttachments],
43
+ [extraction_1.EventType.ContinueLoadingAttachments],
44
+ [extraction_1.EventType.StartDeletingLoaderState],
45
+ [extraction_1.EventType.StartDeletingLoaderAttachmentState],
46
+ [extraction_1.EventType.UnknownEventType],
47
+ ])('is a no-op for already-modern event type %s', (eventType) => {
48
+ expect((0, event_type_translation_1.translateIncomingEventType)(eventType)).toBe(eventType);
49
+ });
50
+ it('returns the input verbatim for an unrecognised event type', () => {
51
+ const result = (0, event_type_translation_1.translateIncomingEventType)('NONSENSE_EVENT');
52
+ expect(result).toBe('NONSENSE_EVENT');
53
+ });
54
+ });
55
+ describe(event_type_translation_1.translateExtractorEventType.name, () => {
56
+ it.each([
57
+ [
58
+ extraction_1.ExtractorEventType.ExtractionExternalSyncUnitsDone,
59
+ extraction_1.ExtractorEventType.ExternalSyncUnitExtractionDone,
60
+ ],
61
+ [
62
+ extraction_1.ExtractorEventType.ExtractionExternalSyncUnitsError,
63
+ extraction_1.ExtractorEventType.ExternalSyncUnitExtractionError,
64
+ ],
65
+ [
66
+ extraction_1.ExtractorEventType.ExtractionMetadataDone,
67
+ extraction_1.ExtractorEventType.MetadataExtractionDone,
68
+ ],
69
+ [
70
+ extraction_1.ExtractorEventType.ExtractionMetadataError,
71
+ extraction_1.ExtractorEventType.MetadataExtractionError,
72
+ ],
73
+ [
74
+ extraction_1.ExtractorEventType.ExtractionDataProgress,
75
+ extraction_1.ExtractorEventType.DataExtractionProgress,
76
+ ],
77
+ [
78
+ extraction_1.ExtractorEventType.ExtractionDataDelay,
79
+ extraction_1.ExtractorEventType.DataExtractionDelayed,
80
+ ],
81
+ [
82
+ extraction_1.ExtractorEventType.ExtractionDataDone,
83
+ extraction_1.ExtractorEventType.DataExtractionDone,
84
+ ],
85
+ [
86
+ extraction_1.ExtractorEventType.ExtractionDataError,
87
+ extraction_1.ExtractorEventType.DataExtractionError,
88
+ ],
89
+ [
90
+ extraction_1.ExtractorEventType.ExtractionDataDeleteDone,
91
+ extraction_1.ExtractorEventType.ExtractorStateDeletionDone,
92
+ ],
93
+ [
94
+ extraction_1.ExtractorEventType.ExtractionDataDeleteError,
95
+ extraction_1.ExtractorEventType.ExtractorStateDeletionError,
96
+ ],
97
+ [
98
+ extraction_1.ExtractorEventType.ExtractionAttachmentsProgress,
99
+ extraction_1.ExtractorEventType.AttachmentExtractionProgress,
100
+ ],
101
+ [
102
+ extraction_1.ExtractorEventType.ExtractionAttachmentsDelay,
103
+ extraction_1.ExtractorEventType.AttachmentExtractionDelayed,
104
+ ],
105
+ [
106
+ extraction_1.ExtractorEventType.ExtractionAttachmentsDone,
107
+ extraction_1.ExtractorEventType.AttachmentExtractionDone,
108
+ ],
109
+ [
110
+ extraction_1.ExtractorEventType.ExtractionAttachmentsError,
111
+ extraction_1.ExtractorEventType.AttachmentExtractionError,
112
+ ],
113
+ [
114
+ extraction_1.ExtractorEventType.ExtractionAttachmentsDeleteDone,
115
+ extraction_1.ExtractorEventType.ExtractorAttachmentsStateDeletionDone,
116
+ ],
117
+ [
118
+ extraction_1.ExtractorEventType.ExtractionAttachmentsDeleteError,
119
+ extraction_1.ExtractorEventType.ExtractorAttachmentsStateDeletionError,
120
+ ],
121
+ ])('maps legacy extractor event %s to %s', (legacy, modern) => {
122
+ expect((0, event_type_translation_1.translateExtractorEventType)(legacy)).toBe(modern);
123
+ });
124
+ it.each([
125
+ [extraction_1.ExtractorEventType.DataExtractionDone],
126
+ [extraction_1.ExtractorEventType.DataExtractionProgress],
127
+ [extraction_1.ExtractorEventType.AttachmentExtractionDone],
128
+ [extraction_1.ExtractorEventType.MetadataExtractionDone],
129
+ [extraction_1.ExtractorEventType.UnknownEventType],
130
+ ])('is a no-op for already-modern extractor event %s', (eventType) => {
131
+ expect((0, event_type_translation_1.translateExtractorEventType)(eventType)).toBe(eventType);
132
+ });
133
+ });
134
+ describe(event_type_translation_1.translateLoaderEventType.name, () => {
135
+ it.each([
136
+ [loading_1.LoaderEventType.DataLoadingDelay, loading_1.LoaderEventType.DataLoadingDelayed],
137
+ [
138
+ loading_1.LoaderEventType.AttachmentsLoadingProgress,
139
+ loading_1.LoaderEventType.AttachmentLoadingProgress,
140
+ ],
141
+ [
142
+ loading_1.LoaderEventType.AttachmentsLoadingDelayed,
143
+ loading_1.LoaderEventType.AttachmentLoadingDelayed,
144
+ ],
145
+ [
146
+ loading_1.LoaderEventType.AttachmentsLoadingDone,
147
+ loading_1.LoaderEventType.AttachmentLoadingDone,
148
+ ],
149
+ [
150
+ loading_1.LoaderEventType.AttachmentsLoadingError,
151
+ loading_1.LoaderEventType.AttachmentLoadingError,
152
+ ],
153
+ ])('maps legacy loader event %s to %s', (legacy, modern) => {
154
+ expect((0, event_type_translation_1.translateLoaderEventType)(legacy)).toBe(modern);
155
+ });
156
+ it.each([
157
+ [loading_1.LoaderEventType.DataLoadingDone],
158
+ [loading_1.LoaderEventType.DataLoadingProgress],
159
+ [loading_1.LoaderEventType.AttachmentLoadingDone],
160
+ ])('is a no-op for already-modern loader event %s', (eventType) => {
161
+ expect((0, event_type_translation_1.translateLoaderEventType)(eventType)).toBe(eventType);
162
+ });
163
+ });
164
+ describe(event_type_translation_1.translateOutgoingEventType.name, () => {
165
+ it('routes extractor events through translateExtractorEventType', () => {
166
+ expect((0, event_type_translation_1.translateOutgoingEventType)(extraction_1.ExtractorEventType.ExtractionDataDone)).toBe(extraction_1.ExtractorEventType.DataExtractionDone);
167
+ });
168
+ it('routes loader events through translateLoaderEventType', () => {
169
+ expect((0, event_type_translation_1.translateOutgoingEventType)(loading_1.LoaderEventType.AttachmentsLoadingDone)).toBe(loading_1.LoaderEventType.AttachmentLoadingDone);
170
+ });
171
+ it('passes through unknown event types unchanged', () => {
172
+ const unknown = 'SOME_UNKNOWN_EVENT';
173
+ expect((0, event_type_translation_1.translateOutgoingEventType)(unknown)).toBe(unknown);
174
+ });
175
+ });
@@ -135,7 +135,6 @@ describe('time-value-resolver', () => {
135
135
  const before = new Date().toISOString();
136
136
  const result = (0, time_value_resolver_1.resolveTimeValue)({ type: extraction_1.TimeValueType.CURRENT_TIME }, baseState);
137
137
  const after = new Date().toISOString();
138
- expect(result).toBeDefined();
139
138
  expect(result >= before).toBe(true);
140
139
  expect(result <= after).toBe(true);
141
140
  });
@@ -7,16 +7,20 @@ const extraction_1 = require("../types/extraction");
7
7
  const create_worker_1 = require("./create-worker");
8
8
  describe(create_worker_1.createWorker.name, () => {
9
9
  it('should create a Worker instance when valid parameters are provided', async () => {
10
+ // Arrange
10
11
  const workerPath = __dirname + '../tests/dummy-worker.ts';
12
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
13
+ payload: { event_type: extraction_1.EventType.ExtractionExternalSyncUnitsStart },
14
+ });
15
+ // Act
11
16
  const worker = worker_threads_1.isMainThread
12
17
  ? await (0, create_worker_1.createWorker)({
13
- event: (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
14
- payload: { event_type: extraction_1.EventType.ExtractionExternalSyncUnitsStart },
15
- }),
18
+ event,
16
19
  initialState: {},
17
20
  workerPath,
18
21
  })
19
22
  : null;
23
+ // Assert
20
24
  expect(worker).not.toBeNull();
21
25
  expect(worker).toBeInstanceOf(worker_threads_1.Worker);
22
26
  if (worker) {
@@ -24,36 +28,43 @@ describe(create_worker_1.createWorker.name, () => {
24
28
  }
25
29
  });
26
30
  it('should throw error when not in main thread', async () => {
31
+ // Arrange
27
32
  const originalIsMainThread = worker_threads_1.isMainThread;
28
33
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
34
  worker_threads_1.isMainThread = false;
30
35
  const workerPath = __dirname + '../tests/dummy-worker.ts';
36
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
37
+ payload: { event_type: extraction_1.EventType.ExtractionExternalSyncUnitsStart },
38
+ });
39
+ // Act & Assert
31
40
  await expect((0, create_worker_1.createWorker)({
32
- event: (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
33
- payload: { event_type: extraction_1.EventType.ExtractionExternalSyncUnitsStart },
34
- }),
41
+ event,
35
42
  initialState: {},
36
43
  workerPath,
37
44
  })).rejects.toThrow('Worker threads can not start more worker threads.');
38
- // Restore original value
39
45
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
46
  worker_threads_1.isMainThread = originalIsMainThread;
41
47
  });
42
48
  it('[edge] should handle worker creation with minimal valid data', async () => {
49
+ // Arrange
43
50
  const workerPath = __dirname + '../tests/dummy-worker.ts';
51
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
52
+ payload: { event_type: extraction_1.EventType.ExtractionExternalSyncUnitsStart },
53
+ });
44
54
  if (worker_threads_1.isMainThread) {
55
+ // Act
45
56
  const worker = await (0, create_worker_1.createWorker)({
46
- event: (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
47
- payload: { event_type: extraction_1.EventType.ExtractionExternalSyncUnitsStart },
48
- }),
57
+ event,
49
58
  initialState: {},
50
59
  workerPath,
51
60
  });
61
+ // Assert
52
62
  expect(worker).toBeInstanceOf(worker_threads_1.Worker);
53
63
  await worker.terminate();
54
64
  }
55
65
  });
56
66
  it('[edge] should handle worker creation with complex initial state', async () => {
67
+ // Arrange
57
68
  const workerPath = __dirname + '../tests/dummy-worker.ts';
58
69
  const complexState = {
59
70
  nested: {
@@ -61,28 +72,35 @@ describe(create_worker_1.createWorker.name, () => {
61
72
  config: { enabled: true },
62
73
  },
63
74
  };
75
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
76
+ payload: { event_type: extraction_1.EventType.ExtractionDataStart },
77
+ });
64
78
  if (worker_threads_1.isMainThread) {
79
+ // Act
65
80
  const worker = await (0, create_worker_1.createWorker)({
66
- event: (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
67
- payload: { event_type: extraction_1.EventType.ExtractionDataStart },
68
- }),
81
+ event,
69
82
  initialState: complexState,
70
83
  workerPath,
71
84
  });
85
+ // Assert
72
86
  expect(worker).toBeInstanceOf(worker_threads_1.Worker);
73
87
  await worker.terminate();
74
88
  }
75
89
  });
76
90
  it('[edge] should handle different event types', async () => {
91
+ // Arrange
77
92
  const workerPath = __dirname + '../tests/dummy-worker.ts';
93
+ const event = (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
94
+ payload: { event_type: extraction_1.EventType.ExtractionMetadataStart },
95
+ });
78
96
  if (worker_threads_1.isMainThread) {
97
+ // Act
79
98
  const worker = await (0, create_worker_1.createWorker)({
80
- event: (0, test_utils_1.createMockEvent)(jest_setup_1.mockServer.baseUrl, {
81
- payload: { event_type: extraction_1.EventType.ExtractionMetadataStart },
82
- }),
99
+ event,
83
100
  initialState: {},
84
101
  workerPath,
85
102
  });
103
+ // Assert
86
104
  expect(worker).toBeInstanceOf(worker_threads_1.Worker);
87
105
  await worker.terminate();
88
106
  }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=process-task.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-task.test.d.ts","sourceRoot":"","sources":["../../src/multithreading/process-task.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const extraction_1 = require("../types/extraction");
4
+ const workers_1 = require("../types/workers");
5
+ // These tests cover logic that is NOT exercised by the end-to-end integration
6
+ // tests under src/tests/timeout-handling/:
7
+ // - translation of legacy wire event types into the new enum (mutates event in place)
8
+ // - the hasWorkerEmitted guard that prevents onTimeout from firing after a
9
+ // successful emit (integration tests only exercise the positive case)
10
+ // - the error branch that posts WorkerMessageFailed and exits(1)
11
+ // - the WorkerMessage handler's guard that only flips isTimeout on
12
+ // WorkerMessageExit (integration tests can't cleanly target non-Exit messages)
13
+ //
14
+ // Tests for the happy path, timeout-signal-reaches-worker behavior, and main-thread
15
+ // early return were removed — they either duplicate what the integration suite
16
+ // already exercises or assert mocked behavior with little signal.
17
+ const mockParentPortPostMessage = jest.fn();
18
+ const mockParentPortOn = jest.fn();
19
+ let mockIsMainThread = false;
20
+ jest.mock('node:worker_threads', () => ({
21
+ get isMainThread() {
22
+ return mockIsMainThread;
23
+ },
24
+ get parentPort() {
25
+ return {
26
+ postMessage: mockParentPortPostMessage,
27
+ on: mockParentPortOn,
28
+ };
29
+ },
30
+ get workerData() {
31
+ var _a;
32
+ return (_a = global.__workerData__) !== null && _a !== void 0 ? _a : {};
33
+ },
34
+ }));
35
+ jest.mock('../common/event-type-translation', () => ({
36
+ translateIncomingEventType: jest.fn((t) => t),
37
+ }));
38
+ jest.mock('../logger/logger', () => ({
39
+ Logger: jest.fn().mockImplementation(() => ({
40
+ log: jest.fn(),
41
+ warn: jest.fn(),
42
+ error: jest.fn(),
43
+ info: jest.fn(),
44
+ logFn: jest.fn(),
45
+ })),
46
+ serializeError: jest.fn((e) => String(e)),
47
+ }));
48
+ jest.mock('../logger/logger.context', () => ({
49
+ runWithSdkLogContext: jest.fn((fn) => fn()),
50
+ runWithUserLogContext: jest.fn((fn) => fn()),
51
+ }));
52
+ jest.mock('../state/state', () => ({
53
+ createAdapterState: jest.fn(),
54
+ }));
55
+ jest.mock('./worker-adapter/worker-adapter', () => ({
56
+ WorkerAdapter: jest.fn().mockImplementation(() => ({
57
+ isTimeout: false,
58
+ hasWorkerEmitted: false,
59
+ })),
60
+ }));
61
+ const process_task_1 = require("./process-task");
62
+ const event_type_translation_1 = require("../common/event-type-translation");
63
+ const state_1 = require("../state/state");
64
+ const worker_adapter_1 = require("./worker-adapter/worker-adapter");
65
+ const test_utils_1 = require("../common/test-utils");
66
+ function setWorkerData(data) {
67
+ global.__workerData__ = data;
68
+ }
69
+ function makeEvent(eventType = extraction_1.EventType.StartExtractingData) {
70
+ return (0, test_utils_1.createMockEvent)('http://localhost:0', {
71
+ payload: { event_type: eventType },
72
+ });
73
+ }
74
+ // Flush the microtask queue enough to let the async IIFE inside processTask run.
75
+ const flush = async () => new Promise((r) => setTimeout(r, 0));
76
+ describe(process_task_1.processTask.name, () => {
77
+ let processExitSpy;
78
+ beforeEach(() => {
79
+ jest.clearAllMocks();
80
+ mockIsMainThread = false;
81
+ processExitSpy = jest
82
+ .spyOn(process, 'exit')
83
+ .mockImplementation((() => { }));
84
+ state_1.createAdapterState.mockResolvedValue({});
85
+ });
86
+ afterEach(() => {
87
+ processExitSpy.mockRestore();
88
+ });
89
+ it('should translate incoming event type before passing to task', async () => {
90
+ // Arrange
91
+ const event = makeEvent(extraction_1.EventType.StartExtractingData);
92
+ setWorkerData({ event, initialState: {}, options: {} });
93
+ event_type_translation_1.translateIncomingEventType.mockReturnValue(extraction_1.EventType.StartExtractingMetadata);
94
+ const task = jest.fn().mockResolvedValue(undefined);
95
+ const onTimeout = jest.fn().mockResolvedValue(undefined);
96
+ // Act
97
+ (0, process_task_1.processTask)({ task, onTimeout });
98
+ await flush();
99
+ // Assert
100
+ expect(event_type_translation_1.translateIncomingEventType).toHaveBeenCalledWith(extraction_1.EventType.StartExtractingData);
101
+ // The event is mutated in place — downstream code (including task) sees the
102
+ // translated type, not the original wire type.
103
+ expect(event.payload.event_type).toBe(extraction_1.EventType.StartExtractingMetadata);
104
+ });
105
+ it('should NOT call onTimeout when the worker already emitted before timeout check', async () => {
106
+ // Arrange
107
+ const event = makeEvent();
108
+ setWorkerData({ event, initialState: {}, options: {} });
109
+ // Both flags true: a timeout arrived but the worker had already emitted —
110
+ // onTimeout must be skipped. This is the guard the integration suite cannot
111
+ // target cleanly because it requires a precise race between emit and timeout.
112
+ const mockAdapter = { isTimeout: true, hasWorkerEmitted: true };
113
+ worker_adapter_1.WorkerAdapter.mockImplementation(() => mockAdapter);
114
+ const task = jest.fn().mockResolvedValue(undefined);
115
+ const onTimeout = jest.fn().mockResolvedValue(undefined);
116
+ // Act
117
+ (0, process_task_1.processTask)({ task, onTimeout });
118
+ await flush();
119
+ // Assert
120
+ expect(onTimeout).not.toHaveBeenCalled();
121
+ expect(processExitSpy).toHaveBeenCalledWith(0);
122
+ });
123
+ it('should NOT flip adapter.isTimeout when a non-Exit WorkerMessage arrives', async () => {
124
+ // Arrange
125
+ const event = makeEvent();
126
+ setWorkerData({ event, initialState: {}, options: {} });
127
+ const mockAdapter = { isTimeout: false, hasWorkerEmitted: false };
128
+ worker_adapter_1.WorkerAdapter.mockImplementation(() => mockAdapter);
129
+ const task = jest.fn().mockResolvedValue(undefined);
130
+ const onTimeout = jest.fn().mockResolvedValue(undefined);
131
+ // Act
132
+ (0, process_task_1.processTask)({ task, onTimeout });
133
+ await flush();
134
+ // Grab the handler registered for WorkerMessage events and invoke it with
135
+ // subjects that must NOT flip isTimeout (log messages, unknown subjects).
136
+ const messageHandlerCall = mockParentPortOn.mock.calls.find(([eventName]) => eventName === workers_1.WorkerEvent.WorkerMessage);
137
+ expect(messageHandlerCall).toBeDefined();
138
+ const handler = messageHandlerCall[1];
139
+ handler({ subject: workers_1.WorkerMessageSubject.WorkerMessageLog });
140
+ handler({ subject: 'NONSENSE_SUBJECT' });
141
+ // Assert
142
+ expect(mockAdapter.isTimeout).toBe(false);
143
+ });
144
+ it('should post WorkerMessageFailed with the error message and exit(1) when task throws', async () => {
145
+ // Arrange
146
+ const event = makeEvent();
147
+ setWorkerData({ event, initialState: {}, options: {} });
148
+ const mockAdapter = { isTimeout: false, hasWorkerEmitted: false };
149
+ worker_adapter_1.WorkerAdapter.mockImplementation(() => mockAdapter);
150
+ const taskError = new Error('task boom');
151
+ const task = jest.fn().mockRejectedValue(taskError);
152
+ const onTimeout = jest.fn().mockResolvedValue(undefined);
153
+ // Act
154
+ (0, process_task_1.processTask)({ task, onTimeout });
155
+ await flush();
156
+ // Assert
157
+ expect(mockParentPortPostMessage).toHaveBeenCalledWith(expect.objectContaining({
158
+ subject: workers_1.WorkerMessageSubject.WorkerMessageFailed,
159
+ payload: expect.objectContaining({
160
+ message: expect.stringContaining('task boom'),
161
+ }),
162
+ }));
163
+ expect(processExitSpy).toHaveBeenCalledWith(1);
164
+ expect(onTimeout).not.toHaveBeenCalled();
165
+ });
166
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=spawn.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawn.test.d.ts","sourceRoot":"","sources":["../../../src/multithreading/spawn/spawn.test.ts"],"names":[],"mappings":""}