avoid partial writes on IO.vmsplice unless F_NONBLOCK
[ruby_io_splice.git] / test / test_io_splice.rb
blob4c63f6964eae0e0762ad6273cd815da2f5772638
1 # -*- encoding: binary -*-
2 require 'test/unit'
3 require 'tempfile'
4 require 'io/splice'
6 class Test_IO_Splice < Test::Unit::TestCase
8   def test_splice
9     str = 'abcde'
10     size = 5
11     rd, wr = IO.pipe
12     tmp = Tempfile.new(nil)
14     assert_nothing_raised {
15       tmp.syswrite(str)
16       tmp.sysseek(0)
17     }
19     nr = IO.splice(tmp.fileno, nil, wr.fileno, nil, size, 0)
20     assert_equal size, nr
21     assert_equal str, rd.sysread(size)
22   end
24   def test_splice_in_offset
25     str = 'abcde'
26     off = 3
27     len = 2
28     rd, wr = IO.pipe
29     tmp = Tempfile.new(nil)
31     assert_nothing_raised {
32       tmp.syswrite(str)
33       tmp.sysseek(0)
34     }
36     nr = IO.splice(tmp.fileno, off, wr.fileno, nil, len, 0)
37     assert_equal len, nr
38     assert_equal 'de', rd.sysread(len)
39   end
41   def test_splice_out_offset
42     str = 'abcde'
43     rd, wr = IO.pipe
44     tmp = Tempfile.new(nil)
46     assert_nothing_raised { wr.syswrite(str) }
47     nr = IO.splice(rd.fileno, nil, tmp.fileno, 3, str.size, 0)
48     assert_equal 5, nr
49     assert_nothing_raised { tmp.sysseek(0) }
50     assert_equal "\0\0\0abcde", tmp.sysread(9)
51   end
53   def test_splice_nonblock
54     rd, wr = IO.pipe
55     tmp = Tempfile.new(nil)
57     assert_raises(Errno::EAGAIN) {
58       IO.splice(rd.fileno, nil, tmp.fileno, 0, 5, IO::Splice::F_NONBLOCK)
59     }
60   end
62   def test_splice_eof
63     rd, wr = IO.pipe
64     tmp = Tempfile.new(nil)
65     wr.syswrite 'abc'
66     wr.close
68     nr = IO.splice(rd.fileno, nil, tmp.fileno, 0, 5, IO::Splice::F_NONBLOCK)
69     assert_equal 3, nr
70     assert_raises(EOFError) {
71       IO.splice(rd.fileno, nil, tmp.fileno, 0, 5, IO::Splice::F_NONBLOCK)
72     }
73   end
75   def test_tee
76     str = 'abcde'
77     size = 5
78     rda, wra = IO.pipe
79     rdb, wrb = IO.pipe
81     assert_nothing_raised { wra.syswrite(str) }
82     nr = IO.tee(rda.fileno, wrb.fileno, size, 0)
83     assert_equal 5, nr
84     assert_equal str, rdb.sysread(5)
85     assert_equal str, rda.sysread(5)
86   end
88   def test_tee_eof
89     rda, wra = IO.pipe
90     rdb, wrb = IO.pipe
91     wra.close
92     assert_raises(EOFError) { IO.tee(rda.fileno, wrb.fileno, 4096, 0) }
93   end
95   def test_tee_nonblock
96     rda, wra = IO.pipe
97     rdb, wrb = IO.pipe
98     assert_raises(Errno::EAGAIN) {
99       IO.tee(rda.fileno, wrb.fileno, 4096, IO::Splice::F_NONBLOCK)
100     }
101   end
103   def test_vmsplice_array
104     data = %w(hello world how are you today)
105     r, w = IO.pipe
106     n = IO.vmsplice(w.fileno, data, 0)
107     assert_equal data.join('').size, n
108     assert_equal data.join(''), r.readpartial(16384)
109   end
111   def test_vmsplice_nonblock
112     data = %w(hello world how are you today)
113     r, w = IO.pipe
114     w.syswrite('.' * IO::Splice::PIPE_CAPA)
115     assert_raises(Errno::EAGAIN) {
116       IO.vmsplice(w.fileno, data, IO::Splice::F_NONBLOCK)
117     }
118   end
120   def test_vmsplice_in_full
121     empty = ""
123     # bs * count should be > PIPE_BUF
124     [ [ 512, 512 ], [ 131073, 3 ], [ 4098, 64 ] ].each do |(bs,count)|
125       rd, wr = IO.pipe
126       buf = File.open('/dev/urandom', 'rb') { |fp| fp.sysread(bs) }
128       vec = (1..count).map { buf }
129       pid = fork do
130         wr.close
131         tmp = []
132         begin
133           sleep 0.005
134           tmp << rd.readpartial(8192, buf)
135         rescue EOFError
136           break
137         end while true
138         ok = (vec.join(empty) == tmp.join(empty))
139         exit! ok
140       end
141       assert_nothing_raised { rd.close }
142       assert_equal(bs * count, IO.vmsplice(wr.fileno, vec, 0))
143       assert_nothing_raised { wr.close }
144       _, status = Process.waitpid2(pid)
145       assert status.success?
146     end
147   end
149   def test_constants
150     assert IO::Splice::PIPE_BUF > 0
151     %w(move nonblock more gift).each { |x|
152       assert Integer === IO::Splice.const_get("F_#{x.upcase}")
153     }
154     assert IO::Splice::PIPE_CAPA >= IO::Splice::PIPE_BUF
155   end