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 libc.so.0.1 libc.so.7 /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}"
123 Thread.new { @mq.send("HI") }
127 @mq = POSIX_MQ.new(@path, :rw)
128 assert ! @mq.nonblock?
131 elapsed = Time.now - t0
132 assert_equal(["HI", 0], a)
133 assert elapsed >= interval, elapsed.inspect
134 assert elapsed < 1.10, elapsed.inspect
135 assert_equal 1, alarms
140 @mq = POSIX_MQ.new(@path, :rw, 0666, POSIX_MQ::Attr[0, 1, 1, 0])
141 assert ! @mq.nonblock?
142 assert_nothing_raised {
144 @mq.send "A", 1, interval
145 rescue NotImplementedError
150 maybe_timeout { @mq.send "B", 1, interval } or return
151 elapsed = Time.now - t0
152 assert elapsed > interval
156 POSIX_MQ.open(@path, IO::CREAT|IO::WRONLY, 0666) do |mq|
158 assert mq.kind_of?(POSIX_MQ)
159 assert_equal @path, mq.name
160 assert_equal true, mq.send("HI", 0)
161 assert_equal 1, mq.attr.curmsgs
163 assert_raises(IOError) { mq.close }
167 POSIX_MQ.unlink(@path)
171 path = "" << @path.dup
173 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
174 assert_equal path, @mq.name
177 def test_new_readonly
178 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
179 rd = POSIX_MQ.new @path, IO::RDONLY
180 assert_equal @mq.name, rd.name
184 def test_send0_receive
185 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
186 assert_equal(@mq, @mq << "hello")
187 assert_equal [ "hello", 0 ], @mq.receive
191 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
192 @mq << "hello" << "world"
193 assert_equal [ "hello", 0 ], @mq.receive
194 assert_equal [ "world", 0 ], @mq.receive
198 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
200 assert_equal "hello", @mq.shift
205 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
207 assert_equal "hello", @mq.shift(buf)
208 assert_equal "hello", buf
211 def test_send_receive
212 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
213 assert_equal true, @mq.send("hello", 0)
214 assert_equal [ "hello", 0 ], @mq.receive
217 def test_send_receive_buf
219 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
220 assert_equal true, @mq.send("hello", 0)
221 assert_equal [ "hello", 0 ], @mq.receive(buf)
222 assert_equal "hello", buf
225 def test_send_receive_prio
226 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
227 assert_equal true, @mq.send("hello", 2)
228 assert_equal [ "hello", 2 ], @mq.receive
232 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
234 assert_equal POSIX_MQ::Attr, mq_attr.class
235 assert mq_attr.flags.kind_of?(Integer)
236 assert mq_attr.maxmsg.kind_of?(Integer)
237 assert mq_attr.msgsize.kind_of?(Integer)
238 assert mq_attr.curmsgs.kind_of?(Integer)
242 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
243 assert @mq.to_io.kind_of?(IO)
244 assert_nothing_raised { IO.select([@mq], nil, nil, 0) }
245 end if POSIX_MQ.method_defined?(:to_io)
249 orig = trap(:USR1) { wr.syswrite('.') }
250 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
251 assert_nothing_raised { @mq.notify = :SIGUSR1 }
252 assert_nothing_raised { @mq.send("hello", 0) }
253 assert_equal [[rd], [], []], IO.select([rd], nil, nil, 10)
254 assert_equal '.', rd.sysread(1)
255 assert_nil(@mq.notify = nil)
256 assert_nothing_raised { @mq.send("hello", 0) }
257 assert_nil IO.select([rd], nil, nil, 0.1)
263 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
264 assert_nothing_raised { @mq.notify = false }
275 _, status = Process.waitpid2(pid)
276 assert status.success?, status.inspect
280 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
281 mq_attr = POSIX_MQ::Attr.new(IO::NONBLOCK)
283 assert_equal IO::NONBLOCK, @mq.attr.flags
284 assert mq_attr.flags.kind_of?(Integer)
288 assert_equal 0, @mq.attr.flags
291 def test_setattr_fork
292 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
293 mq_attr = POSIX_MQ::Attr.new(IO::NONBLOCK)
297 pid = fork { @mq.nonblock = false }
298 assert Process.waitpid2(pid)[1].success?
299 assert ! @mq.nonblock?
302 def test_new_nonblocking
303 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY|IO::NONBLOCK, 0666
307 def test_new_blocking
308 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
309 assert ! @mq.nonblock?
312 def test_nonblock_toggle
313 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
314 assert ! @mq.nonblock?
318 assert ! @mq.nonblock?
319 assert_raises(ArgumentError) { @mq.nonblock = nil }
323 @mq = POSIX_MQ.new @path, :w
324 assert_equal IO::WRONLY, @mq.to_io.fcntl(Fcntl::F_GETFL)
325 end if POSIX_MQ.method_defined?(:to_io)
328 @mq = POSIX_MQ.new @path, :w
330 assert_nothing_raised { mq = POSIX_MQ.new @path, :r }
331 assert_equal IO::RDONLY, mq.to_io.fcntl(Fcntl::F_GETFL)
333 end if POSIX_MQ.method_defined?(:to_io)
335 def test_new_path_only
336 @mq = POSIX_MQ.new @path, :w
338 assert_nothing_raised { mq = POSIX_MQ.new @path }
339 assert_equal IO::RDONLY, mq.to_io.fcntl(Fcntl::F_GETFL)
341 end if POSIX_MQ.method_defined?(:to_io)
344 @mq = POSIX_MQ.new @path, :rw
345 assert_equal IO::RDWR, @mq.to_io.fcntl(Fcntl::F_GETFL)
346 end if POSIX_MQ.method_defined?(:to_io)
349 mq_attr = POSIX_MQ::Attr.new(IO::NONBLOCK, 1, 1, 0)
350 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666, mq_attr
352 assert_equal mq_attr, @mq.attr
354 assert_raises(Errno::EAGAIN) { @mq.receive }
355 assert_raises(Errno::EMSGSIZE) { @mq << '..' }
356 assert_nothing_raised { @mq << '.' }
357 assert_equal [ '.', 0 ], @mq.receive
358 assert_nothing_raised { @mq << '.' }
359 assert_raises(Errno::EAGAIN) { @mq << '.' }
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_nil @mq.tryreceive
367 assert_nil @mq.tryshift
368 assert_equal true, @mq.trysend("a")
369 assert_equal [ "a", 0 ], @mq.tryreceive
370 assert_equal true, @mq.trysend("b")
371 assert_equal "b", @mq.tryshift
372 assert_equal true, @mq.trysend("c")
373 assert_equal false, @mq.trysend("d")
377 min_posix_mq_prio_max = 31 # defined by POSIX
378 assert POSIX_MQ::PRIO_MAX >= min_posix_mq_prio_max
382 assert POSIX_MQ::OPEN_MAX.kind_of?(Integer)
385 def test_notify_block_replace
387 @mq = POSIX_MQ.new(@path, :rw)
388 assert_nothing_raised { @mq.notify { |mq| q << mq } }
389 assert_nothing_raised { Process.waitpid2(fork { @mq << "hi" }) }
390 assert_equal @mq.object_id, q.pop.object_id
391 assert_equal "hi", @mq.receive.first
392 assert_nothing_raised { @mq.notify { |mq| q << "hi" } }
393 assert_nothing_raised { Process.waitpid2(fork { @mq << "bye" }) }
394 assert_equal "hi", q.pop
395 end if POSIX_MQ.method_defined?(:notify)
397 def test_notify_thread
399 @mq = POSIX_MQ.new(@path, :rw)
400 @mq.notify { |mq| q << Thread.current }
403 assert x.instance_of?(Thread)
404 assert Thread.current != x
405 end if POSIX_MQ.method_defined?(:notify)
407 def test_bad_open_mode
408 assert_raises(ArgumentError) { POSIX_MQ.new(@path, "rw") }
411 def test_bad_open_attr
412 assert_raises(TypeError) { POSIX_MQ.new(@path, :rw, 0666, [0, 1, 1, 0]) }
416 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
417 assert_raises(TypeError) { @mq.attr = {} }
418 assert_raises(TypeError) { @mq.attr = Struct.new(:a,:b,:c,:d).new }
423 assert_raises(exc) { } # FAIL
425 rescue Errno::ETIMEDOUT => e
427 rescue NotImplementedError => e