Files
mruby-mruby/mrbgems/mruby-task/test/task.rb
T
Yukihiro "Matz" Matsumoto dfc542dbc5 mruby-task: terminate suspended task in suspend test
The "Task#suspend doesn't raise" test left its task parked in
q_suspended_. A later test ("Task.run inside Task.run is a noop")
calls Task.run, and the scheduler will not exit its loop while any
task sits in the suspended (or waiting) queue, so the whole run
hung.

Terminate the task at the end of the suspend test so it does not
leak into the shared scheduler state the next test depends on. This
fixes the hang at its source rather than scrubbing leaked tasks from
the consumer side.

Refs #6866, #6867.

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-28 12:02:07 +09:00

197 lines
4.7 KiB
Ruby

# Sleep/usleep tests (from mruby-sleep)
# Note: Use minimal sleep times to avoid test slowdown
assert("sleep accepts non-negative values") do
assert_nothing_raised { sleep(0) }
end
assert("sleep accepts non-negative float values") do
skip unless Object.const_defined?(:Float)
assert_nothing_raised { sleep(0.0) }
assert_nothing_raised { sleep(-0.0) }
end
assert("sleep raises ArgumentError for negative integer") do
assert_raise(ArgumentError) { sleep(-1) }
end
assert("sleep raises ArgumentError for negative float") do
skip unless Object.const_defined?(:Float)
assert_raise(ArgumentError) { sleep(-0.1) }
end
assert("usleep accepts non-negative values") do
assert_nothing_raised { usleep(0) }
end
assert("usleep raises ArgumentError for negative value") do
assert_raise(ArgumentError) { usleep(-100) }
end
# Task creation tests
assert("Task.new creates a task") do
task = Task.new { }
assert_kind_of Task, task
end
assert("Task.new accepts name") do
task = Task.new(name: "test") { }
assert_equal "test", task.name
end
assert("Task.new accepts priority") do
task = Task.new(priority: 100) { }
assert_equal 100, task.priority
end
assert("Task.new raises without block") do
assert_raise(ArgumentError) { Task.new }
end
# Task state tests
assert("Task#status returns symbol") do
task = Task.new { }
status = task.status
assert_true [:READY, :RUNNING, :WAITING, :SUSPENDED, :DORMANT, :UNKNOWN].include?(status)
end
assert("new task has READY status") do
task = Task.new { }
assert_equal :READY, task.status
end
assert("Task#inspect returns formatted string") do
task = Task.new(name: "test") { }
inspect_str = task.inspect
assert_kind_of String, inspect_str
assert_true inspect_str.include?("Task")
assert_true inspect_str.include?("test")
end
assert("Task#inspect shows status") do
task = Task.new { }
inspect_str = task.inspect
assert_true inspect_str.include?("READY") || inspect_str.include?("DORMANT")
end
# Task control methods
assert("Task#suspend doesn't raise") do
task = Task.new { }
assert_nothing_raised { task.suspend }
# Clean up: a suspended task left in q_suspended_ keeps a later
# Task.run from terminating (the scheduler idles waiting on it
# instead of exiting).
task.terminate
end
assert("Task#resume doesn't raise") do
task = Task.new { }
assert_nothing_raised { task.resume }
end
assert("Task#terminate doesn't raise") do
task = Task.new { }
assert_nothing_raised { task.terminate }
end
# Task.current tests
assert("Task.current in root context") do
# In root context, Task.current might be nil or a special value
current = Task.current
assert_true current.nil? || current.kind_of?(Task)
end
# Task.pass tests
assert("Task.pass yields control") do
assert_nothing_raised { Task.pass }
end
# Task.stat tests
assert("Task.stat returns hash") do
stat = Task.stat
assert_kind_of Hash, stat
end
assert("Task.stat includes tick") do
stat = Task.stat
assert_true stat.has_key?(:tick)
assert_kind_of Integer, stat[:tick]
end
assert("Task.stat includes wakeup_tick") do
stat = Task.stat
assert_true stat.has_key?(:wakeup_tick)
assert_kind_of Integer, stat[:wakeup_tick]
end
assert("Task.stat includes queue counts") do
stat = Task.stat
[:ready, :waiting, :suspended, :dormant].each do |queue|
assert_true stat.has_key?(queue), "Missing queue: #{queue}"
assert_kind_of Hash, stat[queue]
assert_true stat[queue].has_key?(:count)
assert_kind_of Integer, stat[queue][:count]
assert_true stat[queue].has_key?(:tasks)
assert_kind_of Array, stat[queue][:tasks]
end
end
assert("Task.stat tracks task counts") do
stat_before = Task.stat
ready_before = stat_before[:ready][:count]
task1 = Task.new { sleep 0 }
task2 = Task.new { sleep 0 }
stat_after = Task.stat
ready_after = stat_after[:ready][:count]
assert_equal ready_before + 2, ready_after
end
# Priority tests
assert("Task.new accepts different priorities") do
low = Task.new(priority: 200) { }
high = Task.new(priority: 50) { }
med = Task.new(priority: 128) { }
assert_equal 200, low.priority
assert_equal 50, high.priority
assert_equal 128, med.priority
end
# Name handling
assert("Task with string name") do
task = Task.new(name: "string_name") { }
assert_equal "string_name", task.name
end
assert("Task without name returns (noname)") do
task = Task.new { }
assert_equal "(noname)", task.name
end
# Edge cases
assert("Task.new with block doesn't execute immediately") do
executed = false
task = Task.new { executed = true }
# Block should not execute until scheduler runs
assert_false executed
end
assert("Task.run inside Task.run is a noop") do
assert_nothing_raised do
Task.new { Task.run }
Task.run
end
end