Mongrel.run(app, opts)
[unicorn.git] / test / unit / test_server.rb
blob4ce728d87988066761eb76a4b1010c3c8de3361f
1 # Copyright (c) 2005 Zed A. Shaw 
2 # You can redistribute it and/or modify it under the same terms as Ruby.
4 # Additional work donated by contributors.  See http://mongrel.rubyforge.org/attributions.html 
5 # for more information.
7 require 'test/test_helper'
9 include Mongrel
11 class TestHandler 
12   attr_reader :ran_test
14   def call(env) 
15     @ran_test = true
16   #   response.socket.write("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nhello!\n")
17     [200, { 'Content-Type' => 'text/plain' }, ['hello!\n']]
18    end
19 end
22 class WebServerTest < Test::Unit::TestCase
24   def setup
25     @valid_request = "GET / HTTP/1.1\r\nHost: www.zedshaw.com\r\nContent-Type: text/plain\r\n\r\n"
26     @port = process_based_port
27     @tester = TestHandler.new 
28     @app = Rack::URLMap.new('/test' => @tester)
29     redirect_test_io do
30       # We set max_queued_threads=1 so that we can test the reaping code
31       @server = HttpServer.new(@app, :Host => "127.0.0.1", :Port => @port, :Max_queued_threads => 1)
32     end
33     @server.start
34   end
36   def teardown
37     redirect_test_io do
38       @server.stop(true)
39     end
40   end
42   def test_simple_server
43     hit(["http://localhost:#{@port}/test"])
44     assert @tester.ran_test, "Handler didn't really run"
45   end
48   def do_test(string, chunk, close_after=nil, shutdown_delay=0)
49     # Do not use instance variables here, because it needs to be thread safe
50     socket = TCPSocket.new("127.0.0.1", @port);
51     request = StringIO.new(string)
52     chunks_out = 0
54     while data = request.read(chunk)
55       chunks_out += socket.write(data)
56       socket.flush
57       sleep 0.2
58       if close_after and chunks_out > close_after
59         socket.close
60         sleep 1
61       end
62     end
63     sleep(shutdown_delay)
64     socket.write(" ") # Some platforms only raise the exception on attempted write
65     socket.flush
66   end
68   def test_trickle_attack
69     do_test(@valid_request, 3)
70   end
72   def test_close_client
73     assert_raises IOError do
74       do_test(@valid_request, 10, 20)
75     end
76   end
78   def test_bad_client
79     redirect_test_io do
80       do_test("GET /test HTTP/BAD", 3)
81     end
82   end
84   def test_header_is_too_long
85     redirect_test_io do
86       long = "GET /test HTTP/1.1\r\n" + ("X-Big: stuff\r\n" * 15000) + "\r\n"
87       assert_raises Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::EINVAL, IOError do
88         do_test(long, long.length/2, 10)
89       end
90     end
91   end
93   def test_max_queued_threads_overload
94     redirect_test_io do
95       assert_raises Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::EINVAL, IOError do
96         tests = [
97           Thread.new { do_test(@valid_request, 1) },
98           Thread.new { do_test(@valid_request, 10) },
99         ]
101         tests.each {|t| t.join}
102       end
103     end
104   end
106   def test_file_streamed_request
107     body = "a" * (Mongrel::Const::MAX_BODY * 2)
108     long = "GET /test HTTP/1.1\r\nContent-length: #{body.length}\r\n\r\n" + body
109     do_test(long, Mongrel::Const::CHUNK_SIZE * 2 -400)
110   end