ruote 2.1.9 → 2.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/CHANGELOG.txt +32 -0
  2. data/CREDITS.txt +3 -0
  3. data/Rakefile +4 -4
  4. data/TODO.txt +55 -11
  5. data/examples/barley.rb +2 -1
  6. data/examples/flickr_report.rb +5 -6
  7. data/examples/web_first_page.rb +11 -0
  8. data/lib/ruote/context.rb +36 -13
  9. data/lib/ruote/engine.rb +88 -56
  10. data/lib/ruote/engine/process_error.rb +13 -0
  11. data/lib/ruote/engine/process_status.rb +33 -1
  12. data/lib/ruote/error_handler.rb +122 -0
  13. data/lib/ruote/evt/tracker.rb +27 -10
  14. data/lib/ruote/exp/fe_apply.rb +69 -0
  15. data/lib/ruote/exp/fe_participant.rb +33 -5
  16. data/lib/ruote/exp/flowexpression.rb +37 -5
  17. data/lib/ruote/exp/ro_persist.rb +8 -4
  18. data/lib/ruote/exp/ro_variables.rb +2 -2
  19. data/lib/ruote/fei.rb +59 -7
  20. data/lib/ruote/log/storage_history.rb +2 -0
  21. data/lib/ruote/log/test_logger.rb +28 -19
  22. data/lib/ruote/log/wait_logger.rb +4 -2
  23. data/lib/ruote/parser.rb +2 -1
  24. data/lib/ruote/part/dispatch_pool.rb +10 -10
  25. data/lib/ruote/part/engine_participant.rb +2 -2
  26. data/lib/ruote/part/local_participant.rb +99 -7
  27. data/lib/ruote/part/participant_list.rb +18 -7
  28. data/lib/ruote/part/storage_participant.rb +9 -6
  29. data/lib/ruote/receiver/base.rb +109 -10
  30. data/lib/ruote/storage/base.rb +118 -41
  31. data/lib/ruote/storage/fs_storage.rb +1 -0
  32. data/lib/ruote/storage/hash_storage.rb +2 -1
  33. data/lib/ruote/util/lookup.rb +22 -2
  34. data/lib/ruote/util/misc.rb +5 -5
  35. data/lib/ruote/version.rb +1 -1
  36. data/lib/ruote/worker.rb +50 -63
  37. data/lib/ruote/workitem.rb +64 -0
  38. data/ruote.gemspec +17 -12
  39. data/test/functional/base.rb +3 -1
  40. data/test/functional/concurrent_base.rb +35 -29
  41. data/test/functional/crunner.sh +19 -0
  42. data/test/functional/ct_0_concurrence.rb +17 -30
  43. data/test/functional/ct_1_iterator.rb +20 -17
  44. data/test/functional/ct_2_cancel.rb +32 -25
  45. data/test/functional/eft_12_listen.rb +2 -1
  46. data/test/functional/eft_23_apply.rb +23 -0
  47. data/test/functional/eft_3_participant.rb +27 -0
  48. data/test/functional/ft_11_recursion.rb +1 -1
  49. data/test/functional/ft_13_variables.rb +22 -0
  50. data/test/functional/ft_14_re_apply.rb +3 -0
  51. data/test/functional/ft_15_timeout.rb +1 -0
  52. data/test/functional/ft_20_storage_participant.rb +20 -2
  53. data/test/functional/ft_21_forget.rb +30 -0
  54. data/test/functional/ft_22_process_definitions.rb +2 -1
  55. data/test/functional/ft_24_block_participants.rb +1 -1
  56. data/test/functional/ft_25_receiver.rb +83 -1
  57. data/test/functional/ft_26_participant_timeout.rb +1 -1
  58. data/test/functional/ft_2_errors.rb +2 -5
  59. data/test/functional/ft_30_smtp_participant.rb +47 -45
  60. data/test/functional/ft_36_storage_history.rb +4 -4
  61. data/test/functional/ft_37_engine_participant.rb +14 -10
  62. data/test/functional/ft_38_participant_more.rb +178 -0
  63. data/test/functional/ft_39_wait_for.rb +100 -0
  64. data/test/functional/ft_40_participant_on_reply.rb +87 -0
  65. data/test/functional/ft_41_participants.rb +65 -0
  66. data/test/functional/ft_42_storage_copy.rb +67 -0
  67. data/test/functional/ft_5_on_error.rb +103 -0
  68. data/test/functional/ft_9_subprocesses.rb +2 -1
  69. data/test/functional/storage_helper.rb +5 -1
  70. data/test/functional/test.rb +4 -1
  71. data/test/functional/vertical.rb +46 -0
  72. data/test/unit/storage.rb +17 -1
  73. data/test/unit/storages.rb +27 -7
  74. data/test/unit/ut_11_lookup.rb +36 -0
  75. data/test/unit/ut_16_parser.rb +43 -0
  76. data/test/unit/ut_1_fei.rb +28 -1
  77. data/test/unit/ut_7_workitem.rb +23 -0
  78. metadata +67 -105
  79. data/lib/ruote/log/fs_history.rb +0 -182
  80. data/test/functional/ft_32_fs_history.rb +0 -188
  81. data/test/mpc_test.rb +0 -29
