remove rb_time_interval() and gettimeofday() dependency
[ruby_posix_mq.git] / test / test_posix_mq.rb
blob1f5c9b44a88e5838a3aa02f4a271e9ca4c004c65
1 # -*- encoding: binary -*-
2 require 'test/unit'
3 require 'posix_mq'
4 require 'thread'
5 require 'fcntl'
6 $stderr.sync = $stdout.sync = true
8 class Test_POSIX_MQ < Test::Unit::TestCase
10   POSIX_MQ.method_defined?(:to_io) or
11     warn "POSIX_MQ#to_io not supported on this platform: #{RUBY_PLATFORM}"
12   POSIX_MQ.method_defined?(:notify) or
13     warn "POSIX_MQ#notify not supported on this platform: #{RUBY_PLATFORM}"
15   def setup
16     @mq = nil
17     @path = "/posix_mq.rb.#{Time.now.to_i}.#$$.#{rand}"
18   end
20   def teardown
21     @mq or return
22     assert_equal @mq, @mq.unlink
23     assert ! @mq.closed?
24     assert_nil @mq.close
25     assert @mq.closed?
26   end
28   def test_gc
29     assert_nothing_raised do
30       2025.times { POSIX_MQ.new(@path, :rw) }
31       2025.times { @mq = POSIX_MQ.new(@path, :rw); @mq.to_io }
32     end
33   end
35   def test_name_clobber_proof
36     @mq = POSIX_MQ.new(@path, :rw)
37     tmp = @mq.name
38     tmp.freeze
39     assert_nothing_raised { @mq.name.gsub!(/\A/, "foo") }
40     assert_equal tmp, @mq.name
41     assert tmp.object_id != @mq.name.object_id
42   end
44   def test_dup_clone
45     @mq = POSIX_MQ.new(@path, :rw)
46     dup = @mq.dup
47     assert_equal @mq.object_id, dup.object_id
48     clone = @mq.clone
49     assert_equal @mq.object_id, clone.object_id
50   end
52   def test_timed_receive_float
53     interval = 0.01
54     @mq = POSIX_MQ.new(@path, :rw)
55     assert ! @mq.nonblock?
56     t0 = Time.now
57     assert_raises(Errno::ETIMEDOUT) { @mq.receive "", interval }
58     elapsed = Time.now - t0
59     assert elapsed > interval, elapsed.inspect
60     assert elapsed < 0.02, elapsed.inspect
61   end
63   def test_timed_receive_divmod
64     interval = Object.new
65     def interval.divmod(num)
66       num == 1 ? [ 0, 0.01 ] : nil
67     end
68     @mq = POSIX_MQ.new(@path, :rw)
69     assert ! @mq.nonblock?
70     t0 = Time.now
71     assert_raises(Errno::ETIMEDOUT) { @mq.receive "", interval }
72     elapsed = Time.now - t0
73     assert elapsed >= 0.01, elapsed.inspect
74     assert elapsed <= 0.02, elapsed.inspect
75   end
77   def test_timed_receive_fixnum
78     interval = 1
79     @mq = POSIX_MQ.new(@path, :rw)
80     assert ! @mq.nonblock?
81     t0 = Time.now
82     assert_raises(Errno::ETIMEDOUT) { @mq.receive "", interval }
83     elapsed = Time.now - t0
84     assert elapsed >= interval, elapsed.inspect
85     assert elapsed < 1.10, elapsed.inspect
86   end
88   def test_timed_send
89     interval = 0.01
90     @mq = POSIX_MQ.new(@path, :rw, 0666, POSIX_MQ::Attr[0, 1, 1, 0])
91     assert ! @mq.nonblock?
92     assert_nothing_raised { @mq.send "A", 1, interval }
93     t0 = Time.now
94     assert_raises(Errno::ETIMEDOUT) { @mq.send "B", 1, interval }
95     elapsed = Time.now - t0
96     assert elapsed > interval
97   end
99   def test_open
100     POSIX_MQ.open(@path, IO::CREAT|IO::WRONLY, 0666) do |mq|
101       @mq = mq
102       assert mq.kind_of?(POSIX_MQ)
103       assert_equal @path, mq.name
104       assert_nil mq.send("HI", 0)
105       assert_equal 1, mq.attr.curmsgs
106       assert_nil mq.close
107       assert_raises(IOError) { mq.close }
108     end
109     assert @mq.closed?
110     @mq = nil
111     POSIX_MQ.unlink(@path)
112   end
114   def test_name
115     path = "" << @path.dup
116     path.freeze
117     @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
118     assert_equal path, @mq.name
119   end
121   def test_new_readonly
122     @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
123     rd = POSIX_MQ.new @path, IO::RDONLY
124     assert_equal @mq.name, rd.name
125     assert_nil rd.close
126   end
128   def test_send0_receive
129     @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
130     assert_equal(@mq, @mq << "hello")
131     assert_equal [ "hello", 0 ], @mq.receive
132   end
134   def test_send0_chain
135     @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
136     @mq << "hello" << "world"
137     assert_equal [ "hello", 0 ], @mq.receive
138     assert_equal [ "world", 0 ], @mq.receive
139   end
141   def test_shift
142     @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
143     @mq << "hello"
144     assert_equal "hello", @mq.shift
145   end
147   def test_shift_buf
148     buf = ""
149     @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
150     @mq << "hello"
151     assert_equal "hello", @mq.shift(buf)
152     assert_equal "hello", buf
153   end
155   def test_send_receive
156     @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
157     assert_nil @mq.send("hello", 0)
158     assert_equal [ "hello", 0 ], @mq.receive
159   end
161   def test_send_receive_buf
162     buf = ""
163     @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
164     assert_nil @mq.send("hello", 0)
165     assert_equal [ "hello", 0 ], @mq.receive(buf)
166     assert_equal "hello", buf
167   end
169   def test_send_receive_prio
170     @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
171     assert_nil @mq.send("hello", 2)
172     assert_equal [ "hello", 2 ], @mq.receive
173   end
175   def test_getattr
176     @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
177     mq_attr = @mq.attr
178     assert_equal POSIX_MQ::Attr, mq_attr.class
179     assert mq_attr.flags.kind_of?(Integer)
180     assert mq_attr.maxmsg.kind_of?(Integer)
181     assert mq_attr.msgsize.kind_of?(Integer)
182     assert mq_attr.curmsgs.kind_of?(Integer)
183   end
185   def test_to_io
186     @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
187     assert @mq.to_io.kind_of?(IO)
188     assert_nothing_raised { IO.select([@mq], nil, nil, 0) }
189   end if POSIX_MQ.method_defined?(:to_io)
191   def test_notify
192     rd, wr = IO.pipe
193     orig = trap(:USR1) { wr.syswrite('.') }
194     @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
195     assert_nothing_raised { @mq.notify = :SIGUSR1 }
196     assert_nothing_raised { @mq.send("hello", 0) }
197     assert_equal [[rd], [], []], IO.select([rd], nil, nil, 10)
198     assert_equal '.', rd.sysread(1)
199     assert_nil(@mq.notify = nil)
200     assert_nothing_raised { @mq.send("hello", 0) }
201     assert_nil IO.select([rd], nil, nil, 0.1)
202     ensure
203       trap(:USR1, orig)
204   end
206   def test_notify_none
207     @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666
208     assert_nothing_raised { @mq.notify = false }
209     pid = fork do
210       begin
211         @mq.notify = :USR1
212       rescue Errno::EBUSY
213         exit 0
214       rescue => e
215         p e
216       end
217       exit! 1
218     end
219     _, status = Process.waitpid2(pid)
220     assert status.success?, status.inspect
221   end
223   def test_setattr
224     @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
225     mq_attr = POSIX_MQ::Attr.new(IO::NONBLOCK)
226     @mq.attr = mq_attr
227     assert_equal IO::NONBLOCK, @mq.attr.flags
228     assert mq_attr.flags.kind_of?(Integer)
230     mq_attr.flags = 0
231     @mq.attr = mq_attr
232     assert_equal 0, @mq.attr.flags
233   end
235   def test_new_nonblocking
236     @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY|IO::NONBLOCK, 0666
237     assert @mq.nonblock?
238   end
240   def test_new_blocking
241     @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
242     assert ! @mq.nonblock?
243   end
245   def test_nonblock_toggle
246     @mq = POSIX_MQ.new @path, IO::CREAT|IO::WRONLY, 0666
247     assert ! @mq.nonblock?
248     @mq.nonblock = true
249     assert @mq.nonblock?
250     @mq.nonblock = false
251     assert ! @mq.nonblock?
252     assert_raises(ArgumentError) { @mq.nonblock = nil }
253   end
255   def test_new_sym_w
256     @mq = POSIX_MQ.new @path, :w
257     assert_equal IO::WRONLY, @mq.to_io.fcntl(Fcntl::F_GETFL)
258   end if POSIX_MQ.method_defined?(:to_io)
260   def test_new_sym_r
261     @mq = POSIX_MQ.new @path, :w
262     mq = nil
263     assert_nothing_raised { mq = POSIX_MQ.new @path, :r }
264     assert_equal IO::RDONLY, mq.to_io.fcntl(Fcntl::F_GETFL)
265     assert_nil mq.close
266   end if POSIX_MQ.method_defined?(:to_io)
268   def test_new_path_only
269     @mq = POSIX_MQ.new @path, :w
270     mq = nil
271     assert_nothing_raised { mq = POSIX_MQ.new @path }
272     assert_equal IO::RDONLY, mq.to_io.fcntl(Fcntl::F_GETFL)
273     assert_nil mq.close
274   end if POSIX_MQ.method_defined?(:to_io)
276   def test_new_sym_wr
277     @mq = POSIX_MQ.new @path, :rw
278     assert_equal IO::RDWR, @mq.to_io.fcntl(Fcntl::F_GETFL)
279   end if POSIX_MQ.method_defined?(:to_io)
281   def test_new_attr
282     mq_attr = POSIX_MQ::Attr.new(IO::NONBLOCK, 1, 1, 0)
283     @mq = POSIX_MQ.new @path, IO::CREAT|IO::RDWR, 0666, mq_attr
284     assert @mq.nonblock?
285     assert_equal mq_attr, @mq.attr
287     assert_raises(Errno::EAGAIN) { @mq.receive }
288     assert_raises(Errno::EMSGSIZE) { @mq << '..' }
289     assert_nothing_raised { @mq << '.' }
290     assert_equal [ '.', 0 ], @mq.receive
291     assert_nothing_raised { @mq << '.' }
292     assert_raises(Errno::EAGAIN) { @mq << '.' }
293   end
295   def test_prio_max
296     min_posix_mq_prio_max = 31 # defined by POSIX
297     assert POSIX_MQ::PRIO_MAX >= min_posix_mq_prio_max
298   end
300   def test_open_max
301     assert POSIX_MQ::OPEN_MAX.kind_of?(Integer)
302   end
304   def test_notify_block_replace
305     q = Queue.new
306     @mq = POSIX_MQ.new(@path, :rw)
307     assert_nothing_raised { @mq.notify { |mq| q << mq } }
308     assert_nothing_raised { Process.waitpid2(fork { @mq << "hi" }) }
309     assert_equal @mq.object_id, q.pop.object_id
310     assert_equal "hi", @mq.receive.first
311     assert_nothing_raised { @mq.notify { |mq| q << "hi" } }
312     assert_nothing_raised { Process.waitpid2(fork { @mq << "bye" }) }
313     assert_equal "hi", q.pop
314   end if POSIX_MQ.method_defined?(:notify)
316   def test_notify_thread
317     q = Queue.new
318     @mq = POSIX_MQ.new(@path, :rw)
319     @mq.notify { |mq| q << Thread.current }
320     @mq << "."
321     x = q.pop
322     assert x.instance_of?(Thread)
323     assert Thread.current != x
324   end if POSIX_MQ.method_defined?(:notify)