test: fix broken assertions on Ruby 1.9.3dev
[ruby_io_splice.git] / test / test_io_splice.rb
blobb4a2defaa3ddb15540354efad54739f005777ba1
1 # -*- encoding: binary -*-
2 require 'test/unit'
3 require 'tempfile'
4 require 'socket'
5 require 'io/nonblock'
6 require 'timeout'
7 $-w = true
8 require 'io/splice'
10 class Test_IO_Splice < Test::Unit::TestCase
12   def test_splice
13     str = 'abcde'
14     size = 5
15     rd, wr = IO.pipe
16     tmp = Tempfile.new('ruby_io_splice')
18     assert_nothing_raised {
19       tmp.syswrite(str)
20       tmp.sysseek(0)
21     }
23     nr = IO.splice(tmp.fileno, nil, wr.fileno, nil, size, 0)
24     assert_equal size, nr
25     assert_equal str, rd.sysread(size)
26   end
28   def test_splice_io
29     str = 'abcde'
30     size = 5
31     rd, wr = IO.pipe
32     tmp = Tempfile.new('ruby_io_splice')
34     assert_nothing_raised {
35       tmp.syswrite(str)
36       tmp.sysseek(0)
37     }
39     nr = IO.splice(tmp, nil, wr, nil, size, 0)
40     assert_equal size, nr
41     assert_equal str, rd.sysread(size)
42   end
44   def test_splice_io_ish
45     str = 'abcde'
46     size = 5
47     rd, wr = IO.pipe
48     tmp = Tempfile.new('ruby_io_splice')
49     io_ish = [ tmp ]
50     def io_ish.to_io
51       first.to_io
52     end
54     assert_nothing_raised {
55       tmp.syswrite(str)
56       tmp.sysseek(0)
57     }
59     nr = IO.splice(io_ish, nil, wr, nil, size, 0)
60     assert_equal size, nr
61     assert_equal str, rd.sysread(size)
62   end
64   def test_splice_in_offset
65     str = 'abcde'
66     off = 3
67     len = 2
68     rd, wr = IO.pipe
69     tmp = Tempfile.new('ruby_io_splice')
71     assert_nothing_raised {
72       tmp.syswrite(str)
73       tmp.sysseek(0)
74     }
76     nr = IO.splice(tmp.fileno, off, wr.fileno, nil, len, 0)
77     assert_equal len, nr
78     assert_equal 'de', rd.sysread(len)
79   end
81   def test_splice_out_offset
82     str = 'abcde'
83     rd, wr = IO.pipe
84     tmp = Tempfile.new('ruby_io_splice')
86     assert_nothing_raised { wr.syswrite(str) }
87     nr = IO.splice(rd.fileno, nil, tmp.fileno, 3, str.size, 0)
88     assert_equal 5, nr
89     assert_nothing_raised { tmp.sysseek(0) }
90     assert_equal "\0\0\0abcde", tmp.sysread(9)
91   end
93   def test_splice_nonblock
94     rd, wr = IO.pipe
95     tmp = Tempfile.new('ruby_io_splice')
97     assert_raises(Errno::EAGAIN) {
98       IO.splice(rd.fileno, nil, tmp.fileno, 0, 5, IO::Splice::F_NONBLOCK)
99     }
100   end
102   def test_trysplice_nonblock
103     rd, wr = IO.pipe
104     tmp = Tempfile.new('ruby_io_splice')
105     assert_equal :EAGAIN,
106            IO.trysplice(rd, nil, tmp, 0, 5, IO::Splice::F_NONBLOCK)
107   end
109   def test_splice_eof
110     rd, wr = IO.pipe
111     tmp = Tempfile.new('ruby_io_splice')
112     wr.syswrite 'abc'
113     wr.close
115     nr = IO.splice(rd.fileno, nil, tmp.fileno, 0, 5, IO::Splice::F_NONBLOCK)
116     assert_equal 3, nr
117     assert_raises(EOFError) {
118       IO.splice(rd.fileno, nil, tmp.fileno, 0, 5, IO::Splice::F_NONBLOCK)
119     }
120   end
122   def test_trysplice_eof
123     rd, wr = IO.pipe
124     tmp = Tempfile.new('ruby_io_splice')
125     wr.syswrite 'abc'
126     wr.close
128     nr = IO.trysplice(rd, nil, tmp, 0, 5, IO::Splice::F_NONBLOCK)
129     assert_equal 3, nr
130     assert_nil IO.trysplice(rd, nil, tmp, 0, 5, IO::Splice::F_NONBLOCK)
131   end
133   def test_splice_nonblock_socket
134     server = TCPServer.new('127.0.0.1', 0)
135     port = server.addr[1]
136     rp, wp = IO.pipe
137     rs = TCPSocket.new('127.0.0.1', port)
138     rs.nonblock = true
139     assert_raises(Errno::EAGAIN) { IO.splice(rs, nil, wp, nil, 1024, 0) }
140     rs.close
141     server.close
142   end
144   def test_tee
145     str = 'abcde'
146     size = 5
147     rda, wra = IO.pipe
148     rdb, wrb = IO.pipe
150     assert_nothing_raised { wra.syswrite(str) }
151     nr = IO.tee(rda.fileno, wrb.fileno, size, 0)
152     assert_equal 5, nr
153     assert_equal str, rdb.sysread(5)
154     assert_equal str, rda.sysread(5)
155   end
157   def test_tee_eof
158     rda, wra = IO.pipe
159     rdb, wrb = IO.pipe
160     wra.close
161     assert_raises(EOFError) { IO.tee(rda.fileno, wrb.fileno, 4096, 0) }
162   end
164   def test_tee_nonblock
165     rda, wra = IO.pipe
166     rdb, wrb = IO.pipe
167     assert_raises(Errno::EAGAIN) {
168       IO.tee(rda.fileno, wrb.fileno, 4096, IO::Splice::F_NONBLOCK)
169     }
170   end
172   def test_tee_io
173     str = 'abcde'
174     size = 5
175     rda, wra = IO.pipe
176     rdb, wrb = IO.pipe
178     assert_nothing_raised { wra.syswrite(str) }
179     nr = IO.tee(rda, wrb, size, 0)
180     assert_equal 5, nr
181     assert_equal str, rdb.sysread(5)
182     assert_equal str, rda.sysread(5)
183   end
185   def test_vmsplice_array
186     data = %w(hello world how are you today)
187     r, w = IO.pipe
188     n = IO.vmsplice(w.fileno, data, 0)
189     assert_equal data.join('').size, n
190     assert_equal data.join(''), r.readpartial(16384)
191   end
193   def test_vmsplice_string
194     r, w = IO.pipe
195     assert_equal 5, IO.vmsplice(w, 'hello', 0)
196     assert_equal 'hello', r.read(5)
197   end
199   def test_vmsplice_array_io
200     data = %w(hello world how are you today)
201     r, w = IO.pipe
202     n = IO.vmsplice(w, data, 0)
203     assert_equal data.join('').size, n
204     assert_equal data.join(''), r.readpartial(16384)
205   end
207   def test_vmsplice_nonblock
208     data = %w(hello world how are you today)
209     r, w = IO.pipe
210     w.syswrite('.' * IO::Splice::PIPE_CAPA)
211     assert_raises(Errno::EAGAIN) {
212       IO.vmsplice(w.fileno, data, IO::Splice::F_NONBLOCK)
213     }
214   end
216   def test_vmsplice_in_full
217     empty = ""
219     # bs * count should be > PIPE_BUF
220     [ [ 512, 512 ], [ 131073, 3 ], [ 4098, 64 ] ].each do |(bs,count)|
221       rd, wr = IO.pipe
222       buf = File.open('/dev/urandom', 'rb') { |fp| fp.sysread(bs) }
224       vec = (1..count).map { buf }
225       pid = fork do
226         wr.close
227         tmp = []
228         begin
229           sleep 0.005
230           tmp << rd.readpartial(8192)
231         rescue EOFError
232           break
233         end while true
234         ok = (vec.join(empty) == tmp.join(empty))
235         exit! ok
236       end
237       assert_nothing_raised { rd.close }
238       assert_equal(bs * count, IO.vmsplice(wr.fileno, vec, 0))
239       assert_nothing_raised { wr.close }
240       _, status = Process.waitpid2(pid)
241       assert status.success?
242     end
243   end
245   def test_vmsplice_nil
246     data = %w(hello world how are you today)
247     assert_raises(TypeError) { IO.vmsplice(nil, data, 0) }
248   end
250   def test_constants
251     assert IO::Splice::PIPE_BUF > 0
252     %w(move nonblock more gift).each { |x|
253       assert Integer === IO::Splice.const_get("F_#{x.upcase}")
254     }
255     assert IO::Splice::PIPE_CAPA >= IO::Splice::PIPE_BUF
256   end
258   def test_splice_copy_stream_file_to_file_small
259     a, b = Tempfile.new('a'), Tempfile.new('b')
260     a.syswrite 'hello world'
261     a.sysseek(0)
262     IO::Splice.copy_stream(a, b)
263     b.rewind
264     assert_equal 'hello world', b.read
265   end
267   def test_splice_copy_stream_file_to_file_big
268     buf = ('ab' * IO::Splice::PIPE_CAPA) + 'hi'
269     a, b = Tempfile.new('a'), Tempfile.new('b')
270     a.syswrite buf
271     a.sysseek(0)
272     IO::Splice.copy_stream(a, b)
273     b.rewind
274     assert_equal buf, b.read
275   end
277   def test_splice_copy_stream_file_to_file_big_partial
278     nr = IO::Splice::PIPE_CAPA
279     buf = ('ab' * nr) + 'hi'
280     a, b = Tempfile.new('a'), Tempfile.new('b')
281     a.syswrite buf
282     a.sysseek(0)
283     assert_equal nr, IO::Splice.copy_stream(a, b, nr)
284     b.rewind
285     assert_equal('ab' * (nr/2), b.read)
286   end
288   def test_splice_copy_stream_file_to_file_len
289     a, b = Tempfile.new('a'), Tempfile.new('b')
290     a.syswrite 'hello world'
291     a.sysseek(0)
292     IO::Splice.copy_stream(a, b, 5)
293     b.rewind
294     assert_equal 'hello', b.read
295   end
297   def test_splice_copy_stream_pipe_to_file_len
298     a = Tempfile.new('a')
299     r, w = IO.pipe
300     w.syswrite 'hello world'
301     IO::Splice.copy_stream(r, a, 5)
302     a.rewind
303     assert_equal 'hello', a.read
304   end
306   def test_splice_copy_stream_paths
307     a = Tempfile.new('a')
308     b = Tempfile.new('a')
309     a.syswrite('hello world')
310     IO::Splice.copy_stream(a.path, b.path, 5)
311     assert_equal 'hello', b.read
312   end
314   def test_splice_copy_stream_src_offset
315     a = Tempfile.new('a')
316     b = Tempfile.new('a')
317     a.syswrite('hello world')
318     IO::Splice.copy_stream(a.path, b.path, 5, 6)
319     assert_equal 'world', b.read
320   end
322   def test_copy_stream_nonblock_src
323     server = TCPServer.new('127.0.0.1', 0)
324     port = server.addr[1]
325     rp, wp = IO.pipe
326     rs = TCPSocket.new('127.0.0.1', port)
327     rs.nonblock = true
328     nr = 0
329     assert_raises(Timeout::Error) do
330       timeout(0.05) { nr += IO::Splice.copy_stream(rs, wp, 5) }
331     end
332     assert_equal 0, nr
333     rs.close
334     server.close
335   end
337   def test_copy_stream_nonblock_dst
338     server = TCPServer.new('127.0.0.1', 0)
339     port = server.addr[1]
340     rp, wp = IO.pipe
341     rs = TCPSocket.new('127.0.0.1', port)
342     rs.nonblock = true
343     client = server.accept
344     buf = ' ' * IO::Splice::PIPE_CAPA
345     nr = 0
346     assert_raises(Timeout::Error) do
347       loop do
348         begin
349           wp.write_nonblock(buf)
350         rescue Errno::EAGAIN
351         end
352         timeout(0.05) do
353           nr += IO::Splice.copy_stream(rp, rs, IO::Splice::PIPE_CAPA)
354         end
355       end
356     end
357     assert_equal nr, client.read(nr).size
358     rs.close
359     server.close
360   end
362   def test_copy_stream_eof
363     r, w = IO.pipe
364     w.syswrite 'hello world'
365     w.close
366     a = Tempfile.new('a')
367     assert_equal 11, IO::Splice.copy_stream(r, a)
368     a.rewind
369     assert_equal 'hello world', a.read
370   end
372   def test_pipe_size
373     r, w = IO.pipe
374     assert_kind_of Integer, r.pipe_size
375     assert(r.pipe_size >= 512)
376     assert_nothing_raised { w.pipe_size = 8192 }
377     assert_equal 8192, r.pipe_size
379     w.write('*' * 4097)
380     assert_raises(Errno::EBUSY) { r.pipe_size = 4096 }
382     pipe_max_size = File.read("/proc/sys/fs/pipe-max-size").to_i
383     assert_nothing_raised { r.pipe_size = pipe_max_size }
384     assert_raises(Errno::EPERM) { r.pipe_size = pipe_max_size * 2 }
385   end if IO.method_defined?(:pipe_size)