@@ -268,16 +268,60 @@ def test_single_test_marked_lost_after_default_timeout
268268 reserved_id = worker1 . send ( :try_to_reserve_test )
269269 assert_equal 'TestA#test_1' , reserved_id
270270
271- # Wait longer than timeout (0.5s)
271+ # Wait longer than timeout (0.5s) but less than 2 minutes
272272 sleep 0.6
273273
274- # Try to reserve with worker2 - should get the lost test
274+ # Try to reserve with worker2 - should NOT get the test because heartbeat is recent (< 2 minutes)
275275 worker2_config = config . dup
276276 worker2_config . instance_variable_set ( :@worker_id , '2' )
277277 worker2 = CI ::Queue ::Redis . new ( @redis_url , worker2_config )
278278
279279 lost_test = worker2 . send ( :try_to_reserve_lost_test )
280- assert_equal 'TestA#test_1' , lost_test , 'Single test should be marked as lost after default timeout'
280+ assert_nil lost_test , 'Test should not be marked as lost if heartbeat is recent (< 2 minutes)'
281+ end
282+
283+ def test_single_test_marked_lost_after_heartbeat_expires
284+ # Create worker with short timeout
285+ config = CI ::Queue ::Configuration . new (
286+ build_id : 'heartbeat-timeout-test' ,
287+ worker_id : '1' ,
288+ timeout : 0.5 # 0.5 seconds
289+ )
290+
291+ worker1 = CI ::Queue ::Redis . new ( @redis_url , config )
292+
293+ # Populate with single test (no chunk)
294+ tests = create_mock_tests ( [ 'TestA#test_1' ] )
295+
296+ worker1 . stub ( :reorder_tests , tests ) do
297+ worker1 . populate ( tests )
298+ end
299+
300+ # Reserve the test with worker1
301+ reserved_id = worker1 . send ( :try_to_reserve_test )
302+ assert_equal 'TestA#test_1' , reserved_id
303+
304+ # Manually set the heartbeat timestamp to be older than 2 minutes
305+ # by manipulating Redis directly
306+ current_time = CI ::Queue . time_now . to_f
307+ old_heartbeat_time = current_time - 130 # 130 seconds ago (more than 2 minutes)
308+ worker_queue_key = "build:heartbeat-timeout-test:worker:1:queue"
309+ owner_value = "#{ worker_queue_key } |#{ old_heartbeat_time } "
310+ @redis . hset ( 'build:heartbeat-timeout-test:owners' , 'TestA#test_1' , owner_value )
311+
312+ # Also set the deadline to be in the past so it's considered "lost"
313+ @redis . zadd ( 'build:heartbeat-timeout-test:running' , current_time - 10 , 'TestA#test_1' )
314+
315+ # Wait a bit to ensure time has passed
316+ sleep 0.1
317+
318+ # Try to reserve with worker2 - should get the lost test now
319+ worker2_config = config . dup
320+ worker2_config . instance_variable_set ( :@worker_id , '2' )
321+ worker2 = CI ::Queue ::Redis . new ( @redis_url , worker2_config )
322+
323+ lost_test = worker2 . send ( :try_to_reserve_lost_test )
324+ assert_equal 'TestA#test_1' , lost_test , 'Test should be marked as lost after heartbeat expires (> 2 minutes)'
281325 end
282326
283327 def test_batching_with_many_chunks
0 commit comments