1858257787e6fd0ce4dc5290ad4544e8c967e221
[ruby_io_splice.git] / test / test_copy_stream.rb
blob1858257787e6fd0ce4dc5290ad4544e8c967e221
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     return
236     mkcdtmpdir {
238       content = "foobar"
239       File.open("src", "w") {|f| f << content }
241       with_socketpair {|s1, s2|
242         ret = IO::Splice.copy_stream("src", s1)
243         assert_equal(content.bytesize, ret)
244         s1.close
245         assert_equal(content, s2.read)
246       }
248       bigcontent = "abc" * 123456
249       File.open("bigsrc", "w") {|f| f << bigcontent }
251       with_socketpair {|s1, s2|
252         t = Thread.new { s2.read }
253         ret = IO::Splice.copy_stream("bigsrc", s1)
254         assert_equal(bigcontent.bytesize, ret)
255         s1.close
256         result = t.value
257         assert_equal(bigcontent, result)
258       }
260       with_socketpair {|s1, s2|
261         t = Thread.new { s2.read }
262         ret = IO::Splice.copy_stream("bigsrc", s1, 10000)
263         assert_equal(10000, ret)
264         s1.close
265         result = t.value
266         assert_equal(bigcontent[0,10000], result)
267       }
269       File.open("bigsrc") {|f|
270         assert_equal(0, f.pos)
271         with_socketpair {|s1, s2|
272           t = Thread.new { s2.read }
273           ret = IO::Splice.copy_stream(f, s1, nil, 100)
274           assert_equal(bigcontent.bytesize-100, ret)
275           assert_equal(0, f.pos)
276           s1.close
277           result = t.value
278           assert_equal(bigcontent[100..-1], result)
279         }
280       }
282       File.open("bigsrc") {|f|
283         assert_equal(bigcontent[0,100], f.read(100))
284         assert_equal(100, f.pos)
285         with_socketpair {|s1, s2|
286           t = Thread.new { s2.read }
287           ret = IO::Splice.copy_stream(f, s1)
288           assert_equal(bigcontent.bytesize-100, ret)
289           assert_equal(bigcontent.length, f.pos)
290           s1.close
291           result = t.value
292           assert_equal(bigcontent[100..-1], result)
293         }
294       }
296       megacontent = "abc" * 1234567
297       File.open("megasrc", "w") {|f| f << megacontent }
299       if have_nonblock?
300         with_socketpair {|s1, s2|
301           begin
302             s1.nonblock = true
303           rescue Errno::EBADF
304             skip "nonblocking IO for pipe is not implemented"
305           end
306           t = Thread.new { s2.read }
307           ret = IO::Splice.copy_stream("megasrc", s1)
308           assert_equal(megacontent.bytesize, ret)
309           s1.close
310           result = t.value
311           assert_equal(megacontent, result)
312         }
313         with_socketpair {|s1, s2|
314           begin
315             s1.nonblock = true
316           rescue Errno::EBADF
317             skip "nonblocking IO for pipe is not implemented"
318           end
319           trapping_usr1 do
320             nr = 10
321             pid = fork do
322               s1.close
323               IO.select([s2])
324               Process.kill(:USR1, Process.ppid)
325               s2.read
326             end
327             s2.close
328             nr.times do
329               assert_equal megacontent.bytesize,
330                           IO::Splice.copy_stream("megasrc", s1)
331             end
332             assert_equal(1, @usr1_rcvd)
333             s1.close
334             _, status = Process.waitpid2(pid)
335             assert status.success?, status.inspect
336           end
337         }
338       end
339     }
340   end