1 # -*- encoding: binary -*-
6 $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}"
18 @path = "/posix_mq.rb.#{Time.now.to_i}.#$$.#{rand}"
23 assert_equal @mq, @mq.unlink
29 def test_open_with_null_byte
30 assert_raises(ArgumentError) { POSIX_MQ.open("/hello\0world", :rw) }
33 def test_unlink_with_null_byte
34 assert_raises(ArgumentError) { POSIX_MQ.open("/hello\0world", :rw) }
38 assert_nothing_raised do
39 2025.times { POSIX_MQ.new(@path, :rw) }
41 @mq = POSIX_MQ.new(@path, :rw)
42 @mq.to_io if @mq.respond_to?(:to_io)
45 end unless defined?RUBY_ENGINE && RUBY_ENGINE == "rbx"
47 def test_name_clobber_proof
48 @mq = POSIX_MQ.new(@path, :rw)
51 assert_nothing_raised { @mq.name.gsub!(/\A/, "foo") }
52 assert_equal tmp, @mq.name
53 assert tmp.object_id != @mq.name.object_id
57 @mq = POSIX_MQ.new(@path, :rw)
59 assert_equal @mq.object_id, dup.object_id
61 assert_equal @mq.object_id, clone.object_id
64 def test_timed_receive_float
66 @mq = POSIX_MQ.new(@path, :rw)
67 assert ! @mq.nonblock?
69 maybe_timeout { @mq.receive "", interval } or return
70 elapsed = Time.now - t0
71 assert elapsed > interval, elapsed.inspect
72 assert elapsed < 0.02, elapsed.inspect
75 def test_timed_receive_divmod
77 def interval.divmod(num)
78 num == 1 ? [ 0, 0.01 ] : nil
80 @mq = POSIX_MQ.new(@path, :rw)
81 assert ! @mq.nonblock?
83 maybe_timeout { @mq.receive "", interval } or return
84 elapsed = Time.now - t0
85 assert elapsed >= 0.01, elapsed.inspect
86 assert elapsed <= 0.02, elapsed.inspect
89 def test_timed_receive_fixnum
91 @mq = POSIX_MQ.new(@path, :rw)
92 assert ! @mq.nonblock?
94 maybe_timeout { @mq.receive "", interval } or return
95 elapsed = Time.now - t0
96 assert elapsed >= interval, elapsed.inspect
97 assert elapsed < 1.10, elapsed.inspect
100 def test_alarm_signal_safe
102 libcs = %w(libc.so.6 /usr/lib/libc.sl)
104 libc = DL::Handle.new(name) rescue next
106 alarm = libc["alarm"]
107 alarm = Fiddle::Function.new(alarm, [DL::TYPE_INT], DL::TYPE_INT)
109 alarm = libc["alarm", "II"]
113 alarm or return warn "alarm() not found in #{libcs.inspect}"
115 trap("ALRM") { alarms += 1 }
118 @mq = POSIX_MQ.new(@path, :rw)
119 assert ! @mq.nonblock?
122 assert_raises(Errno::EINTR) { a = @mq.receive }
123 elapsed = Time.now - t0
125 assert elapsed >= interval, elapsed.inspect
126 assert elapsed < 1.10, elapsed.inspect
127 assert_equal 1, alarms
132 @mq = POSIX_MQ.new(@path, :rw, 0666, POSIX_MQ::Attr[0, 1, 1, 0])
133 assert ! @mq.nonblock?
134 assert_nothing_raised {
136 @mq.send "A", 1, interval
137 rescue NotImplementedError
142 maybe_timeout { @mq.send "B", 1, interval } or return
143 elapsed = Time.now - t0
144 assert elapsed > interval
148 POSIX_MQ.open(@path, IO::CREAT|IO::WRONLY, 0666) do |mq|
150 assert mq.kind_of?(POSIX_MQ)
151 assert_equal @path, mq.name
152 assert_nil mq.send("HI", 0)
153 assert_equal 1, mq.attr.curmsgs
155 assert_raises(IOError) { mq.close }
159 POSIX_MQ.unlink(@path)
163 path = "" << @path.dup
165 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
166 assert_equal path, @mq.name
169 def test_new_readonly
170 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
171 rd = POSIX_MQ.new @path, IO::RDONLY
172 assert_equal @mq.name, rd.name
176 def test_send0_receive
177 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
178 assert_equal(@mq, @mq << "hello")
179 assert_equal [ "hello", 0 ], @mq.receive
183 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
184 @mq << "hello" << "world"
185 assert_equal [ "hello", 0 ], @mq.receive
186 assert_equal [ "world", 0 ], @mq.receive
190 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
192 assert_equal "hello", @mq.shift
197 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
199 assert_equal "hello", @mq.shift(buf)
200 assert_equal "hello", buf
203 def test_send_receive
204 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
205 assert_nil @mq.send("hello", 0)
206 assert_equal [ "hello", 0 ], @mq.receive
209 def test_send_receive_buf
211 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
212 assert_nil @mq.send("hello", 0)
213 assert_equal [ "hello", 0 ], @mq.receive(buf)
214 assert_equal "hello", buf
217 def test_send_receive_prio
218 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
219 assert_nil @mq.send("hello", 2)
220 assert_equal [ "hello", 2 ], @mq.receive
224 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
226 assert_equal POSIX_MQ::Attr, mq_attr.class
227 assert mq_attr.flags.kind_of?(Integer)
228 assert mq_attr.maxmsg.kind_of?(Integer)
229 assert mq_attr.msgsize.kind_of?(Integer)
230 assert mq_attr.curmsgs.kind_of?(Integer)
234 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
235 assert @mq.to_io.kind_of?(IO)
236 assert_nothing_raised { IO.select([@mq], nil, nil, 0) }
237 end if POSIX_MQ.method_defined?(:to_io)
241 orig = trap(:USR1) { wr.syswrite('.') }
242 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
243 assert_nothing_raised { @mq.notify = :SIGUSR1 }
244 assert_nothing_raised { @mq.send("hello", 0) }
245 assert_equal [[rd], [], []], IO.select([rd], nil, nil, 10)
246 assert_equal '.', rd.sysread(1)
247 assert_nil(@mq.notify = nil)
248 assert_nothing_raised { @mq.send("hello", 0) }
249 assert_nil IO.select([rd], nil, nil, 0.1)
255 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
256 assert_nothing_raised { @mq.notify = false }
267 _, status = Process.waitpid2(pid)
268 assert status.success?, status.inspect
272 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
273 mq_attr = POSIX_MQ::Attr.new(IO::NONBLOCK)
275 assert_equal IO::NONBLOCK, @mq.attr.flags
276 assert mq_attr.flags.kind_of?(Integer)
280 assert_equal 0, @mq.attr.flags
283 def test_setattr_fork
284 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
285 mq_attr = POSIX_MQ::Attr.new(IO::NONBLOCK)
289 pid = fork { @mq.nonblock = false }
290 assert Process.waitpid2(pid)[1].success?
291 assert ! @mq.nonblock?
294 def test_new_nonblocking
295 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY|IO::NONBLOCK, 0666
299 def test_new_blocking
300 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
301 assert ! @mq.nonblock?
304 def test_nonblock_toggle
305 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
306 assert ! @mq.nonblock?
310 assert ! @mq.nonblock?
311 assert_raises(ArgumentError) { @mq.nonblock = nil }
315 @mq = POSIX_MQ.new @path, :w
316 assert_equal IO::WRONLY, @mq.to_io.fcntl(Fcntl::F_GETFL)
317 end if POSIX_MQ.method_defined?(:to_io)
320 @mq = POSIX_MQ.new @path, :w
322 assert_nothing_raised { mq = POSIX_MQ.new @path, :r }
323 assert_equal IO::RDONLY, mq.to_io.fcntl(Fcntl::F_GETFL)
325 end if POSIX_MQ.method_defined?(:to_io)
327 def test_new_path_only
328 @mq = POSIX_MQ.new @path, :w
330 assert_nothing_raised { mq = POSIX_MQ.new @path }
331 assert_equal IO::RDONLY, mq.to_io.fcntl(Fcntl::F_GETFL)
333 end if POSIX_MQ.method_defined?(:to_io)
336 @mq = POSIX_MQ.new @path, :rw
337 assert_equal IO::RDWR, @mq.to_io.fcntl(Fcntl::F_GETFL)
338 end if POSIX_MQ.method_defined?(:to_io)
341 mq_attr = POSIX_MQ::Attr.new(IO::NONBLOCK, 1, 1, 0)
342 @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666, mq_attr
344 assert_equal mq_attr, @mq.attr
346 assert_raises(Errno::EAGAIN) { @mq.receive }
347 assert_raises(Errno::EMSGSIZE) { @mq << '..' }
348 assert_nothing_raised { @mq << '.' }
349 assert_equal [ '.', 0 ], @mq.receive
350 assert_nothing_raised { @mq << '.' }
351 assert_raises(Errno::EAGAIN) { @mq << '.' }
355 min_posix_mq_prio_max = 31 # defined by POSIX
356 assert POSIX_MQ::PRIO_MAX >= min_posix_mq_prio_max
360 assert POSIX_MQ::OPEN_MAX.kind_of?(Integer)
363 def test_notify_block_replace
365 @mq = POSIX_MQ.new(@path, :rw)
366 assert_nothing_raised { @mq.notify { |mq| q << mq } }
367 assert_nothing_raised { Process.waitpid2(fork { @mq << "hi" }) }
368 assert_equal @mq.object_id, q.pop.object_id
369 assert_equal "hi", @mq.receive.first
370 assert_nothing_raised { @mq.notify { |mq| q << "hi" } }
371 assert_nothing_raised { Process.waitpid2(fork { @mq << "bye" }) }
372 assert_equal "hi", q.pop
373 end if POSIX_MQ.method_defined?(:notify)
375 def test_notify_thread
377 @mq = POSIX_MQ.new(@path, :rw)
378 @mq.notify { |mq| q << Thread.current }
381 assert x.instance_of?(Thread)
382 assert Thread.current != x
383 end if POSIX_MQ.method_defined?(:notify)
385 def test_bad_open_mode
386 assert_raises(ArgumentError) { mq = POSIX_MQ.new(@path, "rw") }
389 def test_bad_open_attr
390 assert_raises(TypeError) { POSIX_MQ.new(@path, :rw, 0666, [0, 1, 1, 0]) }
394 @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
395 assert_raises(TypeError) { @mq.attr = {} }
396 assert_raises(TypeError) { @mq.attr = Struct.new(:a,:b,:c,:d).new }
401 assert_raises(exc) { } # FAIL
403 rescue Errno::ETIMEDOUT => e
405 rescue NotImplementedError => e