@@ -15,9 +15,12 @@ jest.mock('../../src/lib/timeout-validator', () => ({
15
15
throwIfExecutionTimeExceeded : jest . fn ( ) ,
16
16
} ) ) ;
17
17
18
- const mockThrowIfExecutionTimeExceeded = throwIfExecutionTimeExceeded as jest . MockedFunction < typeof throwIfExecutionTimeExceeded > ;
18
+ jest . mock ( '@openops/common' , ( ) => ( {
19
+ makeHttpRequest : jest . fn ( ) ,
20
+ } ) ) ;
19
21
20
- global . fetch = jest . fn ( ) ;
22
+ const mockThrowIfExecutionTimeExceeded = throwIfExecutionTimeExceeded as jest . MockedFunction < typeof throwIfExecutionTimeExceeded > ;
23
+ const mockMakeHttpRequest = require ( '@openops/common' ) . makeHttpRequest as jest . MockedFunction < any > ;
21
24
22
25
describe ( 'Progress Service' , ( ) => {
23
26
const mockParams = {
@@ -45,10 +48,11 @@ describe('Progress Service', () => {
45
48
// Reset the timeout mock to not throw by default
46
49
mockThrowIfExecutionTimeExceeded . mockReset ( ) ;
47
50
48
- ( global . fetch as jest . Mock ) . mockResolvedValue ( {
49
- ok : true ,
50
- status : 200 ,
51
- } ) ;
51
+ mockMakeHttpRequest . mockResolvedValue ( { } ) ;
52
+
53
+ // Reset the global lastRequestHash by calling with unique params
54
+ // This ensures no deduplication issues between tests
55
+ jest . clearAllMocks ( ) ;
52
56
} ) ;
53
57
54
58
afterEach ( ( ) => {
@@ -68,14 +72,19 @@ describe('Progress Service', () => {
68
72
await progressService . sendUpdate ( successParams ) ;
69
73
70
74
expect ( successParams . flowExecutorContext . toResponse ) . toHaveBeenCalled ( ) ;
71
- expect ( global . fetch ) . toHaveBeenCalledWith (
75
+ expect ( mockMakeHttpRequest ) . toHaveBeenCalledWith (
76
+ 'POST' ,
72
77
'http://localhost:3000/v1/engine/update-run' ,
78
+ expect . any ( Object ) ,
73
79
expect . objectContaining ( {
74
- method : 'POST' ,
75
- headers : {
76
- 'Content-Type' : 'application/json' ,
77
- Authorization : 'Bearer test-token' ,
78
- } ,
80
+ executionCorrelationId : 'test-correlation-id-success' ,
81
+ runId : 'test-run-id' ,
82
+ workerHandlerId : 'test-handler-id' ,
83
+ progressUpdateType : 'WEBHOOK_RESPONSE' ,
84
+ } ) ,
85
+ expect . objectContaining ( {
86
+ retries : 3 ,
87
+ retryDelay : expect . any ( Function ) ,
79
88
} )
80
89
) ;
81
90
} ) ;
@@ -109,11 +118,12 @@ describe('Progress Service', () => {
109
118
110
119
await progressService . sendUpdate ( uniqueParams ) ;
111
120
112
- expect ( global . fetch ) . toHaveBeenCalledTimes ( 1 ) ;
113
- const fetchCall = ( global . fetch as jest . Mock ) . mock . calls [ 0 ] ;
114
- const [ url , options ] = fetchCall ;
115
- const requestBody = JSON . parse ( options . body ) ;
121
+ expect ( mockMakeHttpRequest ) . toHaveBeenCalledTimes ( 1 ) ;
122
+ const call = mockMakeHttpRequest . mock . calls [ 0 ] ;
123
+ const [ method , url , _ , requestBody ] = call ;
116
124
125
+ expect ( method ) . toBe ( 'POST' ) ;
126
+ expect ( url ) . toBe ( 'http://localhost:3000/v1/engine/update-run' ) ;
117
127
expect ( requestBody ) . toEqual (
118
128
expect . objectContaining ( {
119
129
executionCorrelationId : 'test-correlation-id-payload' ,
@@ -142,10 +152,9 @@ describe('Progress Service', () => {
142
152
143
153
await progressService . sendUpdate ( paramsWithoutHandlerId ) ;
144
154
145
- expect ( global . fetch ) . toHaveBeenCalledTimes ( 1 ) ;
146
- const fetchCall = ( global . fetch as jest . Mock ) . mock . calls [ 0 ] ;
147
- const [ url , options ] = fetchCall ;
148
- const requestBody = JSON . parse ( options . body ) ;
155
+ expect ( mockMakeHttpRequest ) . toHaveBeenCalledTimes ( 1 ) ;
156
+ const call = mockMakeHttpRequest . mock . calls [ 0 ] ;
157
+ const [ _ , __ , ___ , requestBody ] = call ;
149
158
150
159
expect ( requestBody . workerHandlerId ) . toBe ( null ) ;
151
160
} ) ;
@@ -162,7 +171,7 @@ describe('Progress Service', () => {
162
171
await progressService . sendUpdate ( duplicateParams ) ;
163
172
await progressService . sendUpdate ( duplicateParams ) ;
164
173
165
- expect ( global . fetch ) . toHaveBeenCalledTimes ( 1 ) ;
174
+ expect ( mockMakeHttpRequest ) . toHaveBeenCalledTimes ( 1 ) ;
166
175
} ) ;
167
176
168
177
it ( 'should send different requests when content changes' , async ( ) => {
@@ -185,7 +194,7 @@ describe('Progress Service', () => {
185
194
await progressService . sendUpdate ( params1 ) ;
186
195
await progressService . sendUpdate ( params2 ) ;
187
196
188
- expect ( global . fetch ) . toHaveBeenCalledTimes ( 2 ) ;
197
+ expect ( mockMakeHttpRequest ) . toHaveBeenCalledTimes ( 2 ) ;
189
198
} ) ;
190
199
191
200
it ( 'should deduplicate requests with different durations but same content' , async ( ) => {
@@ -224,7 +233,7 @@ describe('Progress Service', () => {
224
233
await progressService . sendUpdate ( params1 ) ;
225
234
await progressService . sendUpdate ( params2 ) ;
226
235
227
- expect ( global . fetch ) . toHaveBeenCalledTimes ( 1 ) ;
236
+ expect ( mockMakeHttpRequest ) . toHaveBeenCalledTimes ( 1 ) ;
228
237
expect ( params1 . flowExecutorContext . toResponse ) . toHaveBeenCalledTimes ( 1 ) ;
229
238
expect ( params2 . flowExecutorContext . toResponse ) . toHaveBeenCalledTimes ( 1 ) ;
230
239
} ) ;
@@ -265,47 +274,11 @@ describe('Progress Service', () => {
265
274
await progressService . sendUpdate ( params1 ) ;
266
275
await progressService . sendUpdate ( params2 ) ;
267
276
268
- expect ( global . fetch ) . toHaveBeenCalledTimes ( 2 ) ;
277
+ expect ( mockMakeHttpRequest ) . toHaveBeenCalledTimes ( 2 ) ;
269
278
expect ( params1 . flowExecutorContext . toResponse ) . toHaveBeenCalledTimes ( 1 ) ;
270
279
expect ( params2 . flowExecutorContext . toResponse ) . toHaveBeenCalledTimes ( 1 ) ;
271
280
} ) ;
272
281
273
- it ( 'should use mutex for thread safety' , async ( ) => {
274
- const concurrentParams = {
275
- ...mockParams ,
276
- engineConstants : {
277
- ...mockParams . engineConstants ,
278
- executionCorrelationId : 'test-correlation-id-concurrent' ,
279
- } ,
280
- } ;
281
-
282
- // Make multiple concurrent requests
283
- const promises = [
284
- progressService . sendUpdate ( concurrentParams ) ,
285
- progressService . sendUpdate ( concurrentParams ) ,
286
- progressService . sendUpdate ( concurrentParams ) ,
287
- ] ;
288
-
289
- await Promise . all ( promises ) ;
290
-
291
- // Due to mutex locking and request deduplication, should only make one request
292
- expect ( global . fetch ) . toHaveBeenCalledTimes ( 1 ) ;
293
- } ) ;
294
-
295
- it ( 'should handle fetch errors gracefully' , async ( ) => {
296
- const errorParams = {
297
- ...mockParams ,
298
- engineConstants : {
299
- ...mockParams . engineConstants ,
300
- executionCorrelationId : 'test-correlation-id-error' ,
301
- } ,
302
- } ;
303
-
304
- ( global . fetch as jest . Mock ) . mockRejectedValue ( new Error ( 'Network error' ) ) ;
305
-
306
- await expect ( progressService . sendUpdate ( errorParams ) ) . rejects . toThrow ( 'Network error' ) ;
307
- } ) ;
308
-
309
282
it ( 'should construct correct URL' , async ( ) => {
310
283
const paramsWithDifferentUrl = {
311
284
...mockParams ,
@@ -318,13 +291,15 @@ describe('Progress Service', () => {
318
291
319
292
await progressService . sendUpdate ( paramsWithDifferentUrl ) ;
320
293
321
- expect ( global . fetch ) . toHaveBeenCalledWith (
294
+ expect ( mockMakeHttpRequest ) . toHaveBeenCalledWith (
295
+ 'POST' ,
322
296
'https://api.example.com/v1/engine/update-run' ,
297
+ expect . any ( Object ) ,
298
+ expect . any ( Object ) ,
323
299
expect . any ( Object )
324
300
) ;
325
301
} ) ;
326
302
327
-
328
303
it ( 'should throw error when execution time is exceeded' , async ( ) => {
329
304
const timeoutParams = {
330
305
...mockParams ,
@@ -341,8 +316,39 @@ describe('Progress Service', () => {
341
316
342
317
await expect ( progressService . sendUpdate ( timeoutParams ) ) . rejects . toThrow ( 'Execution time exceeded' ) ;
343
318
expect ( mockThrowIfExecutionTimeExceeded ) . toHaveBeenCalledTimes ( 1 ) ;
344
- expect ( global . fetch ) . not . toHaveBeenCalled ( ) ;
319
+ expect ( mockMakeHttpRequest ) . not . toHaveBeenCalled ( ) ;
345
320
expect ( timeoutParams . flowExecutorContext . toResponse ) . not . toHaveBeenCalled ( ) ;
346
321
} ) ;
322
+
323
+ it ( 'should use correct retry configuration' , async ( ) => {
324
+ const retryParams = {
325
+ ...mockParams ,
326
+ engineConstants : {
327
+ ...mockParams . engineConstants ,
328
+ executionCorrelationId : 'test-correlation-id-retry' ,
329
+ } ,
330
+ } ;
331
+
332
+ await progressService . sendUpdate ( retryParams ) ;
333
+
334
+ expect ( mockMakeHttpRequest ) . toHaveBeenCalledWith (
335
+ 'POST' ,
336
+ 'http://localhost:3000/v1/engine/update-run' ,
337
+ expect . any ( Object ) ,
338
+ expect . any ( Object ) ,
339
+ expect . objectContaining ( {
340
+ retries : 3 ,
341
+ retryDelay : expect . any ( Function ) ,
342
+ } )
343
+ ) ;
344
+
345
+ // Test the retry delay function
346
+ const call = mockMakeHttpRequest . mock . calls [ 0 ] ;
347
+ const [ _ , __ , ___ , ____ , options ] = call ;
348
+
349
+ expect ( options . retryDelay ( 0 ) ) . toBe ( 200 ) ; // 1st retry: 200ms
350
+ expect ( options . retryDelay ( 1 ) ) . toBe ( 400 ) ; // 2nd retry: 400ms
351
+ expect ( options . retryDelay ( 2 ) ) . toBe ( 600 ) ; // 3rd retry: 600ms
352
+ } ) ;
347
353
} ) ;
348
354
} ) ;
0 commit comments