1 # -*- encoding: binary -*-
2 # frozen_string_literal: false
4 # Copyright (c) 2009 Eric Wong
5 # You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
6 # the GPLv2+ (GPLv3+ preferred)
8 # Ensure we stay sane in the face of signals being sent to us
10 require './test/test_helper'
15 def initialize(bs, count)
21 @count.times { yield @buf }
25 class SignalsTest < Test::Unit::TestCase
31 @sock = Tempfile.new('unicorn.sock')
32 @tmp = Tempfile.new('unicorn.write')
34 File.unlink(@sock.path)
35 File.unlink(@tmp.path)
37 :listeners => [ "127.0.0.1:#@port", @sock.path ],
38 :after_fork => lambda { |server,worker|
39 trap(:HUP) { @tmp.syswrite('.') }
49 def test_worker_dies_on_dead_master
51 app = lambda { |env| [ 200, {'x-pid' => "#$$" }, [] ] }
52 opts = @server_opts.merge(:timeout => 3)
53 redirect_test_io { HttpServer.new(app, opts).start.join }
55 wait_workers_ready("test_stderr.#{pid}.log", 1)
56 sock = tcp_socket('127.0.0.1', @port)
57 sock.syswrite("GET / HTTP/1.0\r\n\r\n")
58 buf = sock.readpartial(4096)
60 buf =~ /\bx-pid: (\d+)\b/ or raise Exception
62 wait_master_ready("test_stderr.#{pid}.log")
63 wait_workers_ready("test_stderr.#{pid}.log", 1)
64 Process.kill(:KILL, pid)
66 File.unlink("test_stderr.#{pid}.log", "test_stdout.#{pid}.log")
70 assert_raises(Errno::ESRCH) { loop { Process.kill(0, child); sleep 0.2 } }
71 assert((Time.now - t0) < 60)
78 app = lambda { |env| wr.syswrite('.'); sleep; [ 200, {}, [] ] }
79 redirect_test_io { HttpServer.new(app, @server_opts).start.join }
82 wait_workers_ready("test_stderr.#{pid}.log", 1)
83 sock = tcp_socket('127.0.0.1', @port)
84 sock.syswrite("GET / HTTP/1.0\r\n\r\n")
85 buf = rd.readpartial(1)
86 wait_master_ready("test_stderr.#{pid}.log")
87 Process.kill(:INT, pid)
91 assert_raises(EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,
93 buf = sock.sysread(4096)
98 def test_timeout_slow_response
100 app = lambda { |env| sleep }
101 opts = @server_opts.merge(:timeout => 3)
102 redirect_test_io { HttpServer.new(app, opts).start.join }
105 wait_workers_ready("test_stderr.#{pid}.log", 1)
106 sock = tcp_socket('127.0.0.1', @port)
107 sock.syswrite("GET / HTTP/1.0\r\n\r\n")
110 assert_raises(EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,
112 buf = sock.sysread(4096)
116 assert diff > 1.0, "diff was #{diff.inspect}"
119 Process.kill(:TERM, pid) rescue nil
122 def test_response_write
124 [ 200, { 'content-type' => 'text/plain', 'x-pid' => Process.pid.to_s },
125 Dd.new(@bs, @count) ]
127 redirect_test_io { @server = HttpServer.new(app, @server_opts).start }
128 wait_workers_ready("test_stderr.#{$$}.log", 1)
129 sock = tcp_socket('127.0.0.1', @port)
130 sock.syswrite("GET / HTTP/1.0\r\n\r\n")
132 header_len = pid = nil
133 buf = sock.sysread(16384, buf)
134 pid = buf[/\r\nx-pid: (\d+)\r\n/, 1].to_i
135 header_len = buf[/\A(.+?\r\n\r\n)/m, 1].size
136 assert pid > 0, "pid not positive: #{pid.inspect}"
138 size_before = @tmp.stat.size
139 assert_raises(EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,
142 3.times { Process.kill(:HUP, pid) }
143 sock.sysread(16384, buf)
145 3.times { Process.kill(:HUP, pid) }
149 redirect_test_io { @server.stop(true) }
150 # can't check for == since pending signals get merged
151 assert size_before < @tmp.stat.size
152 got = read - header_len
153 expect = @bs * @count
154 assert_equal(expect, got, "expect=#{expect} got=#{got}")
155 assert_nil sock.close
158 def test_request_read
160 while env['rack.input'].read(4096)
162 [ 200, {'content-type'=>'text/plain', 'x-pid'=>Process.pid.to_s}, [] ]
164 redirect_test_io { @server = HttpServer.new(app, @server_opts).start }
166 wait_workers_ready("test_stderr.#{$$}.log", 1)
167 sock = tcp_socket('127.0.0.1', @port)
168 sock.syswrite("GET / HTTP/1.0\r\n\r\n")
169 pid = sock.sysread(4096)[/\r\nx-pid: (\d+)\r\n/, 1].to_i
170 assert_nil sock.close
172 assert pid > 0, "pid not positive: #{pid.inspect}"
173 sock = tcp_socket('127.0.0.1', @port)
174 sock.syswrite("PUT / HTTP/1.0\r\n")
175 sock.syswrite("Content-Length: #{@bs * @count}\r\n\r\n")
176 1000.times { Process.kill(:HUP, pid) }
177 size_before = @tmp.stat.size
178 killer = fork { loop { Process.kill(:HUP, pid); sleep(0.01) } }
180 @count.times { sock.syswrite(buf) }
181 Process.kill(:KILL, killer)
182 Process.waitpid2(killer)
183 redirect_test_io { @server.stop(true) }
184 # can't check for == since pending signals get merged
185 assert size_before < @tmp.stat.size
186 assert_equal pid, sock.sysread(4096)[/\r\nx-pid: (\d+)\r\n/, 1].to_i
187 assert_nil sock.close