2017-05-12 15:16:55 -04:00
|
|
|
require_relative "helper"
|
2019-10-20 21:35:15 -04:00
|
|
|
require_relative "helpers/ssl"
|
2011-11-22 00:15:40 -05:00
|
|
|
|
2016-11-22 10:05:49 -05:00
|
|
|
require "puma/cli"
|
2019-05-21 08:43:18 -04:00
|
|
|
require "json"
|
2016-11-22 10:05:49 -05:00
|
|
|
|
|
|
|
class TestCLI < Minitest::Test
|
2019-10-20 21:35:15 -04:00
|
|
|
include SSLHelper
|
|
|
|
|
2011-11-22 00:15:40 -05:00
|
|
|
def setup
|
2012-07-05 16:38:06 -04:00
|
|
|
@environment = 'production'
|
2011-12-05 14:15:44 -05:00
|
|
|
@tmp_file = Tempfile.new("puma-test")
|
|
|
|
@tmp_path = @tmp_file.path
|
|
|
|
@tmp_file.close!
|
|
|
|
|
|
|
|
@tmp_path2 = "#{@tmp_path}2"
|
|
|
|
|
2019-08-10 11:14:11 -04:00
|
|
|
File.unlink @tmp_path if File.exist? @tmp_path
|
2011-12-05 14:15:44 -05:00
|
|
|
File.unlink @tmp_path2 if File.exist? @tmp_path2
|
2013-07-05 19:54:15 -04:00
|
|
|
|
|
|
|
@wait, @ready = IO.pipe
|
|
|
|
|
2016-02-03 15:06:00 -05:00
|
|
|
@events = Puma::Events.strings
|
2013-07-05 19:54:15 -04:00
|
|
|
@events.on_booted { @ready << "!" }
|
|
|
|
end
|
|
|
|
|
|
|
|
def wait_booted
|
|
|
|
@wait.sysread 1
|
2011-12-05 14:15:44 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def teardown
|
|
|
|
File.unlink @tmp_path if File.exist? @tmp_path
|
|
|
|
File.unlink @tmp_path2 if File.exist? @tmp_path2
|
2013-07-05 19:54:15 -04:00
|
|
|
|
|
|
|
@wait.close
|
|
|
|
@ready.close
|
2011-11-22 00:15:40 -05:00
|
|
|
end
|
|
|
|
|
2012-06-21 12:01:18 -04:00
|
|
|
def test_control_for_tcp
|
2019-08-12 06:32:46 -04:00
|
|
|
tcp = UniquePort.call
|
|
|
|
cntl = UniquePort.call
|
2019-02-20 15:29:52 -05:00
|
|
|
url = "tcp://127.0.0.1:#{cntl}/"
|
|
|
|
|
|
|
|
cli = Puma::CLI.new ["-b", "tcp://127.0.0.1:#{tcp}",
|
2019-10-12 04:32:43 -04:00
|
|
|
"--control-url", url,
|
2012-06-21 12:01:18 -04:00
|
|
|
"--control-token", "",
|
2017-04-11 17:08:18 -04:00
|
|
|
"test/rackup/lobster.ru"], @events
|
2013-07-05 19:54:15 -04:00
|
|
|
|
2012-06-21 12:01:18 -04:00
|
|
|
t = Thread.new do
|
2016-09-05 14:28:52 -04:00
|
|
|
cli.run
|
2015-03-13 19:08:07 -04:00
|
|
|
end
|
2012-06-21 12:01:18 -04:00
|
|
|
|
2013-07-05 19:54:15 -04:00
|
|
|
wait_booted
|
2012-06-21 12:01:18 -04:00
|
|
|
|
2019-02-20 15:29:52 -05:00
|
|
|
s = TCPSocket.new "127.0.0.1", cntl
|
2012-06-21 12:01:18 -04:00
|
|
|
s << "GET /stats HTTP/1.0\r\n\r\n"
|
|
|
|
body = s.read
|
2019-02-20 15:29:52 -05:00
|
|
|
s.close
|
|
|
|
|
2019-08-10 11:14:11 -04:00
|
|
|
assert_match(/{ "started_at": "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", "backlog": 0, "running": 0, "pool_capacity": 16, "max_threads": 16 }/, body.split(/\r?\n/).last)
|
|
|
|
assert_match(/{ "started_at": "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", "backlog": 0, "running": 0, "pool_capacity": 16, "max_threads": 16 }/, Puma.stats)
|
2012-06-21 12:01:18 -04:00
|
|
|
|
2019-02-20 15:29:52 -05:00
|
|
|
ensure
|
2016-02-06 22:00:29 -05:00
|
|
|
cli.launcher.stop
|
2012-06-21 12:01:18 -04:00
|
|
|
t.join
|
|
|
|
end
|
|
|
|
|
2019-10-20 21:35:15 -04:00
|
|
|
def test_control_for_ssl
|
|
|
|
app_port = UniquePort.call
|
|
|
|
control_port = UniquePort.call
|
|
|
|
control_host = "127.0.0.1"
|
|
|
|
control_url = "ssl://#{control_host}:#{control_port}?#{ssl_query}"
|
|
|
|
token = "token"
|
|
|
|
|
|
|
|
cli = Puma::CLI.new ["-b", "tcp://127.0.0.1:#{app_port}",
|
|
|
|
"--control-url", control_url,
|
|
|
|
"--control-token", token,
|
|
|
|
"test/rackup/lobster.ru"], @events
|
|
|
|
|
|
|
|
t = Thread.new do
|
|
|
|
cli.run
|
|
|
|
end
|
|
|
|
|
|
|
|
wait_booted
|
|
|
|
|
|
|
|
body = ""
|
|
|
|
http = Net::HTTP.new control_host, control_port
|
|
|
|
http.use_ssl = true
|
|
|
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
|
|
http.start do
|
|
|
|
req = Net::HTTP::Get.new "/stats?token=#{token}", {}
|
|
|
|
body = http.request(req).body
|
|
|
|
end
|
|
|
|
|
|
|
|
expected_stats = /{ "started_at": "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", "backlog": 0, "running": 0, "pool_capacity": 16, "max_threads": 16 }/
|
|
|
|
assert_match(expected_stats, body.split(/\r?\n/).last)
|
|
|
|
assert_match(expected_stats, Puma.stats)
|
|
|
|
|
|
|
|
ensure
|
|
|
|
cli.launcher.stop
|
|
|
|
t.join
|
|
|
|
end
|
|
|
|
|
2016-02-18 14:35:14 -05:00
|
|
|
def test_control_clustered
|
2019-02-20 15:29:52 -05:00
|
|
|
skip NO_FORK_MSG unless HAS_FORK
|
|
|
|
skip UNIX_SKT_MSG unless UNIX_SKT_EXIST
|
2016-02-18 14:35:14 -05:00
|
|
|
url = "unix://#{@tmp_path}"
|
|
|
|
|
|
|
|
cli = Puma::CLI.new ["-b", "unix://#{@tmp_path2}",
|
|
|
|
"-t", "2:2",
|
|
|
|
"-w", "2",
|
2019-10-12 04:32:43 -04:00
|
|
|
"--control-url", url,
|
2016-02-18 14:35:14 -05:00
|
|
|
"--control-token", "",
|
2017-04-11 17:08:18 -04:00
|
|
|
"test/rackup/lobster.ru"], @events
|
2016-02-18 14:35:14 -05:00
|
|
|
|
2019-09-19 13:37:53 -04:00
|
|
|
# without this, Minitest.after_run will trigger on this test ?
|
|
|
|
$debugging_hold = true
|
|
|
|
|
2016-02-18 14:35:14 -05:00
|
|
|
t = Thread.new { cli.run }
|
|
|
|
|
|
|
|
wait_booted
|
|
|
|
|
|
|
|
s = UNIXSocket.new @tmp_path
|
|
|
|
s << "GET /stats HTTP/1.0\r\n\r\n"
|
|
|
|
body = s.read
|
2019-09-19 13:37:53 -04:00
|
|
|
s.close
|
2016-02-18 14:35:14 -05:00
|
|
|
|
2016-09-05 14:28:52 -04:00
|
|
|
require 'json'
|
|
|
|
status = JSON.parse(body.split("\n").last)
|
|
|
|
|
|
|
|
assert_equal 2, status["workers"]
|
2016-02-18 14:35:14 -05:00
|
|
|
|
|
|
|
# wait until the first status ping has come through
|
|
|
|
sleep 6
|
|
|
|
s = UNIXSocket.new @tmp_path
|
|
|
|
s << "GET /stats HTTP/1.0\r\n\r\n"
|
|
|
|
body = s.read
|
2019-09-19 13:37:53 -04:00
|
|
|
s.close
|
2016-02-18 14:35:14 -05:00
|
|
|
|
2019-09-19 13:37:53 -04:00
|
|
|
assert_match(/\{ "started_at": "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", "workers": 2, "phase": 0, "booted_workers": 2, "old_workers": 0, "worker_status": \[\{ "started_at": "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", "pid": \d+, "index": 0, "phase": 0, "booted": true, "last_checkin": "[^"]+", "last_status": \{ "backlog":0, "running":2, "pool_capacity":2, "max_threads": 2 \} \},\{ "started_at": "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", "pid": \d+, "index": 1, "phase": 0, "booted": true, "last_checkin": "[^"]+", "last_status": \{ "backlog":0, "running":2, "pool_capacity":2, "max_threads": 2 \} \}\] \}/, body.split("\r\n").last)
|
|
|
|
ensure
|
|
|
|
if UNIX_SKT_EXIST && HAS_FORK
|
|
|
|
cli.launcher.stop
|
|
|
|
|
|
|
|
done = nil
|
|
|
|
until done
|
|
|
|
@events.stdout.rewind
|
|
|
|
log = @events.stdout.readlines.join ''
|
|
|
|
done = log[/ - Goodbye!/]
|
|
|
|
end
|
|
|
|
|
|
|
|
t.join
|
|
|
|
$debugging_hold = false
|
|
|
|
end
|
2016-02-18 14:35:14 -05:00
|
|
|
end
|
|
|
|
|
2011-12-06 17:56:38 -05:00
|
|
|
def test_control
|
2019-02-20 15:29:52 -05:00
|
|
|
skip UNIX_SKT_MSG unless UNIX_SKT_EXIST
|
2011-12-05 14:15:44 -05:00
|
|
|
url = "unix://#{@tmp_path}"
|
|
|
|
|
2011-12-07 13:46:36 -05:00
|
|
|
cli = Puma::CLI.new ["-b", "unix://#{@tmp_path2}",
|
2019-10-12 04:32:43 -04:00
|
|
|
"--control-url", url,
|
2011-12-07 13:46:36 -05:00
|
|
|
"--control-token", "",
|
2017-04-11 17:08:18 -04:00
|
|
|
"test/rackup/lobster.ru"], @events
|
2011-12-05 14:15:44 -05:00
|
|
|
|
|
|
|
t = Thread.new { cli.run }
|
|
|
|
|
2013-07-05 19:54:15 -04:00
|
|
|
wait_booted
|
2011-12-05 14:15:44 -05:00
|
|
|
|
|
|
|
s = UNIXSocket.new @tmp_path
|
|
|
|
s << "GET /stats HTTP/1.0\r\n\r\n"
|
|
|
|
body = s.read
|
2019-09-19 13:37:53 -04:00
|
|
|
s.close
|
2011-12-05 14:15:44 -05:00
|
|
|
|
2019-08-10 11:14:11 -04:00
|
|
|
assert_match(/{ "started_at": "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", "backlog": 0, "running": 0, "pool_capacity": 16, "max_threads": 16 }/, body.split("\r\n").last)
|
2019-09-19 13:37:53 -04:00
|
|
|
ensure
|
|
|
|
if UNIX_SKT_EXIST
|
|
|
|
cli.launcher.stop
|
|
|
|
t.join
|
|
|
|
end
|
2011-12-05 14:15:44 -05:00
|
|
|
end
|
|
|
|
|
2011-12-06 17:56:38 -05:00
|
|
|
def test_control_stop
|
2019-02-20 15:29:52 -05:00
|
|
|
skip UNIX_SKT_MSG unless UNIX_SKT_EXIST
|
2011-12-05 14:15:44 -05:00
|
|
|
url = "unix://#{@tmp_path}"
|
|
|
|
|
2011-12-07 13:46:36 -05:00
|
|
|
cli = Puma::CLI.new ["-b", "unix://#{@tmp_path2}",
|
2019-10-12 04:32:43 -04:00
|
|
|
"--control-url", url,
|
2011-12-07 13:46:36 -05:00
|
|
|
"--control-token", "",
|
2017-04-11 17:08:18 -04:00
|
|
|
"test/rackup/lobster.ru"], @events
|
2011-12-05 14:15:44 -05:00
|
|
|
|
|
|
|
t = Thread.new { cli.run }
|
|
|
|
|
2013-07-05 19:54:15 -04:00
|
|
|
wait_booted
|
2011-12-05 14:15:44 -05:00
|
|
|
|
|
|
|
s = UNIXSocket.new @tmp_path
|
|
|
|
s << "GET /stop HTTP/1.0\r\n\r\n"
|
|
|
|
body = s.read
|
2019-09-19 13:37:53 -04:00
|
|
|
s.close
|
2011-12-05 14:15:44 -05:00
|
|
|
|
|
|
|
assert_equal '{ "status": "ok" }', body.split("\r\n").last
|
2019-09-19 13:37:53 -04:00
|
|
|
ensure
|
|
|
|
t.join if UNIX_SKT_EXIST
|
2011-12-05 14:15:44 -05:00
|
|
|
end
|
|
|
|
|
2019-02-20 15:29:52 -05:00
|
|
|
def control_gc_stats(uri, cntl)
|
|
|
|
cli = Puma::CLI.new ["-b", uri,
|
2019-10-12 04:32:43 -04:00
|
|
|
"--control-url", cntl,
|
2017-08-03 17:46:49 -04:00
|
|
|
"--control-token", "",
|
|
|
|
"test/rackup/lobster.ru"], @events
|
|
|
|
|
2019-02-20 15:29:52 -05:00
|
|
|
t = Thread.new do
|
|
|
|
cli.run
|
|
|
|
end
|
2017-08-03 17:46:49 -04:00
|
|
|
|
|
|
|
wait_booted
|
|
|
|
|
2019-02-20 15:29:52 -05:00
|
|
|
s = yield
|
2017-08-03 17:46:49 -04:00
|
|
|
s << "GET /gc-stats HTTP/1.0\r\n\r\n"
|
|
|
|
body = s.read
|
|
|
|
s.close
|
|
|
|
|
|
|
|
lines = body.split("\r\n")
|
|
|
|
json_line = lines.detect { |l| l[0] == "{" }
|
|
|
|
pairs = json_line.scan(/\"[^\"]+\": [^,]+/)
|
|
|
|
gc_stats = {}
|
|
|
|
pairs.each do |p|
|
|
|
|
p =~ /\"([^\"]+)\": ([^,]+)/ || raise("Can't parse #{p.inspect}!")
|
|
|
|
gc_stats[$1] = $2
|
|
|
|
end
|
|
|
|
gc_count_before = gc_stats["count"].to_i
|
|
|
|
|
2019-02-20 15:29:52 -05:00
|
|
|
s = yield
|
2017-08-03 17:46:49 -04:00
|
|
|
s << "GET /gc HTTP/1.0\r\n\r\n"
|
|
|
|
body = s.read # Ignored
|
|
|
|
s.close
|
|
|
|
|
2019-02-20 15:29:52 -05:00
|
|
|
s = yield
|
2017-08-03 17:46:49 -04:00
|
|
|
s << "GET /gc-stats HTTP/1.0\r\n\r\n"
|
|
|
|
body = s.read
|
|
|
|
s.close
|
2019-02-20 15:29:52 -05:00
|
|
|
|
2017-08-03 17:46:49 -04:00
|
|
|
lines = body.split("\r\n")
|
|
|
|
json_line = lines.detect { |l| l[0] == "{" }
|
2019-05-21 08:43:18 -04:00
|
|
|
gc_stats = JSON.parse(json_line)
|
2017-08-03 17:46:49 -04:00
|
|
|
gc_count_after = gc_stats["count"].to_i
|
|
|
|
|
|
|
|
# Hitting the /gc route should increment the count by 1
|
2019-02-20 13:19:50 -05:00
|
|
|
assert(gc_count_before < gc_count_after, "make sure a gc has happened")
|
2017-08-03 17:46:49 -04:00
|
|
|
|
2019-02-20 15:29:52 -05:00
|
|
|
ensure
|
|
|
|
cli.launcher.stop if cli
|
2017-08-03 17:46:49 -04:00
|
|
|
t.join
|
|
|
|
end
|
|
|
|
|
2019-02-20 15:29:52 -05:00
|
|
|
def test_control_gc_stats_tcp
|
|
|
|
skip_on :jruby, suffix: " - Hitting /gc route does not increment count"
|
2019-08-12 06:32:46 -04:00
|
|
|
uri = "tcp://127.0.0.1:#{UniquePort.call}/"
|
|
|
|
cntl_port = UniquePort.call
|
2019-02-20 15:29:52 -05:00
|
|
|
cntl = "tcp://127.0.0.1:#{cntl_port}/"
|
|
|
|
|
|
|
|
control_gc_stats(uri, cntl) { TCPSocket.new "127.0.0.1", cntl_port }
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_control_gc_stats_unix
|
|
|
|
skip_on :jruby, suffix: " - Hitting /gc route does not increment count"
|
|
|
|
skip UNIX_SKT_MSG unless UNIX_SKT_EXIST
|
|
|
|
|
|
|
|
uri = "unix://#{@tmp_path2}"
|
|
|
|
cntl = "unix://#{@tmp_path}"
|
|
|
|
|
|
|
|
control_gc_stats(uri, cntl) { UNIXSocket.new @tmp_path }
|
|
|
|
end
|
|
|
|
|
2011-12-06 17:56:38 -05:00
|
|
|
def test_tmp_control
|
2019-02-20 15:29:52 -05:00
|
|
|
skip_on :jruby, suffix: " - Unknown issue"
|
|
|
|
|
2019-10-12 04:32:43 -04:00
|
|
|
cli = Puma::CLI.new ["--state", @tmp_path, "--control-url", "auto"]
|
2016-02-06 22:00:29 -05:00
|
|
|
cli.launcher.write_state
|
2011-12-05 14:32:18 -05:00
|
|
|
|
2012-01-08 15:46:10 -05:00
|
|
|
data = YAML.load File.read(@tmp_path)
|
2011-12-05 14:32:18 -05:00
|
|
|
|
|
|
|
assert_equal Process.pid, data["pid"]
|
|
|
|
|
2016-02-06 22:00:29 -05:00
|
|
|
url = data["control_url"]
|
2011-12-05 14:32:18 -05:00
|
|
|
|
|
|
|
m = %r!unix://(.*)!.match(url)
|
|
|
|
|
|
|
|
assert m, "'#{url}' is not a URL"
|
|
|
|
end
|
2012-04-30 19:44:03 -04:00
|
|
|
|
2015-12-10 03:01:47 -05:00
|
|
|
def test_state_file_callback_filtering
|
2019-02-20 15:29:52 -05:00
|
|
|
skip NO_FORK_MSG unless HAS_FORK
|
2016-02-04 10:49:01 -05:00
|
|
|
cli = Puma::CLI.new [ "--config", "test/config/state_file_testing_config.rb",
|
2015-12-10 03:01:47 -05:00
|
|
|
"--state", @tmp_path ]
|
2016-02-06 22:00:29 -05:00
|
|
|
cli.launcher.write_state
|
2015-12-10 03:01:47 -05:00
|
|
|
|
2016-11-22 10:05:49 -05:00
|
|
|
data = YAML.load_file(@tmp_path)
|
2015-12-10 03:01:47 -05:00
|
|
|
|
|
|
|
keys_not_stripped = data.keys & Puma::CLI::KEYS_NOT_TO_PERSIST_IN_STATE
|
|
|
|
assert_empty keys_not_stripped
|
|
|
|
end
|
|
|
|
|
2019-08-01 15:21:23 -04:00
|
|
|
def test_log_formatter_default_single
|
|
|
|
cli = Puma::CLI.new [ ]
|
|
|
|
assert_instance_of Puma::Events::DefaultFormatter, cli.launcher.events.formatter
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_log_formatter_default_clustered
|
|
|
|
skip NO_FORK_MSG unless HAS_FORK
|
|
|
|
|
|
|
|
cli = Puma::CLI.new [ "-w 2" ]
|
|
|
|
assert_instance_of Puma::Events::PidFormatter, cli.launcher.events.formatter
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_log_formatter_custom_single
|
|
|
|
cli = Puma::CLI.new [ "--config", "test/config/custom_log_formatter.rb" ]
|
|
|
|
assert_instance_of Proc, cli.launcher.events.formatter
|
|
|
|
assert_match(/^\[.*\] \[.*\] .*: test$/, cli.launcher.events.format('test'))
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_log_formatter_custom_clustered
|
|
|
|
skip NO_FORK_MSG unless HAS_FORK
|
|
|
|
|
|
|
|
cli = Puma::CLI.new [ "--config", "test/config/custom_log_formatter.rb", "-w 2" ]
|
|
|
|
assert_instance_of Proc, cli.launcher.events.formatter
|
|
|
|
assert_match(/^\[.*\] \[.*\] .*: test$/, cli.launcher.events.format('test'))
|
|
|
|
end
|
|
|
|
|
2016-01-28 00:08:04 -05:00
|
|
|
def test_state
|
2019-08-12 06:32:46 -04:00
|
|
|
url = "tcp://127.0.0.1:#{UniquePort.call}"
|
2019-10-12 04:32:43 -04:00
|
|
|
cli = Puma::CLI.new ["--state", @tmp_path, "--control-url", url]
|
2016-02-06 22:00:29 -05:00
|
|
|
cli.launcher.write_state
|
2016-01-28 00:08:04 -05:00
|
|
|
|
|
|
|
data = YAML.load File.read(@tmp_path)
|
|
|
|
|
|
|
|
assert_equal Process.pid, data["pid"]
|
2016-02-06 22:00:29 -05:00
|
|
|
assert_equal url, data["control_url"]
|
2016-01-28 00:08:04 -05:00
|
|
|
end
|
|
|
|
|
2012-04-30 19:44:03 -04:00
|
|
|
def test_load_path
|
2018-03-12 12:41:03 -04:00
|
|
|
Puma::CLI.new ["--include", 'foo/bar']
|
2012-04-30 19:44:03 -04:00
|
|
|
|
|
|
|
assert_equal 'foo/bar', $LOAD_PATH[0]
|
|
|
|
$LOAD_PATH.shift
|
|
|
|
|
2018-03-12 12:41:03 -04:00
|
|
|
Puma::CLI.new ["--include", 'foo/bar:baz/qux']
|
2012-04-30 19:44:03 -04:00
|
|
|
|
|
|
|
assert_equal 'foo/bar', $LOAD_PATH[0]
|
|
|
|
$LOAD_PATH.shift
|
|
|
|
assert_equal 'baz/qux', $LOAD_PATH[0]
|
|
|
|
$LOAD_PATH.shift
|
|
|
|
end
|
2012-07-05 16:38:06 -04:00
|
|
|
|
|
|
|
def test_environment
|
2016-02-06 22:00:29 -05:00
|
|
|
ENV.delete 'RACK_ENV'
|
|
|
|
|
|
|
|
Puma::CLI.new ["--environment", @environment]
|
2012-07-05 16:38:06 -04:00
|
|
|
|
2015-03-13 19:08:07 -04:00
|
|
|
assert_equal ENV['RACK_ENV'], @environment
|
2012-07-05 16:38:06 -04:00
|
|
|
end
|
2011-11-22 00:15:40 -05:00
|
|
|
end
|