@@ -35,6 +35,8 @@ module FunctionalBase
35
35
 
36
36
  @engine.add_service('tracer', @tracer)
37
37
 
38
+ noisy if ARGV.include?('-n')
39
+
38
40
  #noisy # uncommented, it makes all the tests noisy
39
41
  end
40
42
 
@@ -96,7 +98,7 @@ module FunctionalBase
96
98
 
97
99
  def wait_for (*wfid_or_part)
98
100
 
99
- @engine.context.logger.wait_for(*wfid_or_part)
101
+ @engine.wait_for(*wfid_or_part)
100
102
  end
101
103
 
102
104
  def assert_engine_clean (wfid)
@@ -10,43 +10,49 @@ require File.join(File.dirname(__FILE__), 'base.rb')
10
10
 
11
11
  class Ruote::Worker
12
12
 
13
- def step_by_one
14
- msg = @storage.get_msgs.first
15
- #p [ msg['action'], msg['fei'] ]
16
- if msg
17
- process(msg)
18
- else
19
- false
20
- end
21
- end
22
-
23
13
  public :process
24
-
25
- def step_until (&block)
26
- loop do
27
- msg = @storage.get_msgs.first
28
- return msg if block.call(msg)
29
- process(msg)
30
- end
31
- end
32
14
  end
33
15
 
34
16
  class Ruote::Engine
35
- def step (count=1)
36
- count.times { @context.worker.step_by_one }
17
+
18
+ def peek_msg
19
+ @msgs = @context.storage.get_msgs if ( ! @msgs) || @msgs.size < 1
20
+ @msgs.shift
37
21
  end
38
- def step!
39
- r = @context.worker.step_by_one
40
- step! if r == false
22
+
23
+ def do_process (msg)
24
+ @context.worker.process(msg)
41
25
  end
42
- def walk
43
- while @context.worker.step_by_one do; end
26
+
27
+ def step (count)
28
+ return if count == 0
29
+ loop do
30
+ m = next_msg
31
+ next unless m
32
+ do_process(m)
33
+ break
34
+ end
35
+ step(count - 1)
44
36
  end
45
- def do_step (msg)
46
- @context.worker.process(msg)
37
+
38
+ def next_msg
39
+ loop do
40
+ if m = peek_msg
41
+ return m
42
+ end
43
+ end
47
44
  end
48
- def step_until (&block)
49
- @context.worker.step_until(&block)
45
+
46
+ def gather_msgs
47
+ (1..77).to_a.inject({}) { |h, i|
48
+ #(i % 10).times { Thread.pass }
49
+ sleep 0.001
50
+ m = peek_msg
51
+ h[m['_id']] = m if m
52
+ h
53
+ }.values.sort { |a, b|
54
+ a['put_at'] <=> b['put_at']
55
+ }
50
56
  end
51
57
  end
52
58
 
