test: increase test data sizes to fill socket buffers
[kgio.git] / test / lib_read_write.rb
blob5f70964592cf892a9f230ce85f9b67b07d011487
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       end while true
170       dig.hexdigest
171     end
172     50.times do
173       wr = buf
174       begin
175         rv = @wr.kgio_trywrite(wr)
176         case rv
177         when String
178           wr = rv
179         when :wait_readable
180           assert false, "should never get here line=#{__LINE__}"
181         when :wait_writable
182           IO.select(nil, [ @wr ])
183         else
184           wr = false
185         end
186       end while wr
187     end
188     @wr.close
189     t.join
190     assert_equal '8ff79d8115f9fe38d18be858c66aa08a1cc27a66', t.value
191   end
193   def test_trywritev_full
194     buf = ["\302\251" * 128] * 8 * 1024
195     buf2 = ""
196     dig = Digest::SHA1.new
197     t = Thread.new do
198       sleep 1
199       nr = 0
200       begin
201         dig.update(@rd.readpartial(4096, buf2))
202         nr += buf2.size
203       rescue EOFError
204         break
205       rescue => e
206       end while true
207       dig.hexdigest
208     end
209     50.times do
210       wr = buf
211       begin
212         rv = @wr.kgio_trywritev(wr)
213         case rv
214         when Array
215           wr = rv
216         when :wait_readable
217           assert false, "should never get here line=#{__LINE__}"
218         when :wait_writable
219           IO.select(nil, [ @wr ])
220         else
221           wr = false
222         end
223       end while wr
224     end
225     @wr.close
226     t.join
227     assert_equal '8ff79d8115f9fe38d18be858c66aa08a1cc27a66', t.value
228   end
230   def test_write_conv
231     assert_equal nil, @wr.kgio_write(10)
232     assert_equal "10", @rd.kgio_read(2)
233   end
235   def test_trywrite_conv
236     assert_equal nil, @wr.kgio_trywrite(10)
237     IO.select([@rd]) # this seems needed on FreeBSD 9.0
238     assert_equal "10", @rd.kgio_tryread(2)
239   end
241   def test_tryread_empty
242     assert_equal :wait_readable, @rd.kgio_tryread(1)
243   end
245   def test_read_too_much
246     assert_equal nil, @wr.kgio_write("hi")
247     assert_equal "hi", @rd.kgio_read(4)
248   end
250   def test_tryread_too_much
251     assert_equal nil, @wr.kgio_trywrite("hi")
252     assert_equal @rd, @rd.kgio_wait_readable
253     assert_equal "hi", @rd.kgio_tryread(4)
254   end
256   def test_read_short
257     assert_equal nil, @wr.kgio_write("hi")
258     assert_equal "h", @rd.kgio_read(1)
259     assert_equal "i", @rd.kgio_read(1)
260   end
262   def test_tryread_short
263     assert_equal nil, @wr.kgio_trywrite("hi")
264     IO.select([@rd]) # this seems needed on FreeBSD 9.0
265     assert_equal "h", @rd.kgio_tryread(1)
266     assert_equal "i", @rd.kgio_tryread(1)
267   end
269   def test_read_extra_buf
270     tmp = ""
271     tmp_object_id = tmp.object_id
272     assert_equal nil, @wr.kgio_write("hi")
273     rv = @rd.kgio_read(2, tmp)
274     assert_equal "hi", rv
275     assert_equal rv.object_id, tmp.object_id
276     assert_equal tmp_object_id, rv.object_id
277   end
279   def test_trywrite_return_wait_writable
280     tmp = []
281     tmp << @wr.kgio_trywrite("HI") until tmp[-1] == :wait_writable
282     assert :wait_writable === tmp[-1]
283     assert(!(:wait_readable === tmp[-1]))
284     assert_equal :wait_writable, tmp.pop
285     assert tmp.size > 0
286     penultimate = tmp.pop
287     assert(penultimate == "I" || penultimate == nil)
288     assert tmp.size > 0
289     tmp.each { |count| assert_equal nil, count }
290   end
292   def test_trywritev_return_wait_writable
293     tmp = []
294     tmp << @wr.kgio_trywritev(["HI"]) until tmp[-1] == :wait_writable
295     assert :wait_writable === tmp[-1]
296     assert(!(:wait_readable === tmp[-1]))
297     assert_equal :wait_writable, tmp.pop
298     assert tmp.size > 0
299     penultimate = tmp.pop
300     assert(penultimate == ["I"] || penultimate == nil,
301            "penultimate is #{penultimate.inspect}")
302     assert tmp.size > 0
303     tmp.each { |count| assert_equal nil, count }
304   end
306   def test_tryread_extra_buf_eagain_clears_buffer
307     tmp = "hello world"
308     rv = @rd.kgio_tryread(2, tmp)
309     assert_equal :wait_readable, rv
310     assert_equal "", tmp
311   end
313   def test_tryread_extra_buf_eof_clears_buffer
314     tmp = "hello world"
315     @wr.close
316     IO.select([@rd]) # this seems needed on FreeBSD 9.0
317     assert_nil @rd.kgio_tryread(2, tmp)
318     assert_equal "", tmp
319   end
321   def test_monster_trywrite
322     buf = RANDOM_BLOB.dup
323     rv = @wr.kgio_trywrite(buf)
324     assert_kind_of String, rv
325     assert rv.size < buf.size
326     @rd.nonblock = false
327     assert_equal(buf, @rd.read(buf.size - rv.size) + rv)
328   end
330   def test_monster_write
331     buf = RANDOM_BLOB.dup
332     thr = Thread.new { @wr.kgio_write(buf) }
333     @rd.nonblock = false
334     readed = @rd.read(buf.size)
335     thr.join
336     assert_nil thr.value
337     assert_equal buf, readed
338   end
340   def test_monster_trywritev
341     buf, start = [], 0
342     while start < RANDOM_BLOB.size
343       s = RANDOM_BLOB[start, 1000]
344       start += s.size
345       buf << s
346     end
347     rv = @wr.kgio_trywritev(buf)
348     assert_kind_of Array, rv
349     rv = rv.join
350     assert rv.size < RANDOM_BLOB.size
351     @rd.nonblock = false
352     assert_equal(RANDOM_BLOB, @rd.read(RANDOM_BLOB.size - rv.size) + rv)
353   end
355   def test_monster_writev
356     buf, start = [], 0
357     while start < RANDOM_BLOB.size
358       s = RANDOM_BLOB[start, 10000]
359       start += s.size
360       buf << s
361     end
362     thr = Thread.new { @wr.kgio_writev(buf) }
363     @rd.nonblock = false
364     readed = @rd.read(RANDOM_BLOB.size)
365     thr.join
366     assert_nil thr.value
367     e = (RANDOM_BLOB == readed)
368     assert e
369   end
371   def test_monster_write_wait_writable
372     @wr.instance_variable_set :@nr, 0
373     def @wr.kgio_wait_writable
374       @nr += 1
375       IO.select(nil, [self])
376     end
377     buf = RANDOM_BLOB
378     thr = Thread.new { @wr.kgio_write(buf) }
379     Thread.pass until thr.stop?
380     readed = @rd.read(buf.size)
381     thr.join
382     assert_nil thr.value
383     assert_equal buf, readed
384     assert @wr.instance_variable_get(:@nr) > 0
385   end
387   def test_monster_writev_wait_writable
388     @wr.instance_variable_set :@nr, 0
389     def @wr.kgio_wait_writable
390       @nr += 1
391       IO.select(nil, [self])
392     end
393     buf = [ RANDOM_BLOB, RANDOM_BLOB ]
394     buf_size = buf.inject(0){|c, s| c + s.size}
395     thr = Thread.new { @wr.kgio_writev(buf) }
396     Thread.pass until thr.stop?
397     readed = @rd.read(buf_size)
398     thr.join
399     assert_nil thr.value
400     e = (buf.join == readed)
401     assert e
402     assert @wr.instance_variable_get(:@nr) > 0
403   end
405   def test_wait_readable_ruby_default
406     elapsed = 0
407     foo = nil
408     t0 = Time.now
409     thr = Thread.new { sleep 1; @wr.write "HELLO" }
410     foo = @rd.kgio_read(5)
411     elapsed = Time.now - t0
412     assert elapsed >= 1.0, "elapsed: #{elapsed}"
413     assert_equal "HELLO", foo
414     thr.join
415     assert_equal 5, thr.value
416   end
418   def test_wait_writable_ruby_default
419     buf = "." * 512
420     nr = 0
421     begin
422       nr += @wr.write_nonblock(buf)
423     rescue Errno::EAGAIN
424       break
425     end while true
426     elapsed = 0
427     foo = nil
428     t0 = Time.now
429     thr = Thread.new { sleep 1; @rd.read(nr) }
430     foo = @wr.kgio_write("HELLO")
431     elapsed = Time.now - t0
433     assert_nil foo
434     if @wr.stat.pipe?
435       assert elapsed >= 1.0, "elapsed: #{elapsed}"
436     end
437     assert(String === foo || foo == nil)
438     assert_kind_of String, thr.value
439   end
441   def test_wait_readable_method
442     def @rd.kgio_wait_readable
443       defined?(@z) ? raise(RuntimeError, "Hello") : @z = "HI"
444     end
445     foo = nil
446     begin
447       foo = @rd.kgio_read(5)
448       assert false
449     rescue RuntimeError => e
450       assert_equal("Hello", e.message)
451     end
452     assert_equal "HI", @rd.instance_variable_get(:@z)
453     assert_nil foo
454   end
456   def test_tryread_wait_readable_method
457     def @rd.kgio_wait_readable
458       raise "Hello"
459     end
460     assert_equal :wait_readable, @rd.kgio_tryread(5)
461   end
463   def test_trywrite_wait_readable_method
464     def @wr.kgio_wait_writable
465       raise "Hello"
466     end
467     buf = "." * 4096
468     rv = nil
469     until rv == :wait_writable
470       rv = @wr.kgio_trywrite(buf)
471     end
472     assert_equal :wait_writable, rv
473   end
475   def test_wait_writable_method
476     def @wr.kgio_wait_writable
477       defined?(@z) ? raise(RuntimeError, "Hello") : @z = "HI"
478     end
479     n = []
480     begin
481       loop { n << @wr.kgio_write("HIHIHIHIHIHI") }
482       assert false
483     rescue RuntimeError => e
484       assert_equal("Hello", e.message)
485     end
486     assert n.size > 0
487     assert_equal "HI", @wr.instance_variable_get(:@z)
488   end