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