@@ -0,0 +1,19 @@
1
+ #!/bin/bash
2
+
3
+ TEST="test/functional/ct_0_concurrence.rb"
4
+ if [ $1 = "1" ]; then
5
+ TEST="test/functional/ct_1_iterator.rb"
6
+ fi
7
+ if [ $1 = "2" ]; then
8
+ TEST="test/functional/ct_2_cancel.rb"
9
+ fi
10
+
11
+ COUNT=0
12
+
13
+ while [ $? == 0 ]
14
+ do
15
+ echo " *** $COUNT"
16
+ ((COUNT=$COUNT + 1))
17
+ time ruby $TEST $1 $2
18
+ done
19
+
@@ -25,46 +25,33 @@ class CtConcurrenceTest < Test::Unit::TestCase
25
25
  #noisy
26
26
 
27
27
  wfid = @engine0.launch(pdef)
28
- @engine0.step 4
29
28
 
30
- msgs = @storage.get_msgs
31
- $stderr.puts "*cough*" if msgs.size != 2
32
- #msgs.each do |m|
33
- # p [ m['action'], m['fei']['expid'], m['workitem'] ]
34
- #end
29
+ replies = []
35
30
 
36
- t0 = Thread.new { @engine1.step! }
37
- t1 = Thread.new { @engine0.step! }
38
- t0.join
39
- t1.join
31
+ while replies.size < 2
40
32
 
41
- #t0 = Thread.new { @engine1.step }
42
- #@engine0.step
43
- #t0.join
33
+ msg = @engine0.next_msg
44
34
 
45
- msgs = @storage.get_msgs
46
- msg = msgs.first
35
+ if msg['action'] == 'reply'
36
+ replies << msg
37
+ else
38
+ @engine0.do_process(msg)
39
+ end
40
+ end
47
41
 
48
- if msgs.size > 1 || (msg && msg['fei'] && msg['fei']['expid'] != '0')
42
+ replies.sort! { |a, b| a['put_at'] <=> b['put_at'] }
49
43
 
50
- msgs.each do |m|
44
+ t0 = Thread.new { @engine1.do_process(replies[0]) }
45
+ t1 = Thread.new { @engine0.do_process(replies[1]) }
46
+ t0.join
47
+ t1.join
51
48
 
52
- fei = m['fei'] ?
53
- Ruote::FlowExpressionId.to_storage_id(m['fei']) : ''
54
- wi_fei = m['workitem'] ?
55
- Ruote::FlowExpressionId.to_storage_id(m['workitem']['fei']) : ''
49
+ msgs = @engine0.gather_msgs
56
50
 
57
- p [ m['action'], fei, wi_fei ]
58
- end
59
- end
51
+ assert_equal 1, msgs.size, 'exactly 1 message was expected'
60
52
 
61
- if msg['action'] == 'error_intercepted'
62
- #p @engine0.process(wfid).errors.first
63
- puts @engine0.process(wfid).errors.first.message
64
- puts @engine0.process(wfid).errors.first.trace
65
- end
53
+ msg = msgs.first
66
54
 
67
- assert_equal 1, msgs.size
68
55
  assert_equal 'reply', msg['action']
69
56
  assert_equal '0', msg['fei']['expid']
70
57
  end
@@ -30,32 +30,35 @@ class CtIteratorTest < Test::Unit::TestCase
30
30
 
31
31
  wfid = @engine0.launch(pdef)
32
32
 
33
- #@engine0.step 11
34
- msg = @engine0.step_until { |msg| msg['command'] != nil }
33
+ stop_msg = nil
35
34
 
36
- assert_equal 'stop', msg['command'].first
37
- assert_equal '0_0_0', msg['fei']['expid']
38
-
39
- msgs = @storage.get_msgs
40
-
41
- assert_equal 3, msgs.size
42
-
43
- msgs = msgs - [ msg ]
35
+ loop do
36
+ m = @engine0.next_msg
37
+ if m['command']
38
+ stop_msg = m
39
+ break
40
+ end
41
+ @engine0.do_process(m)
42
+ end
44
43
 
45
- assert_equal 2, msgs.size
44
+ assert_equal 'stop', stop_msg['command'].first
45
+ assert_equal '0_0_0', stop_msg['fei']['expid']
46
46
 
47
- msg1 = msgs.first
47
+ msg = @engine0.next_msg
48
48
 
49
- t0 = Thread.new { @engine1.do_step(msg) }
50
- t1 = Thread.new { @engine0.do_step(msg1) }
49
+ t0 = Thread.new { @engine1.do_process(stop_msg) }
50
+ t1 = Thread.new { @engine0.do_process(msg) }
51
51
  t0.join
