reinstate the original (and dangerous) autopush in C
[kgio.git] / test / lib_read_write.rb
blob26e7aef93aeb6a98bd9fd860daae4dea42ebd614
1 # -*- encoding: binary -*-
2 require 'test/unit'
3 require 'io/nonblock'
4 require 'digest/sha1'
5 require 'fileutils'
6 $-w = true
7 require 'kgio'
9 module LibReadWriteTest
10   RANDOM_BLOB = File.open("/dev/urandom") { |fp| fp.read(10 * 1024 * 1024) }
12   def teardown
13     @rd.close if defined?(@rd) && ! @rd.closed?
14     @wr.close if defined?(@wr) && ! @wr.closed?
15     FileUtils.remove_entry_secure(@tmpdir) if defined?(@tmpdir)
16   end
18   def test_write_empty
19     assert_nil @wr.kgio_write("")
20   end
22   def test_trywrite_empty
23     assert_nil @wr.kgio_trywrite("")
24   end
26   def test_writev_empty
27     assert_nil @wr.kgio_writev([])
28   end
30   def test_trywritev_empty
31     assert_nil @wr.kgio_trywritev([])
32   end
34   def test_read_zero
35     assert_equal "", @rd.kgio_read(0)
36     buf = "foo"
37     assert_equal buf.object_id, @rd.kgio_read(0, buf).object_id
38     assert_equal "", buf
39   end
41   def test_read_shared
42     a = "." * 0x1000
43     b = a.dup
44     @wr.syswrite "a"
45     assert_equal "a", @rd.kgio_read(0x1000, a)
46     assert_equal "a", a
47     assert_equal "." * 0x1000, b
48   end
50   def test_read_shared_2
51     a = "." * 0x1000
52     b = a.dup
53     @wr.syswrite "a"
54     assert_equal "a", @rd.kgio_read(0x1000, b)
55     assert_equal "a", b
56     assert_equal "." * 0x1000, a
57   end
59   def test_tryread_zero
60     assert_equal "", @rd.kgio_tryread(0)
61     buf = "foo"
62     assert_equal buf.object_id, @rd.kgio_tryread(0, buf).object_id
63     assert_equal "", buf
64   end
66   def test_tryread_shared
67     a = "." * 0x1000
68     b = a.dup
69     @wr.syswrite("a")
70     IO.select([@rd]) # this seems needed on FreeBSD 9.0
71     assert_equal "a", @rd.kgio_tryread(0x1000, b)
72     assert_equal "a", b
73     assert_equal "." * 0x1000, a
74   end
76   def test_tryread_shared_2
77     a = "." * 0x1000
78     b = a.dup
79     @wr.syswrite("a")
80     IO.select([@rd]) # this seems needed on FreeBSD 9.0
81     assert_equal "a", @rd.kgio_tryread(0x1000, a)
82     assert_equal "a", a
83     assert_equal "." * 0x1000, b
84   end
86   def test_read_eof
87     @wr.close
88     assert_nil @rd.kgio_read(5)
89   end
91   def test_read_bang_eof
92     @wr.close
93     begin
94       @rd.kgio_read!(5)
95       assert false, "should never get here (line:#{__LINE__})"
96     rescue EOFError => e
97       assert_equal [], e.backtrace
98     end
99   end
101   def test_tryread_eof
102     @wr.close
103     IO.select([@rd]) # this seems needed on FreeBSD 9.0
104     assert_nil @rd.kgio_tryread(5)
105   end
107   def test_write_closed
108     @rd.close
109     begin
110       loop { @wr.kgio_write "HI" }
111     rescue Errno::EPIPE, Errno::ECONNRESET => e
112       assert_equal [], e.backtrace
113       return
114     end
115     assert false, "should never get here (line:#{__LINE__})"
116   end
118   def test_trywrite_closed
119     @rd.close
120     begin
121       loop { @wr.kgio_trywrite "HI" }
122     rescue Errno::EPIPE, Errno::ECONNRESET => e
123       assert_equal [], e.backtrace
124       return
125     end
126     assert false, "should never get here (line:#{__LINE__})"
127   end
129   def test_writev_closed
130     @rd.close
131     begin
132       loop { @wr.kgio_writev ["HI"] }
133     rescue Errno::EPIPE, Errno::ECONNRESET => e
134       assert_equal [], e.backtrace
135       return
136     end
137     assert false, "should never get here (line:#{__LINE__})"
138   end
140   def test_trywritev_closed
141     @rd.close
142     begin
143       loop { @wr.kgio_trywritev ["HI"] }
144     rescue Errno::EPIPE, Errno::ECONNRESET => e
145       assert_equal [], e.backtrace
146       return
147     end
148     assert false, "should never get here (line:#{__LINE__})"
149   end
151   def test_trywrite_full
152     buf = "\302\251" * 1024 * 1024
153     buf2 = ""
154     dig = Digest::SHA1.new
155     t = Thread.new do
156       sleep 1
157       nr = 0
158       begin
159         dig.update(@rd.readpartial(4096, buf2))
160         nr += buf2.size
161       rescue EOFError
162         break
163       rescue => e
164       end while true
165       dig.hexdigest
166     end
167     50.times do
168       wr = buf
169       begin
170         rv = @wr.kgio_trywrite(wr)
171         case rv
172         when String
173           wr = rv
174         when :wait_readable
175           assert false, "should never get here line=#{__LINE__}"
176         when :wait_writable
177           IO.select(nil, [ @wr ])
178         else
179           wr = false
180         end
181       end while wr
182     end
183     @wr.close
184     t.join
185     assert_equal '8ff79d8115f9fe38d18be858c66aa08a1cc27a66', t.value
186   end
188   def test_trywritev_full
189     buf = ["\302\251" * 128] * 8 * 1024
190     buf2 = ""
191     dig = Digest::SHA1.new
192     t = Thread.new do
193       sleep 1
194       nr = 0
195       begin
196         dig.update(@rd.readpartial(4096, buf2))
197         nr += buf2.size
198       rescue EOFError
199         break
200       rescue => e
201       end while true
202       dig.hexdigest
203     end
204     50.times do
205       wr = buf
206       begin
207         rv = @wr.kgio_trywritev(wr)
208         case rv
209         when Array
210           wr = rv
211         when :wait_readable
212           assert false, "should never get here line=#{__LINE__}"
213         when :wait_writable
214           IO.select(nil, [ @wr ])
215         else
216           wr = false
217         end
218       end while wr
219     end
220     @wr.close
221     t.join
222     assert_equal '8ff79d8115f9fe38d18be858c66aa08a1cc27a66', t.value
223   end
225   def test_write_conv
226     assert_equal nil, @wr.kgio_write(10)
227     assert_equal "10", @rd.kgio_read(2)
228   end
230   def test_trywrite_conv
231     assert_equal nil, @wr.kgio_trywrite(10)
232     IO.select([@rd]) # this seems needed on FreeBSD 9.0
233     assert_equal "10", @rd.kgio_tryread(2)
234   end
236   def test_tryread_empty
237     assert_equal :wait_readable, @rd.kgio_tryread(1)
238   end
240   def test_read_too_much
241     assert_equal nil, @wr.kgio_write("hi")
242     assert_equal "hi", @rd.kgio_read(4)
243   end
245   def test_tryread_too_much
246     assert_equal nil, @wr.kgio_trywrite("hi")
247     assert_equal @rd, @rd.kgio_wait_readable
248     assert_equal "hi", @rd.kgio_tryread(4)
249   end
251   def test_read_short
252     assert_equal nil, @wr.kgio_write("hi")
253     assert_equal "h", @rd.kgio_read(1)
254     assert_equal "i", @rd.kgio_read(1)
255   end
257   def test_tryread_short
258     assert_equal nil, @wr.kgio_trywrite("hi")
259     IO.select([@rd]) # this seems needed on FreeBSD 9.0
260     assert_equal "h", @rd.kgio_tryread(1)
261     assert_equal "i", @rd.kgio_tryread(1)
262   end
264   def test_read_extra_buf
265     tmp = ""
266     tmp_object_id = tmp.object_id
267     assert_equal nil, @wr.kgio_write("hi")
268     rv = @rd.kgio_read(2, tmp)
269     assert_equal "hi", rv
270     assert_equal rv.object_id, tmp.object_id
271     assert_equal tmp_object_id, rv.object_id
272   end
274   def test_trywrite_return_wait_writable
275     tmp = []
276     tmp << @wr.kgio_trywrite("HI") until tmp[-1] == :wait_writable
277     assert :wait_writable === tmp[-1]
278     assert(!(:wait_readable === tmp[-1]))
279     assert_equal :wait_writable, tmp.pop
280     assert tmp.size > 0
281     penultimate = tmp.pop
282     assert(penultimate == "I" || penultimate == nil)
283     assert tmp.size > 0
284     tmp.each { |count| assert_equal nil, count }
285   end
287   def test_trywritev_return_wait_writable
288     tmp = []
289     tmp << @wr.kgio_trywritev(["HI"]) until tmp[-1] == :wait_writable
290     assert :wait_writable === tmp[-1]
291     assert(!(:wait_readable === tmp[-1]))
292     assert_equal :wait_writable, tmp.pop
293     assert tmp.size > 0
294     penultimate = tmp.pop
295     assert(penultimate == ["I"] || penultimate == nil,
296            "penultimate is #{penultimate.inspect}")
297     assert tmp.size > 0
298     tmp.each { |count| assert_equal nil, count }
299   end
301   def test_tryread_extra_buf_eagain_clears_buffer
302     tmp = "hello world"
303     rv = @rd.kgio_tryread(2, tmp)
304     assert_equal :wait_readable, rv
305     assert_equal "", tmp
306   end
308   def test_tryread_extra_buf_eof_clears_buffer
309     tmp = "hello world"
310     @wr.close
311     IO.select([@rd]) # this seems needed on FreeBSD 9.0
312     assert_nil @rd.kgio_tryread(2, tmp)
313     assert_equal "", tmp
314   end
316   def test_monster_trywrite
317     buf = RANDOM_BLOB.dup
318     rv = @wr.kgio_trywrite(buf)
319     assert_kind_of String, rv
320     assert rv.size < buf.size
321     @rd.nonblock = false
322     assert_equal(buf, @rd.read(buf.size - rv.size) + rv)
323   end
325   def test_monster_write
326     buf = RANDOM_BLOB.dup
327     thr = Thread.new { @wr.kgio_write(buf) }
328     @rd.nonblock = false
329     readed = @rd.read(buf.size)
330     thr.join
331     assert_nil thr.value
332     assert_equal buf, readed
333   end
335   def test_monster_trywritev
336     buf, start = [], 0
337     while start < RANDOM_BLOB.size
338       s = RANDOM_BLOB[start, 1000]
339       start += s.size
340       buf << s
341     end
342     rv = @wr.kgio_trywritev(buf)
343     assert_kind_of Array, rv
344     rv = rv.join
345     assert rv.size < RANDOM_BLOB.size
346     @rd.nonblock = false
347     assert_equal(RANDOM_BLOB, @rd.read(RANDOM_BLOB.size - rv.size) + rv)
348   end
350   def test_monster_writev
351     buf, start = [], 0
352     while start < RANDOM_BLOB.size
353       s = RANDOM_BLOB[start, 10000]
354       start += s.size
355       buf << s
356     end
357     thr = Thread.new { @wr.kgio_writev(buf) }
358     @rd.nonblock = false
359     readed = @rd.read(RANDOM_BLOB.size)
360     thr.join
361     assert_nil thr.value
362     e = (RANDOM_BLOB == readed)
363     assert e
364   end
366   def test_monster_write_wait_writable
367     @wr.instance_variable_set :@nr, 0
368     def @wr.kgio_wait_writable
369       @nr += 1
370       IO.select(nil, [self])
371     end
372     buf = "." * 1024 * 1024 * 10
373     thr = Thread.new { @wr.kgio_write(buf) }
374     Thread.pass until thr.stop?
375     readed = @rd.read(buf.size)
376     thr.join
377     assert_nil thr.value
378     assert_equal buf, readed
379     assert @wr.instance_variable_get(:@nr) > 0
380   end
382   def test_monster_writev_wait_writable
383     @wr.instance_variable_set :@nr, 0
384     def @wr.kgio_wait_writable
385       @nr += 1
386       IO.select(nil, [self])
387     end
388     buf = ["." * 1024] * 1024 * 10
389     buf_size = buf.inject(0){|c, s| c + s.size}
390     thr = Thread.new { @wr.kgio_writev(buf) }
391     Thread.pass until thr.stop?
392     readed = @rd.read(buf_size)
393     thr.join
394     assert_nil thr.value
395     e = (buf.join == readed)
396     assert e
397     assert @wr.instance_variable_get(:@nr) > 0
398   end
400   def test_wait_readable_ruby_default
401     elapsed = 0
402     foo = nil
403     t0 = Time.now
404     thr = Thread.new { sleep 1; @wr.write "HELLO" }
405     foo = @rd.kgio_read(5)
406     elapsed = Time.now - t0
407     assert elapsed >= 1.0, "elapsed: #{elapsed}"
408     assert_equal "HELLO", foo
409     thr.join
410     assert_equal 5, thr.value
411   end
413   def test_wait_writable_ruby_default
414     buf = "." * 512
415     nr = 0
416     begin
417       nr += @wr.write_nonblock(buf)
418     rescue Errno::EAGAIN
419       break
420     end while true
421     elapsed = 0
422     foo = nil
423     t0 = Time.now
424     thr = Thread.new { sleep 1; @rd.read(nr) }
425     foo = @wr.kgio_write("HELLO")
426     elapsed = Time.now - t0
428     assert_nil foo
429     if @wr.stat.pipe?
430       assert elapsed >= 1.0, "elapsed: #{elapsed}"
431     end
432     assert(String === foo || foo == nil)
433     assert_kind_of String, thr.value
434   end
436   def test_wait_readable_method
437     def @rd.kgio_wait_readable
438       defined?(@z) ? raise(RuntimeError, "Hello") : @z = "HI"
439     end
440     foo = nil
441     begin
442       foo = @rd.kgio_read(5)
443       assert false
444     rescue RuntimeError => e
445       assert_equal("Hello", e.message)
446     end
447     assert_equal "HI", @rd.instance_variable_get(:@z)
448     assert_nil foo
449   end
451   def test_tryread_wait_readable_method
452     def @rd.kgio_wait_readable
453       raise "Hello"
454     end
455     assert_equal :wait_readable, @rd.kgio_tryread(5)
456   end
458   def test_trywrite_wait_readable_method
459     def @wr.kgio_wait_writable
460       raise "Hello"
461     end
462     buf = "." * 4096
463     rv = nil
464     until rv == :wait_writable
465       rv = @wr.kgio_trywrite(buf)
466     end
467     assert_equal :wait_writable, rv
468   end
470   def test_wait_writable_method
471     def @wr.kgio_wait_writable
472       defined?(@z) ? raise(RuntimeError, "Hello") : @z = "HI"
473     end
474     n = []
475     begin
476       loop { n << @wr.kgio_write("HIHIHIHIHIHI") }
477       assert false
478     rescue RuntimeError => e
479       assert_equal("Hello", e.message)
480     end
481     assert n.size > 0
482     assert_equal "HI", @wr.instance_variable_get(:@z)
483   end