Tag unstable CGI specs.
[rbx.git] / test / mri / rinda / test_rinda.rb
blobd663e0446d2fd6caba8a4664ce1075d0e36acea8
1 require 'test/unit'
3 require 'drb/drb'
4 require 'drb/eq'
5 require 'rinda/tuplespace'
7 require 'singleton'
9 module Rinda
11 class MockClock
12   include Singleton
14   class MyTS < Rinda::TupleSpace
15     def keeper
16       nil
17     end
18   end
19   
20   def initialize
21     @now = 2
22     @reso = 0.1
23     @ts = MyTS.new
24     @ts.write([2, :now])
25     @inf = 2**31 - 1
26   end
28   def now
29     @now.to_f
30   end
32   def at(n)
33     n
34   end
35     
36   def _forward(n=nil)
37     now ,= @ts.take([nil, :now])
38     @now = now + n
39     n = @reso if n.nil?
40     @ts.write([@now, :now])
41   end
43   def forward(n=nil)
44     while n > 0
45       _forward(@reso)
46       n -= @reso
47     end
48   end
50   def rewind
51     now ,= @ts.take([nil, :now])
52     @ts.write([@inf, :now])
53     @ts.take([nil, :now])
54     @now = 2
55     @ts.write([2, :now])
56   end
58   def sleep(n=nil)
59     while will_deadlock? 
60       n -= @reso
61       forward
62       return 0 if n <= 0
63     end
64     now ,= @ts.read([nil, :now])
65     @ts.read([(now + n)..@inf, :now])
66     0
67   end
69   def will_deadlock?
70     sz = Thread.current.group.list.find_all {|x| x.status != 'sleep'}.size
71     sz <= 1
72   end
73 end
75 module Time
76   def sleep(n)
77     @m.sleep(n)
78   end
79   module_function :sleep
81   def at(n)
82     n
83   end
84   module_function :at
86   def now
87     @m ? @m.now : 2
88   end
89   module_function :now
91   def rewind
92     @m.rewind
93   end
94   module_function :rewind
96   def forward(n)
97     @m.forward(n)
98   end
99   module_function :forward
101   @m = MockClock.instance
104 class TupleSpace
105   def sleep(n)
106     Time.sleep(n)
107   end
110 module TupleSpaceTestModule
111   def sleep(n)
112     if Thread.current == Thread.main
113       Time.forward(n)
114     else
115       Time.sleep(n)
116     end
117   end
118   
119   def test_00_tuple
120     tuple = Rinda::TupleEntry.new([1,2,3])
121     assert(!tuple.canceled?)
122     assert(!tuple.expired?)
123     assert(tuple.alive?)
124   end
126   def test_00_template
127     tmpl = Rinda::Template.new([1,2,3])
128     assert_equal(3, tmpl.size)
129     assert_equal(3, tmpl[2])
130     assert(tmpl.match([1,2,3]))
131     assert(!tmpl.match([1,nil,3]))
133     tmpl = Rinda::Template.new([/^rinda/i, nil, :hello])
134     assert_equal(3, tmpl.size)
135     assert(tmpl.match(['Rinda', 2, :hello]))
136     assert(!tmpl.match(['Rinda', 2, Symbol]))
137     assert(!tmpl.match([1, 2, :hello]))
138     assert(tmpl.match([/^rinda/i, 2, :hello]))
140     tmpl = Rinda::Template.new([Symbol])
141     assert_equal(1, tmpl.size)
142     assert(tmpl.match([:hello]))
143     assert(tmpl.match([Symbol]))
144     assert(!tmpl.match(['Symbol']))
146     tmpl = Rinda::Template.new({"message"=>String, "name"=>String})
147     assert_equal(2, tmpl.size)
148     assert(tmpl.match({"message"=>"Hello", "name"=>"Foo"}))
149     assert(!tmpl.match({"message"=>"Hello", "name"=>"Foo", "1"=>2}))
150     assert(!tmpl.match({"message"=>"Hi", "name"=>"Foo", "age"=>1}))
151     assert(!tmpl.match({"message"=>"Hello", "no_name"=>"Foo"}))
153     assert_raises(Rinda::InvalidHashTupleKey) do
154       tmpl = Rinda::Template.new({:message=>String, "name"=>String})
155     end
156     tmpl = Rinda::Template.new({"name"=>String})
157     assert_equal(1, tmpl.size)
158     assert(tmpl.match({"name"=>"Foo"}))
159     assert(!tmpl.match({"message"=>"Hello", "name"=>"Foo"}))
160     assert(!tmpl.match({"message"=>:symbol, "name"=>"Foo", "1"=>2}))
161     assert(!tmpl.match({"message"=>"Hi", "name"=>"Foo", "age"=>1}))
162     assert(!tmpl.match({"message"=>"Hello", "no_name"=>"Foo"}))
164     tmpl = Rinda::Template.new({"message"=>String, "name"=>String})
165     assert_equal(2, tmpl.size)
166     assert(tmpl.match({"message"=>"Hello", "name"=>"Foo"}))
167     assert(!tmpl.match({"message"=>"Hello", "name"=>"Foo", "1"=>2}))
168     assert(!tmpl.match({"message"=>"Hi", "name"=>"Foo", "age"=>1}))
169     assert(!tmpl.match({"message"=>"Hello", "no_name"=>"Foo"}))
171     tmpl = Rinda::Template.new({"message"=>String})
172     assert_equal(1, tmpl.size)
173     assert(tmpl.match({"message"=>"Hello"}))
174     assert(!tmpl.match({"message"=>"Hello", "name"=>"Foo"}))
175     assert(!tmpl.match({"message"=>"Hello", "name"=>"Foo", "1"=>2}))
176     assert(!tmpl.match({"message"=>"Hi", "name"=>"Foo", "age"=>1}))
177     assert(!tmpl.match({"message"=>"Hello", "no_name"=>"Foo"}))
179     tmpl = Rinda::Template.new({"message"=>String, "name"=>nil})
180     assert_equal(2, tmpl.size)
181     assert(tmpl.match({"message"=>"Hello", "name"=>"Foo"}))
182     assert(!tmpl.match({"message"=>"Hello", "name"=>"Foo", "1"=>2}))
183     assert(!tmpl.match({"message"=>"Hi", "name"=>"Foo", "age"=>1}))
184     assert(!tmpl.match({"message"=>"Hello", "no_name"=>"Foo"}))
186     assert_raises(Rinda::InvalidHashTupleKey) do
187       @ts.write({:message=>String, "name"=>String})
188     end
190     @ts.write([1, 2, 3])
191     assert_equal([1, 2, 3], @ts.take([1, 2, 3]))
193     @ts.write({'1'=>1, '2'=>2, '3'=>3})
194     assert_equal({'1'=>1, '2'=>2, '3'=>3}, @ts.take({'1'=>1, '2'=>2, '3'=>3}))
196     entry = @ts.write(['1'=>1, '2'=>2, '3'=>3])
197     assert_raises(Rinda::RequestExpiredError) do
198       assert_equal({'1'=>1, '2'=>2, '3'=>3}, @ts.read({'1'=>1}, 0))
199     end
200     entry.cancel
201   end
203   def test_00_DRbObject
204     ro = DRbObject.new(nil, "druby://host:1234")
205     tmpl = Rinda::DRbObjectTemplate.new
206     assert(tmpl === ro)
208     tmpl = Rinda::DRbObjectTemplate.new("druby://host:1234")
209     assert(tmpl === ro)
211     tmpl = Rinda::DRbObjectTemplate.new("druby://host:12345")
212     assert(!(tmpl === ro))
214     tmpl = Rinda::DRbObjectTemplate.new(/^druby:\/\/host:/)
215     assert(tmpl === ro)
217     ro = DRbObject.new_with(12345, 1234)
218     assert(!(tmpl === ro))
220     ro = DRbObject.new_with("druby://foo:12345", 1234)
221     assert(!(tmpl === ro))
223     tmpl = Rinda::DRbObjectTemplate.new(/^druby:\/\/(foo|bar):/)
224     assert(tmpl === ro)
226     ro = DRbObject.new_with("druby://bar:12345", 1234)
227     assert(tmpl === ro)
229     ro = DRbObject.new_with("druby://baz:12345", 1234)
230     assert(!(tmpl === ro))
231   end
233   def test_inp_rdp
234     assert_raises(Rinda::RequestExpiredError) do
235       @ts.take([:empty], 0)
236     end
238     assert_raises(Rinda::RequestExpiredError) do
239       @ts.read([:empty], 0)
240     end
241   end
243   def test_core_01
244     5.times do |n|
245       @ts.write([:req, 2])
246     end
248     assert_equal([[:req, 2], [:req, 2], [:req, 2], [:req, 2], [:req, 2]],
249                  @ts.read_all([nil, nil]))
251     taker = Thread.new do
252       s = 0
253       while true
254         begin
255           tuple = @ts.take([:req, Integer], 0.5)
256           assert_equal(2, tuple[1])
257           s += tuple[1]
258         rescue Rinda::RequestExpiredError
259           break
260         end
261       end
262       @ts.write([:ans, s])
263       s
264     end
265     
266     sleep(20)
267     tuple = @ts.take([:ans, nil])
268     assert_equal(10, tuple[1])
269     assert_equal(10, taker.value)
270   end
272   def test_core_02
273     taker = Thread.new do
274       s = 0
275       while true
276         begin
277           tuple = @ts.take([:req, Integer], 1.0)
278           assert_equal(2, tuple[1])
279           s += tuple[1]
280         rescue Rinda::RequestExpiredError
281           break
282         end
283       end
284       @ts.write([:ans, s])
285       s
286     end
288     5.times do |n|
289       @ts.write([:req, 2])
290     end
292     sleep(20)
293     tuple = @ts.take([:ans, nil])
294     assert_equal(10, tuple[1])
295     assert_equal(10, taker.value)
296     assert_equal([], @ts.read_all([nil, nil]))
297   end
298   
299   def test_core_03_notify
300     notify1 = @ts.notify(nil, [:req, Integer])
301     notify2 = @ts.notify(nil, [:ans, Integer], 5)
302     notify3 = @ts.notify(nil, {"message"=>String, "name"=>String}, 5)
304     @ts.write({"message"=>"first", "name"=>"3"}, 3)
305     @ts.write({"message"=>"second", "name"=>"1"}, 1)
306     @ts.write({"message"=>"third", "name"=>"0"})
307     @ts.take({"message"=>"third", "name"=>"0"})
309     listener1 = Thread.new do
310       lv = 0
311       n = 0
312       notify1.each  do |ev, tuple|
313         n += 1
314         if ev == 'write'
315           lv = lv + 1
316         elsif ev == 'take'
317           lv = lv - 1
318         else
319           break
320         end
321         assert(lv >= 0)
322         assert_equal([:req, 2], tuple)
323       end
324       [lv, n]
325     end
327     listener2 = Thread.new do
328       result = nil
329       lv = 0
330       n = 0
331       notify2.each  do |ev|
332         n += 1
333         if ev[0] == 'write'
334           lv = lv + 1
335         elsif ev[0] == 'take'
336           lv = lv - 1
337         elsif ev[0] == 'close'
338           result = [lv, n]
339         else
340           break
341         end
342         assert(lv >= 0)
343         assert_equal([:ans, 10], ev[1])
344       end
345       result
346     end
348     taker = Thread.new do
349       s = 0
350       while true
351         begin
352           tuple = @ts.take([:req, Integer], 1.0)
353           s += tuple[1]
354         rescue Rinda::RequestExpiredError
355           break
356         end
357       end
358       @ts.write([:ans, s])
359       s
360     end
362     writer = Thread.new do
363       5.times do |n|
364         @ts.write([:req, 2])
365         sleep 0.1
366       end
367     end
369     @ts.take({"message"=>"first", "name"=>"3"})
371     sleep(4)
372     tuple = @ts.take([:ans, nil])
373     assert_equal(10, tuple[1])
374     assert_equal(10, taker.value)
375     assert_equal([], @ts.read_all([nil, nil]))
376     
377     notify1.cancel
378     sleep(3) # notify2 expired
379     
380     assert_equal([0, 11], listener1.value)
381     assert_equal([0, 3], listener2.value)
383     ary = []
384     ary.push(["write", {"message"=>"first", "name"=>"3"}])
385     ary.push(["write", {"message"=>"second", "name"=>"1"}])
386     ary.push(["write", {"message"=>"third", "name"=>"0"}])
387     ary.push(["take", {"message"=>"third", "name"=>"0"}])
388     ary.push(["take", {"message"=>"first", "name"=>"3"}])
389     ary.push(["delete", {"message"=>"second", "name"=>"1"}])
390     ary.push(["close"])
392     notify3.each do |ev|
393       assert_equal(ary.shift, ev)
394     end
395     assert_equal([], ary)
396   end
398   def test_cancel_01
399     entry = @ts.write([:removeme, 1])
400     assert_equal([[:removeme, 1]], @ts.read_all([nil, nil]))
401     entry.cancel
402     assert_equal([], @ts.read_all([nil, nil]))
403     
404     template = nil
405     taker = Thread.new do
406       @ts.take([:take, nil], 10) do |template|
407         Thread.new do
408           sleep 0.2
409           template.cancel
410         end
411       end
412     end
413     
414     sleep(1)
415     assert(template.canceled?)
416     
417     @ts.write([:take, 1])
419     assert_raises(Rinda::RequestCanceledError) do
420       assert_nil(taker.value)
421     end
423     assert_equal([[:take, 1]], @ts.read_all([nil, nil]))
424   end
426   def test_cancel_02
427     entry = @ts.write([:removeme, 1])
428     assert_equal([[:removeme, 1]], @ts.read_all([nil, nil]))
429     entry.cancel
430     assert_equal([], @ts.read_all([nil, nil]))
432     template = nil
433     reader = Thread.new do
434       @ts.read([:take, nil], 10) do |template|
435         Thread.new do
436           sleep 0.2
437           template.cancel
438         end
439       end
440     end
442     sleep(1)
443     assert(template.canceled?)
444     
445     @ts.write([:take, 1])
447     assert_raises(Rinda::RequestCanceledError) do
448       assert_nil(reader.value)
449     end
451     assert_equal([[:take, 1]], @ts.read_all([nil, nil]))
452   end
454   class SimpleRenewer
455     def initialize(sec, n = 1)
456       @sec = sec
457       @n = n
458     end
459     
460     def renew
461       return -1 if @n <= 0
462       @n -= 1
463       return @sec
464     end
465   end
467   def test_00_renewer
468     tuple = Rinda::TupleEntry.new([1,2,3], true)
469     assert(!tuple.canceled?)
470     assert(tuple.expired?)
471     assert(!tuple.alive?)
472     
473     tuple = Rinda::TupleEntry.new([1,2,3], 1)
474     assert(!tuple.canceled?)
475     assert(!tuple.expired?)
476     assert(tuple.alive?)
477     sleep(2)
478     assert(tuple.expired?)
479     assert(!tuple.alive?)
481     tuple = Rinda::TupleEntry.new([1,2,3], SimpleRenewer.new(1,2))
482     assert(!tuple.canceled?)
483     assert(!tuple.expired?)
484     assert(tuple.alive?)
485     sleep(1.5)
486     assert(!tuple.canceled?)
487     assert(!tuple.expired?)
488     assert(tuple.alive?)
489     sleep(1.5)
490     assert(tuple.expired?)
491     assert(!tuple.alive?)
492   end
495 class TupleSpaceTest < Test::Unit::TestCase
496   include TupleSpaceTestModule
498   def setup
499     ThreadGroup.new.add(Thread.current)
500     @ts = Rinda::TupleSpace.new(1)
501   end
504 class TupleSpaceProxyTest < Test::Unit::TestCase
505   include TupleSpaceTestModule
507   def setup
508     ThreadGroup.new.add(Thread.current)
509     @ts_base = Rinda::TupleSpace.new(1)
510     @ts = Rinda::TupleSpaceProxy.new(@ts_base)
511   end
513   def test_remote_array_and_hash
514     @ts.write(DRbObject.new([1, 2, 3]))
515     assert_equal([1, 2, 3], @ts.take([1, 2, 3], 0))
516     @ts.write(DRbObject.new({'head' => 1, 'tail' => 2}))
517     assert_equal({'head' => 1, 'tail' => 2},
518                  @ts.take({'head' => 1, 'tail' => 2}, 0))
519   end
521   @server = DRb.primary_server || DRb.start_service