@@ -314,8 +314,8 @@ func TestWorker_Handle(t *testing.T) {
314
314
task := & testTask {ID : 1 , Data : "test" }
315
315
result := & testResult {Output : "success" }
316
316
317
- mockTaskWorker .On ("Execute" , ctx , task ).Return (result , nil )
318
- mockTaskWorker .On ("Complete" , ctx , result , task ).Return (nil )
317
+ mockTaskWorker .On ("Execute" , mock . Anything , task ).Return (result , nil )
318
+ mockTaskWorker .On ("Complete" , mock . Anything , result , task ).Return (nil )
319
319
320
320
err := worker .handle (ctx , task )
321
321
assert .NoError (t , err )
@@ -339,8 +339,8 @@ func TestWorker_Handle(t *testing.T) {
339
339
task := & testTask {ID : 1 , Data : "test" }
340
340
result := & testResult {Output : "success" }
341
341
342
- mockTaskWorker .On ("Execute" , ctx , task ).Return (result , nil )
343
- mockTaskWorker .On ("Complete" , ctx , result , task ).Return (nil )
342
+ mockTaskWorker .On ("Execute" , mock . Anything , task ).Return (result , nil )
343
+ mockTaskWorker .On ("Complete" , mock . Anything , result , task ).Return (nil )
344
344
// Heartbeat might be called during execution
345
345
mockTaskWorker .On ("Extend" , mock .Anything , task ).Return (nil ).Maybe ()
346
346
@@ -365,7 +365,7 @@ func TestWorker_Handle(t *testing.T) {
365
365
task := & testTask {ID : 1 , Data : "test" }
366
366
expectedErr := errors .New ("execution error" )
367
367
368
- mockTaskWorker .On ("Execute" , ctx , task ).Return (nil , expectedErr )
368
+ mockTaskWorker .On ("Execute" , mock . Anything , task ).Return (nil , expectedErr )
369
369
370
370
err := worker .handle (ctx , task )
371
371
assert .Error (t , err )
@@ -391,15 +391,48 @@ func TestWorker_Handle(t *testing.T) {
391
391
result := & testResult {Output : "success" }
392
392
expectedErr := errors .New ("completion error" )
393
393
394
- mockTaskWorker .On ("Execute" , ctx , task ).Return (result , nil )
395
- mockTaskWorker .On ("Complete" , ctx , result , task ).Return (expectedErr )
394
+ mockTaskWorker .On ("Execute" , mock . Anything , task ).Return (result , nil )
395
+ mockTaskWorker .On ("Complete" , mock . Anything , result , task ).Return (expectedErr )
396
396
397
397
err := worker .handle (ctx , task )
398
398
assert .Error (t , err )
399
399
assert .Equal (t , expectedErr , err )
400
400
401
401
mockTaskWorker .AssertExpectations (t )
402
402
})
403
+
404
+ t .Run ("abort processing on heartbeat extend failure" , func (t * testing.T ) {
405
+ mockBackend := createMockBackend ()
406
+ mockTaskWorker := & mockTaskWorker {}
407
+
408
+ options := & WorkerOptions {
409
+ Pollers : 1 ,
410
+ MaxParallelTasks : 1 ,
411
+ HeartbeatInterval : time .Millisecond * 5 ,
412
+ }
413
+
414
+ worker := NewWorker (mockBackend , mockTaskWorker , options )
415
+
416
+ ctx , cancel := context .WithTimeout (context .Background (), time .Second )
417
+ defer cancel ()
418
+
419
+ task := & testTask {ID : 1 , Data : "test" }
420
+
421
+ // Simulate Extend failing immediately so the heartbeat cancels processing
422
+ mockTaskWorker .On ("Extend" , mock .Anything , task ).Return (errors .New ("extend failed" )).Maybe ()
423
+
424
+ // Execute should see canceled context and return context.Canceled or respect ctx.Done
425
+ mockTaskWorker .On ("Execute" , mock .Anything , task ).Return (nil , context .Canceled )
426
+
427
+ // Complete must NOT be called when execution is aborted due to lost ownership
428
+ // No expectation set for Complete to ensure it's not invoked
429
+ mockTaskWorker .AssertNotCalled (t , "Complete" , mock .Anything , mock .Anything , mock .Anything )
430
+
431
+ err := worker .handle (ctx , task )
432
+ require .Error (t , err )
433
+
434
+ mockTaskWorker .AssertExpectations (t )
435
+ })
403
436
}
404
437
405
438
func TestWorker_HeartbeatTask (t * testing.T ) {
@@ -423,7 +456,7 @@ func TestWorker_HeartbeatTask(t *testing.T) {
423
456
// Expect multiple heartbeat calls
424
457
mockTaskWorker .On ("Extend" , ctx , task ).Return (nil )
425
458
426
- worker .heartbeatTask (ctx , task )
459
+ worker .heartbeatTask (ctx , task , nil )
427
460
428
461
// Should have called Extend at least once
429
462
mockTaskWorker .AssertExpectations (t )
@@ -450,7 +483,7 @@ func TestWorker_HeartbeatTask(t *testing.T) {
450
483
mockTaskWorker .On ("Extend" , ctx , task ).Return (expectedErr )
451
484
452
485
// Should not panic even with errors
453
- worker .heartbeatTask (ctx , task )
486
+ worker .heartbeatTask (ctx , task , nil )
454
487
455
488
mockTaskWorker .AssertExpectations (t )
456
489
})
@@ -475,7 +508,7 @@ func TestWorker_HeartbeatTask(t *testing.T) {
475
508
476
509
// Should exit quickly without calling Extend
477
510
start := time .Now ()
478
- worker .heartbeatTask (ctx , task )
511
+ worker .heartbeatTask (ctx , task , nil )
479
512
duration := time .Since (start )
480
513
481
514
assert .Less (t , duration , time .Millisecond * 100 )
@@ -504,6 +537,7 @@ func TestWorker_FullWorkflow(t *testing.T) {
504
537
// Track processed tasks
505
538
var processedTasks int32
506
539
var taskResults []* testResult
540
+ var mu sync.Mutex
507
541
508
542
task1 := & testTask {ID : 1 , Data : "task1" }
509
543
task2 := & testTask {ID : 2 , Data : "task2" }
@@ -520,10 +554,14 @@ func TestWorker_FullWorkflow(t *testing.T) {
520
554
521
555
mockTaskWorker .On ("Execute" , mock .Anything , task1 ).Return (result1 , nil ).Run (func (args mock.Arguments ) {
522
556
atomic .AddInt32 (& processedTasks , 1 )
557
+ mu .Lock ()
558
+ defer mu .Unlock ()
523
559
taskResults = append (taskResults , result1 )
524
560
})
525
561
mockTaskWorker .On ("Execute" , mock .Anything , task2 ).Return (result2 , nil ).Run (func (args mock.Arguments ) {
526
562
atomic .AddInt32 (& processedTasks , 1 )
563
+ mu .Lock ()
564
+ defer mu .Unlock ()
527
565
taskResults = append (taskResults , result2 )
528
566
})
529
567
0 commit comments