1 # -*- encoding: binary -*-
5 $stderr.sync = $stdout.sync = true
14 class Test_POSIX_MQ < Test::Unit::TestCase
16 POSIX_MQ.method_defined?(:to_io) or
17 warn "POSIX_MQ#to_io not supported on this platform: #{RUBY_PLATFORM}"
18 POSIX_MQ.method_defined?(:notify) or
19 warn "POSIX_MQ#notify not supported on this platform: #{RUBY_PLATFORM}"
23 @path = "/posix_mq.rb.#{Time.now.to_i}.#$$.#{rand}"
28 assert_equal @mq, @mq.unlink
34 def test_open_with_null_byte
35 assert_raises(ArgumentError) { POSIX_MQ.open("/hello\0world", :rw) }
38 def test_unlink_with_null_byte
39 assert_raises(ArgumentError) { POSIX_MQ.open("/hello\0world", :rw) }
43 assert_nothing_raised do
44 2025.times { POSIX_MQ.new(@path, :rw) }
46 @mq = POSIX_MQ.new(@path, :rw)
47 @mq.to_io if @mq.respond_to?(:to_io)
50 end unless defined?RUBY_ENGINE && RUBY_ENGINE == "rbx"
52 def test_name_clobber_proof
53 @mq = POSIX_MQ.new(@path, :rw)
56 assert_nothing_raised { @mq.name.gsub!(/\A/, "foo") }
57 assert_equal tmp, @mq.name
58 assert tmp.object_id != @mq.name.object_id
62 @mq = POSIX_MQ.new(@path, :rw)
64 assert_equal @mq.object_id, dup.object_id
66 assert_equal @mq.object_id, clone.object_id
69 def test_timed_receive_float
71 @mq = POSIX_MQ.new(@path, :rw)
72 assert ! @mq.nonblock?
74 maybe_timeout { @mq.receive "", interval } or return
75 elapsed = Time.now - t0
76 assert elapsed > interval, elapsed.inspect
77 assert elapsed < 0.02, elapsed.inspect
80 def test_timed_receive_divmod
82 def interval.divmod(num)
83 num == 1 ? [ 0, 0.01 ] : nil
85 @mq = POSIX_MQ.new(@path, :rw)
86 assert ! @mq.nonblock?
88 maybe_timeout { @mq.receive "", interval } or return
89 elapsed = Time.now - t0
90 assert elapsed >= 0.01, elapsed.inspect
91 assert elapsed <= 0.02, elapsed.inspect
94 def test_timed_receive_fixnum
96 @mq = POSIX_MQ.new(@path, :rw)
97 assert ! @mq.nonblock?
99 maybe_timeout { @mq.receive "", interval } or return
100 elapsed = Time.now - t0
101 assert elapsed >= interval, elapsed.inspect
102 assert elapsed < 1.10, elapsed.inspect
105 def test_alarm_signal_safe
107 libcs = %w(libc.so.6 /usr/lib/libc.sl)
109 libc = DL::Handle.new(name) rescue next
110 if defined?(DL::Function)
111 alarm = libc["alarm"]
112 alarm = DL::CFunc.new(alarm, DL::TYPE_INT, "alarm")
113 alarm = DL::Function.new(alarm, [DL::TYPE_INT])
115 alarm = libc["alarm", "II"]
119 alarm or return warn "alarm() not found in #{libcs.inspect}"
121 trap("ALRM") { alarms += 1 }
124 @mq = POSIX_MQ.new(@path, :rw)
125 assert ! @mq.nonblock?
128 assert_raises(Errno::EINTR) { a = @mq.receive }
129 elapsed = Time.now - t0
131 assert elapsed >= interval, elapsed.inspect
132 assert elapsed < 1.10, elapsed.inspect
133 assert_equal 1, alarms
138 @mq = POSIX_MQ.new(@path, :rw, 0666, POSIX_MQ::Attr[0, 1, 1, 0])
139 assert ! @mq.nonblock?
140 assert_nothing_raised {
142 @mq.send "A", 1, interval
143 rescue NotImplementedError
148 maybe_timeout { @mq.send "B", 1, interval } or return
149 elapsed = Time.now - t0
150 assert elapsed > interval
154 POSIX_MQ.open(@path, IO::CREAT|IO::WRONLY, 0666) do |mq|
156 assert mq.kind_of?(POSIX_MQ)
157 assert_equal @path, mq.name
158 assert_equal true, mq.send("HI", 0)
159 assert_equal 1, mq.attr.curmsgs
161 assert_raises(IOError) { mq.close }
165 POSIX_MQ.unlink(@path)
169 path = "" << @path.dup
171 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
172 assert_equal path, @mq.name
175 def test_new_readonly
176 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
177 rd = POSIX_MQ.new @path, IO::RDONLY
178 assert_equal @mq.name, rd.name
182 def test_send0_receive
183 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
184 assert_equal(@mq, @mq << "hello")
185 assert_equal [ "hello", 0 ], @mq.receive
189 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
190 @mq << "hello" << "world"
191 assert_equal [ "hello", 0 ], @mq.receive
192 assert_equal [ "world", 0 ], @mq.receive
196 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
198 assert_equal "hello", @mq.shift
203 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
205 assert_equal "hello", @mq.shift(buf)
206 assert_equal "hello", buf
209 def test_send_receive
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
215 def test_send_receive_buf
217 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
218 assert_equal true, @mq.send("hello", 0)
219 assert_equal [ "hello", 0 ], @mq.receive(buf)
220 assert_equal "hello", buf
223 def test_send_receive_prio
224 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
225 assert_equal true, @mq.send("hello", 2)
226 assert_equal [ "hello", 2 ], @mq.receive
230 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
232 assert_equal POSIX_MQ::Attr, mq_attr.class
233 assert mq_attr.flags.kind_of?(Integer)
234 assert mq_attr.maxmsg.kind_of?(Integer)
235 assert mq_attr.msgsize.kind_of?(Integer)
236 assert mq_attr.curmsgs.kind_of?(Integer)
240 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
241 assert @mq.to_io.kind_of?(IO)
242 assert_nothing_raised { IO.select([@mq], nil, nil, 0) }
243 end if POSIX_MQ.method_defined?(:to_io)
247 orig = trap(:USR1) { wr.syswrite('.') }
248 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
249 assert_nothing_raised { @mq.notify = :SIGUSR1 }
250 assert_nothing_raised { @mq.send("hello", 0) }
251 assert_equal [[rd], [], []], IO.select([rd], nil, nil, 10)
252 assert_equal '.', rd.sysread(1)
253 assert_nil(@mq.notify = nil)
254 assert_nothing_raised { @mq.send("hello", 0) }
255 assert_nil IO.select([rd], nil, nil, 0.1)
261 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
262 assert_nothing_raised { @mq.notify = false }
273 _, status = Process.waitpid2(pid)
274 assert status.success?, status.inspect
278 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
279 mq_attr = POSIX_MQ::Attr.new(IO::NONBLOCK)
281 assert_equal IO::NONBLOCK, @mq.attr.flags
282 assert mq_attr.flags.kind_of?(Integer)
286 assert_equal 0, @mq.attr.flags
289 def test_setattr_fork
290 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
291 mq_attr = POSIX_MQ::Attr.new(IO::NONBLOCK)
295 pid = fork { @mq.nonblock = false }
296 assert Process.waitpid2(pid)[1].success?
297 assert ! @mq.nonblock?
300 def test_new_nonblocking
301 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY|IO::NONBLOCK, 0666
305 def test_new_blocking
306 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
307 assert ! @mq.nonblock?
310 def test_nonblock_toggle
311 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
312 assert ! @mq.nonblock?
316 assert ! @mq.nonblock?
317 assert_raises(ArgumentError) { @mq.nonblock = nil }
321 @mq = POSIX_MQ.new @path, :w
322 assert_equal IO::WRONLY, @mq.to_io.fcntl(Fcntl::F_GETFL)
323 end if POSIX_MQ.method_defined?(:to_io)
326 @mq = POSIX_MQ.new @path, :w
328 assert_nothing_raised { mq = POSIX_MQ.new @path, :r }
329 assert_equal IO::RDONLY, mq.to_io.fcntl(Fcntl::F_GETFL)
331 end if POSIX_MQ.method_defined?(:to_io)
333 def test_new_path_only
334 @mq = POSIX_MQ.new @path, :w
336 assert_nothing_raised { mq = POSIX_MQ.new @path }
337 assert_equal IO::RDONLY, mq.to_io.fcntl(Fcntl::F_GETFL)
339 end if POSIX_MQ.method_defined?(:to_io)
342 @mq = POSIX_MQ.new @path, :rw
343 assert_equal IO::RDWR, @mq.to_io.fcntl(Fcntl::F_GETFL)
344 end if POSIX_MQ.method_defined?(:to_io)
347 mq_attr = POSIX_MQ::Attr.new(IO::NONBLOCK, 1, 1, 0)
348 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666, mq_attr
350 assert_equal mq_attr, @mq.attr
352 assert_raises(Errno::EAGAIN) { @mq.receive }
353 assert_raises(Errno::EMSGSIZE) { @mq << '..' }
354 assert_nothing_raised { @mq << '.' }
355 assert_equal [ '.', 0 ], @mq.receive
356 assert_nothing_raised { @mq << '.' }
357 assert_raises(Errno::EAGAIN) { @mq << '.' }
361 mq_attr = POSIX_MQ::Attr.new(IO::NONBLOCK, 1, 1, 0)
362 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666, mq_attr
364 assert_nil @mq.tryreceive
365 assert_nil @mq.tryshift
366 assert_equal true, @mq.trysend("a")
367 assert_equal [ "a", 0 ], @mq.tryreceive
368 assert_equal true, @mq.trysend("b")
369 assert_equal "b", @mq.tryshift
370 assert_equal true, @mq.trysend("c")
371 assert_equal false, @mq.trysend("d")
375 min_posix_mq_prio_max = 31 # defined by POSIX
376 assert POSIX_MQ::PRIO_MAX >= min_posix_mq_prio_max
380 assert POSIX_MQ::OPEN_MAX.kind_of?(Integer)
383 def test_notify_block_replace
385 @mq = POSIX_MQ.new(@path, :rw)
386 assert_nothing_raised { @mq.notify { |mq| q << mq } }
387 assert_nothing_raised { Process.waitpid2(fork { @mq << "hi" }) }
388 assert_equal @mq.object_id, q.pop.object_id
389 assert_equal "hi", @mq.receive.first
390 assert_nothing_raised { @mq.notify { |mq| q << "hi" } }
391 assert_nothing_raised { Process.waitpid2(fork { @mq << "bye" }) }
392 assert_equal "hi", q.pop
393 end if POSIX_MQ.method_defined?(:notify)
395 def test_notify_thread
397 @mq = POSIX_MQ.new(@path, :rw)
398 @mq.notify { |mq| q << Thread.current }
401 assert x.instance_of?(Thread)
402 assert Thread.current != x
403 end if POSIX_MQ.method_defined?(:notify)
405 def test_bad_open_mode
406 assert_raises(ArgumentError) { POSIX_MQ.new(@path, "rw") }
409 def test_bad_open_attr
410 assert_raises(TypeError) { POSIX_MQ.new(@path, :rw, 0666, [0, 1, 1, 0]) }
414 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
415 assert_raises(TypeError) { @mq.attr = {} }
416 assert_raises(TypeError) { @mq.attr = Struct.new(:a,:b,:c,:d).new }
421 assert_raises(exc) { } # FAIL
423 rescue Errno::ETIMEDOUT => e
425 rescue NotImplementedError => e