kgio 1.3.1 - fix zero-length reads
[kgio.git] / test / lib_read_write.rb
blob6f90041355beba30537618350f6e8eda9458e225
1 # -*- encoding: binary -*-
2 require 'test/unit'
3 require 'io/nonblock'
4 require 'digest/sha1'
5 $-w = true
6 require 'kgio'
8 module LibReadWriteTest
9   RANDOM_BLOB = File.open("/dev/urandom") { |fp| fp.read(10 * 1024 * 1024) }
11   def teardown
12     assert_nothing_raised do
13       @rd.close unless @rd.closed?
14       @wr.close unless @wr.closed?
15     end
16     assert_nothing_raised do
17       Kgio.wait_readable = Kgio.wait_writable = nil
18     end
19   end
21   def test_read_zero
22     assert_equal "", @rd.kgio_read(0)
23     buf = "foo"
24     assert_equal buf.object_id, @rd.kgio_read(0, buf).object_id
25     assert_equal "", buf
26   end
28   def test_tryread_zero
29     assert_equal "", @rd.kgio_tryread(0)
30     buf = "foo"
31     assert_equal buf.object_id, @rd.kgio_tryread(0, buf).object_id
32     assert_equal "", buf
33   end
35   def test_read_eof
36     @wr.close
37     assert_nil @rd.kgio_read(5)
38   end
40   def test_read_bang_eof
41     @wr.close
42     begin
43       @rd.kgio_read!(5)
44       assert false, "should never get here (line:#{__LINE__})"
45     rescue EOFError => e
46       assert_equal [], e.backtrace
47     end
48   end
50   def test_tryread_eof
51     @wr.close
52     assert_nil @rd.kgio_tryread(5)
53   end
55   def test_write_closed
56     @rd.close
57     begin
58       loop { @wr.kgio_write "HI" }
59     rescue Errno::EPIPE, Errno::ECONNRESET => e
60       assert_equal [], e.backtrace
61       return
62     end
63     assert false, "should never get here (line:#{__LINE__})"
64   end
66   def test_trywrite_closed
67     @rd.close
68     begin
69       loop { @wr.kgio_trywrite "HI" }
70     rescue Errno::EPIPE, Errno::ECONNRESET => e
71       assert_equal [], e.backtrace
72       return
73     end
74     assert false, "should never get here (line:#{__LINE__})"
75   end
77   def test_trywrite_full
78     buf = "\302\251" * 1024 * 1024
79     buf2 = ""
80     dig = Digest::SHA1.new
81     t = Thread.new do
82       sleep 1
83       nr = 0
84       begin
85         dig.update(@rd.readpartial(4096, buf2))
86         nr += buf2.size
87       rescue EOFError
88         break
89       rescue => e
90       end while true
91       dig.hexdigest
92     end
93     50.times do
94       wr = buf
95       begin
96         rv = @wr.kgio_trywrite(wr)
97         case rv
98         when String
99           wr = rv
100         when Kgio::WaitReadable
101           assert false, "should never get here line=#{__LINE__}"
102         when Kgio::WaitWritable
103           IO.select(nil, [ @wr ])
104         else
105           wr = false
106         end
107       end while wr
108     end
109     @wr.close
110     t.join
111     assert_equal '8ff79d8115f9fe38d18be858c66aa08a1cc27a66', t.value
112   end
114   def test_write_conv
115     assert_equal nil, @wr.kgio_write(10)
116     assert_equal "10", @rd.kgio_read(2)
117   end
119   def test_trywrite_conv
120     assert_equal nil, @wr.kgio_trywrite(10)
121     assert_equal "10", @rd.kgio_tryread(2)
122   end
124   def test_tryread_empty
125     assert_equal Kgio::WaitReadable, @rd.kgio_tryread(1)
126   end
128   def test_read_too_much
129     assert_equal nil, @wr.kgio_write("hi")
130     assert_equal "hi", @rd.kgio_read(4)
131   end
133   def test_tryread_too_much
134     assert_equal nil, @wr.kgio_trywrite("hi")
135     assert_equal "hi", @rd.kgio_tryread(4)
136   end
138   def test_read_short
139     assert_equal nil, @wr.kgio_write("hi")
140     assert_equal "h", @rd.kgio_read(1)
141     assert_equal "i", @rd.kgio_read(1)
142   end
144   def test_tryread_short
145     assert_equal nil, @wr.kgio_trywrite("hi")
146     assert_equal "h", @rd.kgio_tryread(1)
147     assert_equal "i", @rd.kgio_tryread(1)
148   end
150   def test_read_extra_buf
151     tmp = ""
152     tmp_object_id = tmp.object_id
153     assert_equal nil, @wr.kgio_write("hi")
154     rv = @rd.kgio_read(2, tmp)
155     assert_equal "hi", rv
156     assert_equal rv.object_id, tmp.object_id
157     assert_equal tmp_object_id, rv.object_id
158   end
160   def test_trywrite_return_wait_writable
161     tmp = []
162     tmp << @wr.kgio_trywrite("HI") until tmp[-1] == Kgio::WaitWritable
163     assert Kgio::WaitWritable === tmp[-1]
164     assert(!(Kgio::WaitReadable === tmp[-1]))
165     assert_equal Kgio::WaitWritable, tmp.pop
166     assert tmp.size > 0
167     penultimate = tmp.pop
168     assert(penultimate == "I" || penultimate == nil)
169     assert tmp.size > 0
170     tmp.each { |count| assert_equal nil, count }
171   end
173   def test_tryread_extra_buf_eagain_clears_buffer
174     tmp = "hello world"
175     rv = @rd.kgio_tryread(2, tmp)
176     assert_equal Kgio::WaitReadable, rv
177     assert_equal "", tmp
178   end
180   def test_tryread_extra_buf_eof_clears_buffer
181     tmp = "hello world"
182     @wr.close
183     assert_nil @rd.kgio_tryread(2, tmp)
184     assert_equal "", tmp
185   end
187   def test_monster_trywrite
188     buf = RANDOM_BLOB.dup
189     rv = @wr.kgio_trywrite(buf)
190     assert_kind_of String, rv
191     assert rv.size < buf.size
192     @rd.nonblock = false
193     assert_equal(buf, @rd.read(buf.size - rv.size) + rv)
194   end
196   def test_monster_write
197     buf = RANDOM_BLOB.dup
198     thr = Thread.new { @wr.kgio_write(buf) }
199     @rd.nonblock = false
200     readed = @rd.read(buf.size)
201     thr.join
202     assert_nil thr.value
203     assert_equal buf, readed
204   end
206   def test_monster_write_wait_writable
207     @wr.instance_variable_set :@nr, 0
208     def @wr.wait_writable
209       @nr += 1
210       IO.select(nil, [self])
211     end
212     Kgio.wait_writable = :wait_writable
213     buf = "." * 1024 * 1024 * 10
214     thr = Thread.new { @wr.kgio_write(buf) }
215     readed = @rd.read(buf.size)
216     thr.join
217     assert_nil thr.value
218     assert_equal buf, readed
219     assert @wr.instance_variable_get(:@nr) > 0
220   end
222   def test_wait_readable_ruby_default
223     assert_nothing_raised { Kgio.wait_readable = nil }
224     elapsed = 0
225     foo = nil
226     t0 = Time.now
227     thr = Thread.new { sleep 1; @wr.write "HELLO" }
228     assert_nothing_raised do
229       foo = @rd.kgio_read(5)
230       elapsed = Time.now - t0
231     end
232     assert elapsed >= 1.0, "elapsed: #{elapsed}"
233     assert_equal "HELLO", foo
234     thr.join
235     assert_equal 5, thr.value
236   end
238   def test_wait_writable_ruby_default
239     buf = "." * 512
240     nr = 0
241     begin
242       nr += @wr.write_nonblock(buf)
243     rescue Errno::EAGAIN
244       break
245     end while true
246     assert_nothing_raised { Kgio.wait_writable = nil }
247     elapsed = 0
248     foo = nil
249     t0 = Time.now
250     thr = Thread.new { sleep 1; @rd.readpartial(nr) }
251     assert_nothing_raised do
252       foo = @wr.kgio_write("HELLO")
253       elapsed = Time.now - t0
254     end
255     assert_nil foo
256     if @wr.stat.pipe?
257       assert elapsed >= 1.0, "elapsed: #{elapsed}"
258     end
259     assert(String === foo || foo == nil)
260     assert_kind_of String, thr.value
261   end
263   def test_wait_readable_method
264     def @rd.moo
265       defined?(@z) ? raise(RuntimeError, "Hello") : @z = "HI"
266     end
267     assert_nothing_raised { Kgio.wait_readable = :moo }
268     foo = nil
269     begin
270       foo = @rd.kgio_read(5)
271       assert false
272     rescue RuntimeError => e
273       assert_equal("Hello", e.message)
274     end
275     assert_equal "HI", @rd.instance_variable_get(:@z)
276     assert_nil foo
277   end
279   def test_tryread_wait_readable_method
280     def @rd.moo
281       raise "Hello"
282     end
283     assert_nothing_raised { Kgio.wait_readable = :moo }
284     assert_equal Kgio::WaitReadable, @rd.kgio_tryread(5)
285   end
287   def test_trywrite_wait_readable_method
288     def @wr.moo
289       raise "Hello"
290     end
291     assert_nothing_raised { Kgio.wait_writable = :moo }
292     tmp = []
293     buf = "." * 1024
294     10000.times { tmp << @wr.kgio_trywrite(buf) }
295     assert_equal Kgio::WaitWritable, tmp.pop
296   end
298   def test_wait_writable_method
299     def @wr.moo
300       defined?(@z) ? raise(RuntimeError, "Hello") : @z = "HI"
301     end
302     assert_nothing_raised { Kgio.wait_writable = :moo }
303     n = []
304     begin
305       loop { n << @wr.kgio_write("HIHIHIHIHIHI") }
306       assert false
307     rescue RuntimeError => e
308       assert_equal("Hello", e.message)
309     end
310     assert n.size > 0
311     assert_equal "HI", @wr.instance_variable_get(:@z)
312   end