copy_stream: enough to get this working under MRI 1.8
[ruby_io_splice.git] / test / test_copy_stream.rb
blob71d7cae7db0a1f5d8712add02f645aaa8b0310fe
1 require 'test/unit'
2 require 'tmpdir'
3 require "fcntl"
4 require 'io/nonblock'
5 require 'socket'
6 require 'timeout'
7 require 'tempfile'
8 require 'io/splice'
10 class TestIOCopyStreamCompat < Test::Unit::TestCase
11   def have_nonblock?
12     IO.method_defined?("nonblock=")
13   end
15   def pipe(wp, rp)
16     re, we = nil, nil
17     r, w = IO.pipe
18     rt = Thread.new do
19       begin
20         rp.call(r)
21       rescue Exception
22         r.close
23         re = $!
24       end
25     end
26     wt = Thread.new do
27       begin
28         wp.call(w)
29       rescue Exception
30         w.close
31         we = $!
32       end
33     end
34     flunk("timeout") unless wt.join(10) && rt.join(10)
35   ensure
36     w.close unless !w || w.closed?
37     r.close unless !r || r.closed?
38     (wt.kill; wt.join) if wt
39     (rt.kill; rt.join) if rt
40     raise we if we
41     raise re if re
42   end
44   def with_pipe
45     r, w = IO.pipe
46     begin
47       yield r, w
48     ensure
49       r.close unless r.closed?
50       w.close unless w.closed?
51     end
52   end
54   def with_read_pipe(content)
55     pipe(proc do |w|
56       w << content
57       w.close
58     end, proc do |r|
59       yield r
60     end)
61   end
63   def mkcdtmpdir
64     Dir.mktmpdir {|d|
65       Dir.chdir(d) {
66         yield
67       }
68     }
69   end
71   def trapping_usr1
72     @usr1_rcvd  = 0
73     trap(:USR1) { @usr1_rcvd += 1 }
74     yield
75     ensure
76       trap(:USR1, "DEFAULT")
77   end
79   def test_copy_stream
80     mkcdtmpdir {
81       content = "foobar"
82       File.open("src", "w") {|f| f << content }
83       ret = IO::Splice.copy_stream("src", "dst")
84       assert_equal(content.bytesize, ret)
85       assert_equal(content, File.read("dst"))
87       # overwrite by smaller file.
88       content = "baz"
89       File.open("src", "w") {|f| f << content }
90       ret = IO::Splice.copy_stream("src", "dst")
91       assert_equal(content.bytesize, ret)
92       assert_equal(content, File.read("dst"))
94       ret = IO::Splice.copy_stream("src", "dst", 2)
95       assert_equal(2, ret)
96       assert_equal(content[0,2], File.read("dst"))
98       ret = IO::Splice.copy_stream("src", "dst", 0)
99       assert_equal(0, ret)
100       assert_equal("", File.read("dst"))
102       ret = IO::Splice.copy_stream("src", "dst", nil, 1)
103       assert_equal(content.bytesize-1, ret)
104       assert_equal(content[1..-1], File.read("dst"))
106       assert_raise(Errno::ENOENT) {
107         IO::Splice.copy_stream("nodir/foo", "dst")
108       }
110       assert_raise(Errno::ENOENT) {
111         IO::Splice.copy_stream("src", "nodir/bar")
112       }
114       pipe(proc do |w|
115         ret = IO::Splice.copy_stream("src", w)
116         assert_equal(content.bytesize, ret)
117         w.close
118       end, proc do |r|
119         assert_equal(content, r.read)
120       end)
122       with_pipe {|r, w|
123         w.close
124         assert_raise(IOError) { IO::Splice.copy_stream("src", w) }
125       }
127       pipe_content = "abc"
128       with_read_pipe(pipe_content) {|r|
129         ret = IO::Splice.copy_stream(r, "dst")
130         assert_equal(pipe_content.bytesize, ret)
131         assert_equal(pipe_content, File.read("dst"))
132       }
134       pipe(proc do |w|
135         ret = IO::Splice.copy_stream("src", w, 1, 1)
136         assert_equal(1, ret)
137         w.close
138       end, proc do |r|
139         assert_equal(content[1,1], r.read)
140       end)
142       bigcontent = "abc" * 123456
143       File.open("bigsrc", "w") {|f| f << bigcontent }
144       ret = IO::Splice.copy_stream("bigsrc", "bigdst")
145       assert_equal(bigcontent.bytesize, ret)
146       assert_equal(bigcontent, File.read("bigdst"))
148       File.unlink("bigdst")
149       ret = IO::Splice.copy_stream("bigsrc", "bigdst", nil, 100)
150       assert_equal(bigcontent.bytesize-100, ret)
151       assert_equal(bigcontent[100..-1], File.read("bigdst"))
153       File.unlink("bigdst")
154       ret = IO::Splice.copy_stream("bigsrc", "bigdst", 30000, 100)
155       assert_equal(30000, ret)
156       assert_equal(bigcontent[100, 30000], File.read("bigdst"))
158       File.open("bigsrc") {|f|
159         begin
160           assert_equal(0, f.pos)
161           ret = IO::Splice.copy_stream(f, "bigdst", nil, 10)
162           assert_equal(bigcontent.bytesize-10, ret)
163           assert_equal(bigcontent[10..-1], File.read("bigdst"))
164           assert_equal(0, f.pos)
165           ret = IO::Splice.copy_stream(f, "bigdst", 40, 30)
166           assert_equal(40, ret)
167           assert_equal(bigcontent[30, 40], File.read("bigdst"))
168           assert_equal(0, f.pos)
169         rescue NotImplementedError
170           #skip "pread(2) is not implemtented."
171         end
172       }
174       with_pipe {|r, w|
175         w.close
176         assert_raise(IOError) { IO::Splice.copy_stream("src", w) }
177       }
179       megacontent = "abc" * 1234567
180       File.open("megasrc", "w") {|f| f << megacontent }
182       if have_nonblock?
183         with_pipe {|r1, w1|
184           with_pipe {|r2, w2|
185             begin
186               r1.nonblock = true
187               w2.nonblock = true
188             rescue Errno::EBADF
189               skip "nonblocking IO for pipe is not implemented"
190             end
191             t1 = Thread.new { w1 << megacontent; w1.close }
192             t2 = Thread.new { r2.read }
193             ret = IO::Splice.copy_stream(r1, w2)
194             assert_equal(megacontent.bytesize, ret)
195             w2.close
196             t1.join
197             assert_equal(megacontent, t2.value)
198           }
199         }
200       end
202       with_pipe {|r1, w1|
203         with_pipe {|r2, w2|
204           t1 = Thread.new { w1 << megacontent; w1.close }
205           t2 = Thread.new { r2.read }
206           ret = IO::Splice.copy_stream(r1, w2)
207           assert_equal(megacontent.bytesize, ret)
208           w2.close
209           t1.join
210           assert_equal(megacontent, t2.value)
211         }
212       }
214       with_pipe {|r, w|
215         t = Thread.new { r.read }
216         ret = IO::Splice.copy_stream("megasrc", w)
217         assert_equal(megacontent.bytesize, ret)
218         w.close
219         assert_equal(megacontent, t.value)
220       }
221     }
222   end
224   def with_socketpair
225     s1, s2 = UNIXSocket.pair
226     begin
227       yield s1, s2
228     ensure
229       s1.close unless s1.closed?
230       s2.close unless s2.closed?
231     end
232   end
234   def test_copy_stream_socket
235     mkcdtmpdir {
237       content = "foobar"
238       File.open("src", "w") {|f| f << content }
240       with_socketpair {|s1, s2|
241         ret = IO::Splice.copy_stream("src", s1)
242         assert_equal(content.bytesize, ret)
243         s1.close
244         assert_equal(content, s2.read)
245       }
247       bigcontent = "abc" * 123456
248       File.open("bigsrc", "w") {|f| f << bigcontent }
250       with_socketpair {|s1, s2|
251         t = Thread.new { s2.read }
252         ret = IO::Splice.copy_stream("bigsrc", s1)
253         assert_equal(bigcontent.bytesize, ret)
254         s1.close
255         result = t.value
256         assert_equal(bigcontent, result)
257       }
259       with_socketpair {|s1, s2|
260         t = Thread.new { s2.read }
261         ret = IO::Splice.copy_stream("bigsrc", s1, 10000)
262         assert_equal(10000, ret)
263         s1.close
264         result = t.value
265         assert_equal(bigcontent[0,10000], result)
266       }
268       File.open("bigsrc") {|f|
269         assert_equal(0, f.pos)
270         with_socketpair {|s1, s2|
271           t = Thread.new { s2.read }
272           ret = IO::Splice.copy_stream(f, s1, nil, 100)
273           assert_equal(bigcontent.bytesize-100, ret)
274           assert_equal(0, f.pos)
275           s1.close
276           result = t.value
277           assert_equal(bigcontent[100..-1], result)
278         }
279       }
281       File.open("bigsrc") {|f|
282         assert_equal(bigcontent[0,100], f.sysread(100))
283         assert_equal(100, f.pos)
284         with_socketpair {|s1, s2|
285           t = Thread.new { s2.read }
286           ret = IO::Splice.copy_stream(f, s1)
287           assert_equal(bigcontent.bytesize-100, ret)
288           assert_equal(bigcontent.length, f.sysseek(0, IO::SEEK_CUR))
289           s1.close
290           result = t.value
291           assert_equal(bigcontent[100..-1], result)
292         }
293       }
295       megacontent = "abc" * 1234567
296       File.open("megasrc", "w") {|f| f << megacontent }
298       if have_nonblock?
299         with_socketpair {|s1, s2|
300           begin
301             s1.nonblock = true
302           rescue Errno::EBADF
303             skip "nonblocking IO for pipe is not implemented"
304           end
305           t = Thread.new { s2.read }
306           ret = IO::Splice.copy_stream("megasrc", s1)
307           assert_equal(megacontent.bytesize, ret)
308           s1.close
309           result = t.value
310           assert_equal(megacontent, result)
311         }
312         with_socketpair {|s1, s2|
313           begin
314             s1.nonblock = true
315           rescue Errno::EBADF
316             skip "nonblocking IO for pipe is not implemented"
317           end
318           trapping_usr1 do
319             nr = 10
320             pid = fork do
321               s1.close
322               IO.select([s2])
323               Process.kill(:USR1, Process.ppid)
324               s2.read
325             end
326             s2.close
327             nr.times do
328               assert_equal megacontent.bytesize,
329                           IO::Splice.copy_stream("megasrc", s1)
330             end
331             assert_equal(1, @usr1_rcvd)
332             s1.close
333             _, status = Process.waitpid2(pid)
334             assert status.success?, status.inspect
335           end
336         }
337       end
338     }
339   end