52
52
  t1.join
53
53
 
54
- #@engine0.step 4
55
- @engine1.walk
54
+ loop do
55
+ m = @engine0.next_msg
56
+ break if m['action'] == 'terminated'
57
+ @engine0.do_process(m)
58
+ end
56
59
 
57
60
  assert_equal "1\n2", @tracer0.to_s
58
- assert_equal "", @tracer1.to_s
61
+ assert_equal '', @tracer1.to_s
59
62
  end
60
63
  end
61
64
 
@@ -27,43 +27,50 @@ class CtCancelTest < Test::Unit::TestCase
27
27
 
28
28
  wfid = @engine0.launch(pdef)
29
29
 
30
- @engine0.step 6
30
+ @engine0.step 7
31
31
 
32
- @engine1.cancel_expression(
33
- { 'engine_id' => 'engine', 'wfid' => wfid, 'expid' => '0_0' })
32
+ dispatched_seen = false
33
+ reply_msg = nil
34
34
 
35
- msgs = nil
36
35
  loop do
37
- msgs = @storage.get_msgs
38
- break if msgs.size == 2
39
- #p msgs.collect { |m| m['fei']['expid'] }.uniq
40
- #break if
41
- # msgs.size == 2 &&
42
- # msgs.collect { |m| m['fei']['expid'] }.uniq == %w[ 0_0 ]
36
+ m = @engine0.next_msg
37
+ ma = m['action']
38
+ if ma == 'dispatched'
39
+ dispatched_seen = true
40
+ @engine0.do_process(m)
41
+ break if reply_msg
42
+ elsif ma == 'reply'
43
+ reply_msg = m
44
+ break
45
+ else
46
+ @engine0.do_process(m)
47
+ end
43
48
  end
44
49
 
45
- #msgs.each { |m| p m }
46
- #puts
50
+ #p dispatched_seen
47
51
 
48
- t1 = Thread.new { @engine1.do_step(msgs[1]) }
49
- t0 = Thread.new { @engine0.do_step(msgs[0]) }
50
- t1.join
51
- t0.join
52
+ @engine0.cancel_expression(
53
+ { 'engine_id' => 'engine', 'wfid' => wfid, 'expid' => '0_0' })
52
54
 
53
- #puts
55
+ msgs = @engine0.gather_msgs
54
56
 
55
- @engine0.step 4
57
+ msgs = msgs - [ reply_msg ]
56
58
 
57
- sleep 0.010
59
+ assert_equal 1, msgs.size
60
+ assert_equal 'cancel', msgs.first['action']
58
61
 
59
- assert_equal 0, @storage.get_msgs.size
62
+ t1 = Thread.new { @engine1.do_process(msgs.first) }
63
+ t0 = Thread.new { @engine0.do_process(reply_msg) }
64
+ t1.join
65
+ t0.join
60
66
 
61
- exps = @storage.get_many('expressions')
62
- exps.each { |exp|
63
- p [ exp['fei']['expid'], exp['original_tree'] ]
64
- } if exps.size > 0
67
+ loop do
68
+ m = @engine0.next_msg
69
+ @engine0.do_process(m)
70
+ break if m['action'] == 'terminated'
71
+ end
65
72
 
66
- assert_equal 0, exps.size
73
+ assert_nil @engine0.process(wfid)
67
74
  end
68
75
  end
69
76
 
@@ -70,6 +70,8 @@ class EftListenTest < Test::Unit::TestCase
70
70
  wait_for(:bravo)
71
71
  wait_for(2)
72
72
 
73
+ sleep 0.001
74
+
73
75
  #p @tracer.to_s
74
76
 
75
77
  a = @tracer.to_a
@@ -231,7 +233,6 @@ class EftListenTest < Test::Unit::TestCase
231
233
  lwfid = @engine.launch(listening)
232
234
  ewfid = @engine.launch(emitting)
233
235
 
234
- wait_for(lwfid, ewfid)
235
236
  wait_for(lwfid, ewfid)
236
237
 
237
238
  #assert_equal("edone.\nldone.", @tracer.to_s)
@@ -141,5 +141,28 @@ class EftApplyTest < Test::Unit::TestCase
141
141
 
