Skip to content

Commit 71f68a0

Browse files
committed
Add edge-case tests for heartbeat_max_test_duration
- test_heartbeat_cap_resets_between_tests: verifies :reset clears capped between consecutive tests so subsequent stuck tests are still reclaimable - test_heartbeat_cap_doesnt_affect_fast_test: verifies cap is a no-op when the test finishes before max_duration fires - test_heartbeat_max_test_duration_defaults: pins the default value logic (timeout*10 when heartbeat enabled, nil when disabled, explicit overrides)
1 parent 9c56834 commit 71f68a0

2 files changed

Lines changed: 67 additions & 0 deletions

File tree

ruby/test/ci/queue/configuration_test.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,5 +200,19 @@ def test_new_lazy_load_test_helpers_env
200200
assert_equal ["test/test_helper.rb", "test/support/helper.rb"], config.lazy_load_test_helper_paths
201201
end
202202

203+
def test_heartbeat_max_test_duration_defaults
204+
# defaults to timeout*10 when heartbeat is enabled
205+
config = Configuration.new(timeout: 5, max_missed_heartbeat_seconds: 1)
206+
assert_equal 50, config.heartbeat_max_test_duration
207+
208+
# nil when heartbeat is disabled (no max_missed_heartbeat_seconds)
209+
config = Configuration.new(timeout: 5)
210+
assert_nil config.heartbeat_max_test_duration
211+
212+
# explicit value overrides the default
213+
config = Configuration.new(timeout: 5, max_missed_heartbeat_seconds: 1, heartbeat_max_test_duration: 3)
214+
assert_equal 3, config.heartbeat_max_test_duration
215+
end
216+
203217
end
204218
end

ruby/test/ci/queue/redis_test.rb

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,59 @@ def test_heartbeat_max_test_duration_stops_heartbeat
530530
queue&.stop_heartbeat!
531531
end
532532

533+
def test_heartbeat_cap_resets_between_tests
534+
two_tests = TEST_LIST.first(2)
535+
queue = worker(1, max_missed_heartbeat_seconds: 2, heartbeat_max_test_duration: 1, tests: two_tests, build_id: 'hb-reset')
536+
queue.boot_heartbeat_process!
537+
538+
tests_run = []
539+
queue.poll do |test|
540+
entry = test.queue_entry
541+
lease = queue.lease_for(entry)
542+
tests_run << entry
543+
544+
queue.with_heartbeat(entry, lease: lease) do
545+
if tests_run.size == 1
546+
# First test: sleep past the cap so capped=true inside the thread
547+
sleep 2
548+
score = @redis.zscore(queue.send(:key, 'running'), entry)
549+
assert score < CI::Queue.time_now.to_f - 1, "First test score should be stale after cap"
550+
else
551+
# Second test: cap should have been reset; heartbeat should be ticking
552+
sleep 0.5
553+
score = @redis.zscore(queue.send(:key, 'running'), entry)
554+
assert score > CI::Queue.time_now.to_f - 2, "Second test score should be fresh after reset"
555+
end
556+
end
557+
558+
queue.acknowledge(entry)
559+
end
560+
561+
assert_equal 2, tests_run.size, "Both tests should have run"
562+
ensure
563+
queue&.stop_heartbeat!
564+
end
565+
566+
def test_heartbeat_cap_doesnt_affect_fast_test
567+
queue = worker(1, max_missed_heartbeat_seconds: 2, heartbeat_max_test_duration: 10, tests: [TEST_LIST.first], build_id: 'hb-fast')
568+
queue.boot_heartbeat_process!
569+
570+
queue.poll do |test|
571+
entry = test.queue_entry
572+
lease = queue.lease_for(entry)
573+
574+
queue.with_heartbeat(entry, lease: lease) do
575+
sleep 0.5 # well under the 10s cap
576+
score = @redis.zscore(queue.send(:key, 'running'), entry)
577+
assert score > CI::Queue.time_now.to_f - 2, "Score should be fresh -- cap should not have fired"
578+
end
579+
580+
queue.acknowledge(entry)
581+
end
582+
ensure
583+
queue&.stop_heartbeat!
584+
end
585+
533586
def test_resolve_entry_falls_back_to_resolver
534587
queue = worker(1, populate: false)
535588
queue.instance_variable_set(:@index, { 'ATest#test_foo' => :ok })

0 commit comments

Comments
 (0)