stream_input: read with zero length returns ''
[unicorn.git] / test / unit / test_stream_input.rb
blobadf45712a4d14569ae24c38712c893a3110df4bb
1 # -*- encoding: binary -*-
3 require 'test/unit'
4 require 'digest/sha1'
5 require 'unicorn'
7 class TestStreamInput < Test::Unit::TestCase
8   def setup
9     @rs = $/
10     @env = {}
11     @rd, @wr = Kgio::UNIXSocket.pair
12     @rd.sync = @wr.sync = true
13     @start_pid = $$
14   end
16   def teardown
17     return if $$ != @start_pid
18     $/ = @rs
19     @rd.close rescue nil
20     @wr.close rescue nil
21     Process.waitall
22   end
24   def test_read_small
25     r = init_request('hello')
26     si = Unicorn::StreamInput.new(@rd, r)
27     assert_equal 'hello', si.read
28     assert_equal '', si.read
29     assert_nil si.read(5)
30     assert_nil si.gets
31   end
33   def test_gets_oneliner
34     r = init_request('hello')
35     si = Unicorn::StreamInput.new(@rd, r)
36     assert_equal 'hello', si.gets
37     assert_nil si.gets
38   end
40   def test_gets_multiline
41     r = init_request("a\nb\n\n")
42     si = Unicorn::StreamInput.new(@rd, r)
43     assert_equal "a\n", si.gets
44     assert_equal "b\n", si.gets
45     assert_equal "\n", si.gets
46     assert_nil si.gets
47   end
49   def test_gets_empty_rs
50     $/ = nil
51     r = init_request("a\nb\n\n")
52     si = Unicorn::StreamInput.new(@rd, r)
53     assert_equal "a\nb\n\n", si.gets
54     assert_nil si.gets
55   end
57   def test_read_with_equal_len
58     r = init_request("abcde")
59     si = Unicorn::StreamInput.new(@rd, r)
60     assert_equal "abcde", si.read(5)
61     assert_nil si.read(5)
62   end
64   def test_big_body_multi
65     r = init_request('.', Unicorn::Const::MAX_BODY + 1)
66     si = Unicorn::StreamInput.new(@rd, r)
67     assert_equal Unicorn::Const::MAX_BODY, @parser.content_length
68     assert ! @parser.body_eof?
69     nr = Unicorn::Const::MAX_BODY / 4
70     pid = fork {
71       @rd.close
72       nr.times { @wr.write('....') }
73       @wr.close
74     }
75     @wr.close
76     assert_equal '.', si.read(1)
77     nr.times { |x|
78       assert_equal '....', si.read(4), "nr=#{x}"
79     }
80     assert_nil si.read(1)
81     status = nil
82     assert_nothing_raised { pid, status = Process.waitpid2(pid) }
83     assert status.success?
84   end
86   def test_gets_long
87     r = init_request("hello", 5 + (4096 * 4 * 3) + "#$/foo#$/".size)
88     si = Unicorn::StreamInput.new(@rd, r)
89     status = line = nil
90     pid = fork {
91       @rd.close
92       3.times { @wr.write("ffff" * 4096) }
93       @wr.write "#$/foo#$/"
94       @wr.close
95     }
96     @wr.close
97     assert_nothing_raised { line = si.gets }
98     assert_equal(4096 * 4 * 3 + 5 + $/.size, line.size)
99     assert_equal("hello" << ("ffff" * 4096 * 3) << "#$/", line)
100     assert_nothing_raised { line = si.gets }
101     assert_equal "foo#$/", line
102     assert_nil si.gets
103     assert_nothing_raised { pid, status = Process.waitpid2(pid) }
104     assert status.success?
105   end
107   def test_read_with_buffer
108     r = init_request('hello')
109     si = Unicorn::StreamInput.new(@rd, r)
110     buf = ''
111     rv = si.read(4, buf)
112     assert_equal 'hell', rv
113     assert_equal 'hell', buf
114     assert_equal rv.object_id, buf.object_id
115     assert_equal 'o', si.read
116     assert_equal nil, si.read(5, buf)
117   end
119   def test_read_with_buffer_clobbers
120     r = init_request('hello')
121     si = Unicorn::StreamInput.new(@rd, r)
122     buf = 'foo'
123     assert_equal 'hello', si.read(nil, buf)
124     assert_equal 'hello', buf
125     assert_equal '', si.read(nil, buf)
126     assert_equal '', buf
127     buf = 'asdf'
128     assert_nil si.read(5, buf)
129     assert_equal '', buf
130   end
132   def test_read_zero
133     r = init_request('hello')
134     si = Unicorn::StreamInput.new(@rd, r)
135     assert_equal '', si.read(0)
136     buf = 'asdf'
137     rv = si.read(0, buf)
138     assert_equal rv.object_id, buf.object_id
139     assert_equal '', buf
140     assert_equal 'hello', si.read
141     assert_nil si.read(5)
142     assert_equal '', si.read(0)
143     buf = 'hello'
144     rv = si.read(0, buf)
145     assert_equal rv.object_id, buf.object_id
146     assert_equal '', rv
147   end
149   def init_request(body, size = nil)
150     @parser = Unicorn::HttpParser.new
151     body = body.to_s.freeze
152     @buf = "POST / HTTP/1.1\r\n" \
153            "Host: localhost\r\n" \
154            "Content-Length: #{size || body.size}\r\n" \
155            "\r\n#{body}"
156     assert_equal @env, @parser.headers(@env, @buf)
157     assert_equal body, @buf
158     @parser
159   end