142
142
  assert_trace('nada', pdef)
143
143
  end
144
+
145
+ def test_apply_on_error
146
+
147
+ pdef = Ruote.process_definition do
148
+ handle do
149
+ sequence do
150
+ echo 'in'
151
+ nemo
152
+ end
153
+ end
154
+ define 'handle' do
155
+ apply :on_error => 'notify'
156
+ echo 'over.'
157
+ end
158
+ define 'notify' do
159
+ echo 'error'
160
+ end
161
+ end
162
+
163
+ #noisy
164
+
165
+ assert_trace(%w[ in error over. ], pdef)
166
+ end
144
167
  end
145
168
 
@@ -28,6 +28,7 @@ class EftParticipantTest < Test::Unit::TestCase
28
28
  assert_trace 'alpha', pdef
29
29
 
30
30
  assert_log_count(1) { |e| e['action'] == 'dispatch' }
31
+ assert_log_count(1) { |e| e['action'] == 'dispatched' }
31
32
  assert_log_count(1) { |e| e['action'] == 'receive' }
32
33
  end
33
34
 
@@ -118,5 +119,31 @@ class EftParticipantTest < Test::Unit::TestCase
118
119
  { "commander of the left guard"=>nil, "if"=>"true", "ref"=>"notify" },
119
120
  atts)
120
121
  end
122
+
123
+ def test_dispatched
124
+
125
+ part = @engine.register_participant :alpha do
126
+ sleep 1
127
+ end
128
+
129
+ pdef = Ruote.process_definition do
130
+ alpha
131
+ end
132
+
133
+ #noisy
134
+
135
+ wfid = @engine.launch(pdef)
136
+
137
+ wait_for(:alpha)
138
+
139
+ ps = @engine.process(wfid)
140
+
141
+ fexp = ps.expressions.find { |fe|
142
+ fe.class == Ruote::Exp::ParticipantExpression
143
+ }
144
+
145
+ assert_equal nil, fexp.dispatched
146
+ # not yet 'dispatched'
147
+ end
121
148
  end
122
149
 
@@ -105,7 +105,7 @@ class FtRecursionTest < Test::Unit::TestCase
105
105
 
106
106
  6.times { wait_for(:alpha) }
107
107
 
108
- Thread.pass
108
+ wait_for(1)
109
109
 
110
110
  assert_equal((1..6).to_a.join("\n"), @tracer.to_s)
111
111
  end
@@ -127,5 +127,27 @@ class FtVariablesTest < Test::Unit::TestCase
127
127
  assert_match(/^0||\d+_\d+$/, results[1])
128
128
  assert_match(/^0\_0|\d+|\d+_\d+$/, results[2])
129
129
  end
130
+
131
+ def test_lookup_in_var
132
+
133
+ @engine.register_participant :echo_toto do |wi, fexp|
134
+ @tracer << fexp.lookup_variable('toto').join
135
+ @tracer << "\n"
136
+ end
137
+
138
+ pdef = Ruote.process_definition do
139
+
140
+ set 'v:toto' => %w[ a b c ]
141
+ echo '${v:toto.1}'
142
+
143
+ set 'v:toto.2' => 'C'
144
+ echo_toto
145
+
146
+ unset 'v:toto.1'
147
+ echo_toto
148
+ end
149
+
150
+ assert_trace(%w[ b abC aC ], pdef)
151
+ end
130
152
  end
131
153
 
@@ -91,6 +91,8 @@ class FtReApplyTest < Test::Unit::TestCase
91
91
  wfid = @engine.launch(PDEF)
92
92
  wait_for(:alpha)
93
93
 
94
+ sleep 0.350 # threaded dispatch
95
+
94
96
  id0 = alpha.first.object_id
95
97
 
96
98
  # ... flow stalled ...
@@ -101,6 +103,7 @@ class FtReApplyTest < Test::Unit::TestCase
101
103
 
102
104
  stalled_exp.update_tree([
103
105
  'participant', { 'ref' => 'alpha', 'activity' => 'mow lawn' }, [] ])
106
+ #p [ :stalled, stalled_exp.h['_rev'] ]
104
107
  stalled_exp.persist
105
108
 
106
109
  @engine.re_apply(stalled_exp.fei)