2011-09-20 01:16:31 -04:00
|
|
|
require 'test/unit'
|
|
|
|
|
2011-09-22 22:24:43 -04:00
|
|
|
require 'puma/thread_pool'
|
2011-09-20 01:16:31 -04:00
|
|
|
|
|
|
|
class TestThreadPool < Test::Unit::TestCase
|
|
|
|
|
|
|
|
def teardown
|
|
|
|
@pool.shutdown if @pool
|
|
|
|
end
|
|
|
|
|
2013-07-03 10:25:48 -04:00
|
|
|
def new_pool(min, max, &block)
|
|
|
|
block = proc { } unless block
|
|
|
|
@pool = Puma::ThreadPool.new(min, max, &block)
|
2011-09-20 01:16:31 -04:00
|
|
|
end
|
|
|
|
|
2011-09-23 23:49:45 -04:00
|
|
|
def pause
|
|
|
|
sleep 0.2
|
|
|
|
end
|
|
|
|
|
2011-09-20 01:16:31 -04:00
|
|
|
def test_append_spawns
|
|
|
|
saw = []
|
2016-04-28 10:28:44 -04:00
|
|
|
thread_name = nil
|
2011-09-20 01:16:31 -04:00
|
|
|
|
|
|
|
pool = new_pool(0, 1) do |work|
|
|
|
|
saw << work
|
2016-04-28 10:28:44 -04:00
|
|
|
thread_name = Thread.current.name if Thread.current.respond_to?(:name)
|
2011-09-20 01:16:31 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
pool << 1
|
|
|
|
|
2011-09-23 23:49:45 -04:00
|
|
|
pause
|
|
|
|
|
2011-09-20 01:16:31 -04:00
|
|
|
assert_equal [1], saw
|
|
|
|
assert_equal 1, pool.spawned
|
2016-04-28 10:28:44 -04:00
|
|
|
# Thread name is new in Ruby 2.3
|
|
|
|
assert_equal('puma 001', thread_name) if Thread.current.respond_to?(:name)
|
2011-09-20 01:16:31 -04:00
|
|
|
end
|
|
|
|
|
2013-07-16 20:07:59 -04:00
|
|
|
def test_converts_pool_sizes
|
|
|
|
pool = new_pool('0', '1')
|
|
|
|
|
|
|
|
assert_equal 0, pool.spawned
|
|
|
|
|
|
|
|
pool << 1
|
|
|
|
|
|
|
|
assert_equal 1, pool.spawned
|
|
|
|
end
|
|
|
|
|
2011-09-20 01:16:31 -04:00
|
|
|
def test_append_queues_on_max
|
|
|
|
finish = false
|
|
|
|
pool = new_pool(0, 1) { Thread.pass until finish }
|
|
|
|
|
|
|
|
pool << 1
|
|
|
|
pool << 2
|
|
|
|
pool << 3
|
|
|
|
|
2011-09-23 23:49:45 -04:00
|
|
|
pause
|
|
|
|
|
2011-09-20 01:16:31 -04:00
|
|
|
assert_equal 2, pool.backlog
|
|
|
|
|
|
|
|
finish = true
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_trim
|
|
|
|
pool = new_pool(0, 1)
|
|
|
|
|
|
|
|
pool << 1
|
|
|
|
|
2011-09-23 23:49:45 -04:00
|
|
|
pause
|
|
|
|
|
2011-09-20 01:16:31 -04:00
|
|
|
assert_equal 1, pool.spawned
|
|
|
|
pool.trim
|
2011-10-03 17:52:23 -04:00
|
|
|
|
|
|
|
pause
|
2011-09-20 01:16:31 -04:00
|
|
|
assert_equal 0, pool.spawned
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_trim_leaves_min
|
|
|
|
finish = false
|
|
|
|
pool = new_pool(1, 2) { Thread.pass until finish }
|
|
|
|
|
|
|
|
pool << 1
|
|
|
|
pool << 2
|
|
|
|
|
|
|
|
finish = true
|
|
|
|
|
2012-02-07 12:49:23 -05:00
|
|
|
pause
|
|
|
|
|
2011-09-20 01:16:31 -04:00
|
|
|
assert_equal 2, pool.spawned
|
|
|
|
pool.trim
|
2011-10-03 17:52:23 -04:00
|
|
|
pause
|
2011-09-20 01:16:31 -04:00
|
|
|
|
|
|
|
assert_equal 1, pool.spawned
|
|
|
|
pool.trim
|
2011-10-03 17:52:23 -04:00
|
|
|
pause
|
2011-09-20 01:16:31 -04:00
|
|
|
|
|
|
|
assert_equal 1, pool.spawned
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2012-02-07 12:49:23 -05:00
|
|
|
def test_force_trim_doesnt_overtrim
|
|
|
|
finish = false
|
|
|
|
pool = new_pool(1, 2) { Thread.pass until finish }
|
|
|
|
|
|
|
|
pool << 1
|
|
|
|
pool << 2
|
|
|
|
|
|
|
|
assert_equal 2, pool.spawned
|
|
|
|
pool.trim true
|
|
|
|
pool.trim true
|
|
|
|
|
|
|
|
finish = true
|
|
|
|
|
|
|
|
pause
|
|
|
|
|
|
|
|
assert_equal 1, pool.spawned
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_trim_is_ignored_if_no_waiting_threads
|
2011-09-20 01:16:31 -04:00
|
|
|
finish = false
|
|
|
|
pool = new_pool(1, 2) { Thread.pass until finish }
|
|
|
|
|
|
|
|
pool << 1
|
|
|
|
pool << 2
|
|
|
|
|
|
|
|
assert_equal 2, pool.spawned
|
|
|
|
pool.trim
|
|
|
|
pool.trim
|
|
|
|
|
2012-07-30 19:37:43 -04:00
|
|
|
assert_equal 0, pool.trim_requested
|
|
|
|
|
2011-09-20 01:16:31 -04:00
|
|
|
finish = true
|
|
|
|
|
2011-10-03 17:52:23 -04:00
|
|
|
pause
|
2011-09-20 01:16:31 -04:00
|
|
|
end
|
2011-12-05 13:07:01 -05:00
|
|
|
|
|
|
|
def test_autotrim
|
|
|
|
finish = false
|
|
|
|
pool = new_pool(1, 2) { Thread.pass until finish }
|
|
|
|
|
|
|
|
pool << 1
|
|
|
|
pool << 2
|
|
|
|
|
|
|
|
assert_equal 2, pool.spawned
|
|
|
|
|
|
|
|
finish = true
|
|
|
|
|
|
|
|
pause
|
|
|
|
|
|
|
|
assert_equal 2, pool.spawned
|
|
|
|
|
|
|
|
pool.auto_trim! 1
|
|
|
|
|
|
|
|
sleep 1
|
|
|
|
|
|
|
|
pause
|
|
|
|
|
|
|
|
assert_equal 1, pool.spawned
|
|
|
|
end
|
2014-10-30 20:52:37 -04:00
|
|
|
|
|
|
|
def test_cleanliness
|
|
|
|
values = []
|
|
|
|
n = 100
|
|
|
|
mutex = Mutex.new
|
|
|
|
|
|
|
|
finished = false
|
|
|
|
|
|
|
|
pool = new_pool(1,1) {
|
|
|
|
mutex.synchronize { values.push Thread.current[:foo] }
|
|
|
|
Thread.current[:foo] = :hai
|
|
|
|
Thread.pass until finished
|
|
|
|
}
|
|
|
|
|
2014-11-27 01:50:45 -05:00
|
|
|
pool.clean_thread_locals = true
|
|
|
|
|
2014-10-30 20:52:37 -04:00
|
|
|
n.times { pool << 1 }
|
|
|
|
|
|
|
|
finished = true
|
|
|
|
|
|
|
|
pause
|
|
|
|
|
|
|
|
assert_equal n, values.length
|
|
|
|
|
|
|
|
assert_equal [], values.compact
|
|
|
|
end
|
2015-05-19 10:14:30 -04:00
|
|
|
|
|
|
|
def test_reap_only_dead_threads
|
|
|
|
pool = new_pool(2,2) { Thread.current.kill }
|
|
|
|
|
|
|
|
assert_equal 2, pool.spawned
|
|
|
|
|
|
|
|
pool << 1
|
|
|
|
|
|
|
|
pause
|
|
|
|
|
|
|
|
assert_equal 2, pool.spawned
|
|
|
|
|
|
|
|
pool.reap
|
|
|
|
|
|
|
|
assert_equal 1, pool.spawned
|
|
|
|
|
|
|
|
pool << 2
|
|
|
|
|
|
|
|
pause
|
|
|
|
|
|
|
|
assert_equal 1, pool.spawned
|
|
|
|
|
|
|
|
pool.reap
|
|
|
|
|
|
|
|
assert_equal 0, pool.spawned
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_auto_reap_dead_threads
|
|
|
|
pool = new_pool(2,2) { Thread.current.kill }
|
|
|
|
|
|
|
|
assert_equal 2, pool.spawned
|
|
|
|
|
|
|
|
pool << 1
|
|
|
|
pool << 2
|
|
|
|
|
|
|
|
pause
|
|
|
|
|
|
|
|
assert_equal 2, pool.spawned
|
|
|
|
|
|
|
|
pool.auto_reap! 1
|
|
|
|
|
|
|
|
sleep 1
|
|
|
|
|
|
|
|
pause
|
|
|
|
|
|
|
|
assert_equal 0, pool.spawned
|
|
|
|
end
|
2011-09-20 01:16:31 -04:00
|
|
|
end
|