ruote 2.1.9 → 2.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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)