1 # -*- encoding: binary -*-
5 $stderr.sync = $stdout.sync = true
9 class Test_POSIX_MQ < Test::Unit::TestCase
11 POSIX_MQ.method_defined?(:to_io) or
12 warn "POSIX_MQ#to_io not supported on this platform: #{RUBY_PLATFORM}"
13 POSIX_MQ.method_defined?(:notify) or
14 warn "POSIX_MQ#notify not supported on this platform: #{RUBY_PLATFORM}"
15 POSIX_MQ.respond_to?(:for_fd) or
16 warn "POSIX_MQ::for_fd not supported on this platform: #{RUBY_PLATFORM}"
20 @path = "/posix_mq.rb.#{Time.now.to_i}.#$$.#{rand}"
25 assert_equal @mq, @mq.unlink
31 def test_open_with_null_byte
32 assert_raises(ArgumentError) { POSIX_MQ.open("/hello\0world", :rw) }
35 def test_unlink_with_null_byte
36 assert_raises(ArgumentError) { POSIX_MQ.open("/hello\0world", :rw) }
40 assert_nothing_raised do
41 2025.times { POSIX_MQ.new(@path, :rw) }
43 @mq = POSIX_MQ.new(@path, :rw)
44 @mq.to_io if @mq.respond_to?(:to_io)
47 end unless defined?RUBY_ENGINE && RUBY_ENGINE == "rbx"
49 def test_name_clobber_proof
50 @mq = POSIX_MQ.new(@path, :rw)
53 assert_nothing_raised { @mq.name.gsub!(/\A/, "foo") }
54 assert_equal tmp, @mq.name
55 assert tmp.object_id != @mq.name.object_id
59 @mq = POSIX_MQ.new(@path, :rw)
61 assert_equal @mq.object_id, dup.object_id
63 assert_equal @mq.object_id, clone.object_id
66 def test_timed_receive_float
68 @mq = POSIX_MQ.new(@path, :rw)
69 assert ! @mq.nonblock?
71 maybe_timeout { @mq.receive "", interval } or return
72 elapsed = Time.now - t0
73 assert_operator elapsed, :>, interval, elapsed.inspect
74 assert_operator elapsed, :<, 0.04, elapsed.inspect
77 def test_timed_receive_divmod
79 def interval.divmod(num)
80 num == 1 ? [ 0, 0.01 ] : nil
82 @mq = POSIX_MQ.new(@path, :rw)
83 assert ! @mq.nonblock?
85 maybe_timeout { @mq.receive "", interval } or return
86 elapsed = Time.now - t0
87 assert_operator elapsed, :>=, 0.01, elapsed.inspect
88 assert_operator elapsed, :<=, 0.04, elapsed.inspect
91 def test_timed_receive_fixnum
93 @mq = POSIX_MQ.new(@path, :rw)
94 assert ! @mq.nonblock?
96 maybe_timeout { @mq.receive "", interval } or return
97 elapsed = Time.now - t0
98 assert elapsed >= interval, elapsed.inspect
99 assert elapsed < 1.10, elapsed.inspect
103 alarm = lambda do |x|
104 Thread.new(x) do |time|
106 Process.kill(:USR1, $$)
112 Thread.new { @mq.send("HI") }
116 @mq = POSIX_MQ.new(@path, :rw)
117 assert ! @mq.nonblock?
120 elapsed = Time.now - t0
121 assert_equal(["HI", 0], a)
122 assert elapsed >= interval, elapsed.inspect
123 assert elapsed < 1.10, elapsed.inspect
124 assert_equal 1, alarms
126 trap(:USR1, sig) if sig
131 @mq = POSIX_MQ.new(@path, :rw, 0666, POSIX_MQ::Attr[0, 1, 1, 0])
132 assert ! @mq.nonblock?
133 assert_nothing_raised {
135 @mq.send "A", 1, interval
136 rescue NotImplementedError
141 maybe_timeout { @mq.send "B", 1, interval } or return
142 elapsed = Time.now - t0
143 assert elapsed > interval
147 POSIX_MQ.open(@path, IO::CREAT|IO::WRONLY, 0666) do |mq|
149 assert mq.kind_of?(POSIX_MQ)
150 assert_equal @path, mq.name
151 assert_equal true, mq.send("HI", 0)
152 assert_equal 1, mq.attr.curmsgs
154 assert_raises(IOError) { mq.close }
158 POSIX_MQ.unlink(@path)
162 path = "" << @path.dup
164 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
165 assert_equal path, @mq.name
168 def test_new_readonly
169 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
170 rd = POSIX_MQ.new @path, IO::RDONLY
171 assert_equal @mq.name, rd.name
175 def test_send0_receive
176 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
177 assert_equal(@mq, @mq << "hello")
178 assert_equal [ "hello", 0 ], @mq.receive
182 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
183 @mq << "hello" << "world"
184 assert_equal [ "hello", 0 ], @mq.receive
185 assert_equal [ "world", 0 ], @mq.receive
189 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
191 assert_equal "hello", @mq.shift
196 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
198 assert_equal "hello", @mq.shift(buf)
199 assert_equal "hello", buf
202 def test_send_receive
203 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
204 assert_equal true, @mq.send("hello", 0)
205 assert_equal [ "hello", 0 ], @mq.receive
208 def test_send_receive_buf
210 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
211 assert_equal true, @mq.send("hello", 0)
212 assert_equal [ "hello", 0 ], @mq.receive(buf)
213 assert_equal "hello", buf
216 def test_send_receive_prio
217 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
218 assert_equal true, @mq.send("hello", 2)
219 assert_equal [ "hello", 2 ], @mq.receive
223 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
225 assert_equal POSIX_MQ::Attr, mq_attr.class
226 assert mq_attr.flags.kind_of?(Integer)
227 assert mq_attr.maxmsg.kind_of?(Integer)
228 assert mq_attr.msgsize.kind_of?(Integer)
229 assert mq_attr.curmsgs.kind_of?(Integer)
233 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
234 assert @mq.to_io.kind_of?(IO)
235 assert_nothing_raised { IO.select([@mq], nil, nil, 0) }
236 end if POSIX_MQ.method_defined?(:to_io)
240 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
241 @alt = POSIX_MQ.for_fd(@mq.to_io.to_i)
242 assert_equal true, @mq.send("hello", 0)
243 assert_equal [ "hello", 0 ], @alt.receive(buf)
244 assert_equal "hello", buf
245 assert_equal @mq.to_io.to_i, @alt.to_io.to_i
246 assert_raises(ArgumentError) { @alt.name }
247 assert_raises(Errno::EBADF) { POSIX_MQ.for_fd(1) }
248 @alt.autoclose = false
249 assert_equal false, @alt.autoclose?
251 # iterate a bunch and hope GC kicks in
252 fd = @mq.to_io.fileno
254 mq = POSIX_MQ.for_fd(fd)
255 assert_equal true, mq.autoclose?
257 assert_equal false, mq.autoclose?
259 end if POSIX_MQ.respond_to?(:for_fd) && POSIX_MQ.method_defined?(:to_io)
263 orig = trap(:USR1) { wr.syswrite('.') }
264 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
265 assert_nothing_raised { @mq.notify = :SIGUSR1 }
266 assert_nothing_raised { @mq.send("hello", 0) }
267 assert_equal [[rd], [], []], IO.select([rd], nil, nil, 10)
268 assert_equal '.', rd.sysread(1)
269 assert_nil(@mq.notify = nil)
270 assert_nothing_raised { @mq.send("hello", 0) }
271 assert_nil IO.select([rd], nil, nil, 0.1)
274 end if POSIX_MQ.method_defined?(:to_io)
277 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
278 assert_nothing_raised { @mq.notify = false }
289 _, status = Process.waitpid2(pid)
290 assert status.success?, status.inspect
294 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
295 mq_attr = POSIX_MQ::Attr.new(IO::NONBLOCK)
297 assert_equal IO::NONBLOCK, @mq.attr.flags
298 assert mq_attr.flags.kind_of?(Integer)
302 assert_equal 0, @mq.attr.flags
305 def test_setattr_fork
306 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
307 mq_attr = POSIX_MQ::Attr.new(IO::NONBLOCK)
311 pid = fork { @mq.nonblock = false }
312 assert Process.waitpid2(pid)[1].success?
313 assert ! @mq.nonblock?
316 def test_new_nonblocking
317 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY|IO::NONBLOCK, 0666
321 def test_new_blocking
322 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
323 assert ! @mq.nonblock?
326 def test_nonblock_toggle
327 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
328 assert ! @mq.nonblock?
332 assert ! @mq.nonblock?
333 assert_raises(ArgumentError) { @mq.nonblock = nil }
337 @mq = POSIX_MQ.new @path, :w
338 assert_equal IO::WRONLY, @mq.to_io.fcntl(Fcntl::F_GETFL)
339 end if POSIX_MQ.method_defined?(:to_io)
342 @mq = POSIX_MQ.new @path, :w
344 assert_nothing_raised { mq = POSIX_MQ.new @path, :r }
345 assert_equal IO::RDONLY, mq.to_io.fcntl(Fcntl::F_GETFL)
347 end if POSIX_MQ.method_defined?(:to_io)
349 def test_new_path_only
350 @mq = POSIX_MQ.new @path, :w
352 assert_nothing_raised { mq = POSIX_MQ.new @path }
353 assert_equal IO::RDONLY, mq.to_io.fcntl(Fcntl::F_GETFL)
355 end if POSIX_MQ.method_defined?(:to_io)
358 @mq = POSIX_MQ.new @path, :rw
359 assert_equal IO::RDWR, @mq.to_io.fcntl(Fcntl::F_GETFL)
360 end if POSIX_MQ.method_defined?(:to_io)
363 mq_attr = POSIX_MQ::Attr.new(IO::NONBLOCK, 1, 1, 0)
364 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666, mq_attr
366 assert_equal mq_attr, @mq.attr
368 assert_raises(Errno::EAGAIN) { @mq.receive }
369 assert_raises(Errno::EMSGSIZE) { @mq << '..' }
370 assert_nothing_raised { @mq << '.' }
371 assert_equal [ '.', 0 ], @mq.receive
372 assert_nothing_raised { @mq << '.' }
373 assert_raises(Errno::EAGAIN) { @mq << '.' }
377 mq_attr = POSIX_MQ::Attr.new(IO::NONBLOCK, 1, 1, 0)
378 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666, mq_attr
380 assert_nil @mq.tryreceive
381 assert_nil @mq.tryshift
382 assert_equal true, @mq.trysend("a")
383 assert_equal [ "a", 0 ], @mq.tryreceive
384 assert_equal true, @mq.trysend("b")
385 assert_equal "b", @mq.tryshift
386 assert_equal true, @mq.trysend("c")
387 assert_equal false, @mq.trysend("d")
391 min_posix_mq_prio_max = 31 # defined by POSIX
392 assert POSIX_MQ::PRIO_MAX >= min_posix_mq_prio_max
396 assert POSIX_MQ::OPEN_MAX.kind_of?(Integer)
399 def test_notify_block_replace
401 @mq = POSIX_MQ.new(@path, :rw)
402 assert_nothing_raised { @mq.notify { |mq| q << mq } }
403 assert_nothing_raised { Process.waitpid2(fork { @mq << "hi" }) }
404 assert_equal @mq.object_id, q.pop.object_id
405 assert_equal "hi", @mq.receive.first
406 assert_nothing_raised { @mq.notify { |mq| q << "hi" } }
407 assert_nothing_raised { Process.waitpid2(fork { @mq << "bye" }) }
408 assert_equal "hi", q.pop
409 end if POSIX_MQ.method_defined?(:notify)
411 def test_notify_thread
413 @mq = POSIX_MQ.new(@path, :rw)
414 @mq.notify { |mq| q << Thread.current }
417 assert x.instance_of?(Thread)
418 assert Thread.current != x
419 end if POSIX_MQ.method_defined?(:notify)
421 def test_bad_open_mode
422 assert_raises(ArgumentError) { POSIX_MQ.new(@path, "rw") }
425 def test_bad_open_attr
426 assert_raises(TypeError) { POSIX_MQ.new(@path, :rw, 0666, [0, 1, 1, 0]) }
430 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
431 assert_raises(TypeError) { @mq.attr = {} }
432 assert_raises(TypeError) { @mq.attr = Struct.new(:a,:b,:c,:d).new }
437 assert_raises(exc) { } # FAIL
439 rescue Errno::ETIMEDOUT => e
441 rescue NotImplementedError => e