1
0
Fork 0
mirror of https://github.com/puma/puma.git synced 2022-11-09 13:48:40 -05:00
puma--puma/test/test_integration.rb

257 lines
5.7 KiB
Ruby
Raw Normal View History

require_relative "helper"
2011-12-07 16:43:16 -05:00
require "puma/cli"
require "puma/control_cli"
# These don't run on travis because they're too fragile
class TestIntegration < Minitest::Test
2011-12-07 16:43:16 -05:00
def setup
@state_path = "test/test_puma.state"
@bind_path = "test/test_server.sock"
@control_path = "test/test_control.sock"
@token = "xxyyzz"
@tcp_port = 9998
@server = nil
@script = nil
@wait, @ready = IO.pipe
@events = Puma::Events.strings
@events.on_booted { @ready << "!" }
2011-12-07 16:43:16 -05:00
end
def teardown
File.unlink @state_path rescue nil
File.unlink @bind_path rescue nil
File.unlink @control_path rescue nil
@wait.close
@ready.close
if @server
Process.kill "INT", @server.pid
2013-06-19 19:16:15 -04:00
begin
Process.wait @server.pid
rescue Errno::ECHILD
end
@server.close
end
if @script
@script.close!
end
end
def server(opts)
core = "#{Gem.ruby} -rubygems -Ilib bin/puma"
cmd = "#{core} --restart-cmd '#{core}' -b tcp://127.0.0.1:#{@tcp_port} #{opts}"
tf = Tempfile.new "puma-test"
tf.puts "exec #{cmd}"
tf.close
@script = tf
@server = IO.popen("sh #{tf.path}", "r")
wait_for_server_to_boot
@server
end
def signal(which)
Process.kill which, @server.pid
2011-12-07 16:43:16 -05:00
end
def wait_booted
@wait.sysread 1
end
# reuses an existing connection to make sure that works
def restart_server(connection)
signal :USR2
sleep 1
connection.write "GET / HTTP/1.1\r\n\r\n" # trigger it to start by sending a new request
assert_raises Errno::ECONNRESET do
Timeout.timeout(2) do
raise Errno::ECONNRESET unless connection.read(2)
end
end
wait_for_server_to_boot
end
def connect
s = TCPSocket.new "localhost", @tcp_port
s << "GET / HTTP/1.1\r\n\r\n"
true until s.gets == "\r\n"
s
end
def wait_for_server_to_boot
2017-05-29 20:52:04 -04:00
true while @server.gets !~ /Ctrl-C/ # wait for server to say it booted
sleep(Puma.jruby? ? 5 : 1) # TODO: not sure why that is needed ... something deterministic would be better
end
2011-12-07 16:43:16 -05:00
def test_stop_via_pumactl
2016-03-06 00:44:53 -05:00
if Puma.jruby? || Puma.windows?
2011-12-07 17:58:30 -05:00
assert true
return
end
conf = Puma::Configuration.new do |c|
c.quiet
c.state_path @state_path
c.bind "unix://#{@bind_path}"
c.activate_control_app "unix://#{@control_path}", :auth_token => @token
2017-04-11 17:08:18 -04:00
c.rackup "test/rackup/hello.ru"
end
l = Puma::Launcher.new conf, :events => @events
2011-12-07 16:43:16 -05:00
t = Thread.new do
Thread.current.abort_on_exception = true
l.run
2011-12-07 16:43:16 -05:00
end
wait_booted
2011-12-07 16:53:36 -05:00
s = UNIXSocket.new @bind_path
s << "GET / HTTP/1.0\r\n\r\n"
assert_equal "Hello World", s.read.split("\r\n").last
sout = StringIO.new
ccli = Puma::ControlCLI.new %W!-S #{@state_path} stop!, sout
2011-12-07 16:43:16 -05:00
ccli.run
2011-12-07 16:43:16 -05:00
assert_kind_of Thread, t.join(1), "server didn't stop"
2011-12-07 16:43:16 -05:00
end
def test_phased_restart_via_pumactl
skip("Too finicky, fails 50% of the time on CI.")
2016-03-06 00:44:53 -05:00
if Puma.jruby? || Puma.windows?
2015-01-15 07:58:16 -05:00
assert true
return
end
conf = Puma::Configuration.new do |c|
c.quiet
c.state_path @state_path
c.bind "unix://#{@bind_path}"
c.activate_control_app "unix://#{@control_path}", :auth_token => @token
c.workers 2
c.worker_shutdown_timeout 1
2017-04-11 17:08:18 -04:00
c.rackup "test/rackup/hello-stuck.ru"
end
l = Puma::Launcher.new conf, :events => @events
Thread.abort_on_exception = true
2015-01-15 07:58:16 -05:00
t = Thread.new do
Thread.current.abort_on_exception = true
l.run
2015-01-15 07:58:16 -05:00
end
wait_booted
# Make both workers stuck
s1 = UNIXSocket.new @bind_path
s1 << "GET / HTTP/1.0\r\n\r\n"
sout = StringIO.new
# Phased restart
ccli = Puma::ControlCLI.new %W!-S #{@state_path} phased-restart!, sout
ccli.run
sleep 20
@events.stdout.rewind
log = @events.stdout.readlines.join("")
assert_match(/TERM sent/, log)
assert_match(/- Worker \d \(pid: \d+\) booted, phase: 1/, log)
2015-01-15 07:58:16 -05:00
# Stop
ccli = Puma::ControlCLI.new %W!-S #{@state_path} stop!, sout
ccli.run
assert_kind_of Thread, t.join(5), "server didn't stop"
end
def test_kill_unknown_via_pumactl
if Puma.jruby? || Puma.windows?
assert true
return
end
# we run ls to get a 'safe' pid to pass off as puma in cli stop
# do not want to accidently kill a valid other process
io = IO.popen("ls")
safe_pid = io.pid
Process.wait safe_pid
sout = StringIO.new
e = assert_raises SystemExit do
ccli = Puma::ControlCLI.new %W!-p #{safe_pid} stop!, sout
ccli.run
end
sout.rewind
assert_match(/No pid '\d+' found/, sout.readlines.join(""))
assert_equal(1, e.status)
end
def test_restart_closes_keepalive_sockets
2017-04-11 17:08:18 -04:00
server("-q test/rackup/hello.ru")
s = connect
s.read
restart_server(s)
2016-03-06 00:44:53 -05:00
s = TCPSocket.new "127.0.0.1", @tcp_port
s << "GET / HTTP/1.0\r\n\r\n"
assert_equal "Hello World", s.read.split("\r\n").last
end
def test_restart_closes_keepalive_sockets_workers
2016-03-06 00:44:53 -05:00
if Puma.jruby?
assert true
return
end
2017-04-11 17:08:18 -04:00
server("-q -w 2 test/rackup/hello.ru")
2012-09-10 11:35:50 -04:00
s = connect
s.read
restart_server s
2012-09-10 11:35:50 -04:00
s = TCPSocket.new "localhost", @tcp_port
s << "GET / HTTP/1.0\r\n\r\n"
assert_equal "Hello World", s.read.split("\r\n").last
end
2012-09-10 11:35:50 -04:00
# It does not share environments between multiple generations, which would break Dotenv
def test_restart_restores_environment
server("-q test/rackup/hello-env.ru")
2012-09-10 11:35:50 -04:00
s = connect
initial_reply = s.read
restart_server(s)
2012-09-10 11:35:50 -04:00
s = TCPSocket.new "localhost", @tcp_port
s << "GET / HTTP/1.0\r\n\r\n"
new_reply = s.read.split("\r\n").last
assert_includes initial_reply, "Hello RAND"
assert_includes new_reply, "Hello RAND"
refute_equal initial_reply, new_reply
2012-09-10 11:35:50 -04:00
end
2016-03-06 00:44:53 -05:00
end