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
@@ -30,6 +30,54 @@ class FtOnErrorTest < Test::Unit::TestCase
30
30
  assert_equal 1, logger.log.select { |e| e['action'] == 'fail' }.size
31
31
  end
32
32
 
33
+ def test_on_error_unknown_participant_name
34
+
35
+ pdef = Ruote.process_definition :name => 'test' do
36
+ participant :mark_started
37
+ sequence :on_error => :mark_failed do
38
+ participant :bogus
39
+ end
40
+ participant :mark_finished
41
+ end
42
+
43
+ @marks = []
44
+
45
+ @engine.register_participant 'mark\_.+' do |workitem|
46
+ @marks << workitem.participant_name
47
+ end
48
+
49
+ #noisy
50
+
51
+ wfid = @engine.launch(pdef)
52
+
53
+ wait_for(wfid)
54
+
55
+ assert_equal %w[ mark_started mark_failed mark_finished ], @marks
56
+ end
57
+
58
+ def test_on_error_unknown_participant_name_2
59
+
60
+ pdef = Ruote.process_definition :name => 'test' do
61
+ participant :mark_started
62
+ participant :bogus, :on_error => :mark_failed
63
+ participant :mark_finished
64
+ end
65
+
66
+ @marks = []
67
+
68
+ @engine.register_participant 'mark\_.+' do |workitem|
69
+ @marks << workitem.participant_name
70
+ end
71
+
72
+ #noisy
73
+
74
+ wfid = @engine.launch(pdef)
75
+
76
+ wait_for(wfid)
77
+
78
+ assert_equal %w[ mark_started mark_failed mark_finished ], @marks
79
+ end
80
+
33
81
  def test_on_error_neutralization
34
82
 
35
83
  pdef = Ruote.process_definition do
@@ -96,6 +144,26 @@ class FtOnErrorTest < Test::Unit::TestCase
96
144
  assert_nil @engine.process(wfid)
97
145
  end
98
146
 
147
+ def test_on_error_undo__pass
148
+
149
+ @engine.register_participant :nemo do |wi|
150
+ wi.fields['fail_count'] = 1
151
+ raise 'nemo'
152
+ end
153
+
154
+ pdef = Ruote.process_definition do
155
+ sequence do
156
+ echo 'in'
157
+ nemo :on_error => 'undo'
158
+ echo '${f:error}|${f:fail_count}'
159
+ end
160
+ end
161
+
162
+ wfid = assert_trace(%w[ in |1 ], pdef)
163
+
164
+ assert_nil @engine.process(wfid)
165
+ end
166
+
99
167
  def test_missing_handler_triggers_regular_error
100
168
 
101
169
  pdef = Ruote.process_definition :on_error => 'failpath' do
@@ -151,5 +219,40 @@ class FtOnErrorTest < Test::Unit::TestCase
151
219
  assert_equal 1, a_count
152
220
  assert_equal 1, e_count
153
221
  end
222
+
223
+ def test_participant_on_error
224
+
225
+ pdef = Ruote.process_definition do
226
+ troublemaker :on_error => 'handle_error'
227
+ define 'handle_error' do
228
+ troublespotter
229
+ end
230
+ end
231
+
232
+ workitem = nil
233
+
234
+ @engine.register_participant :troublemaker do |wi|
235
+ wi.fields['seen'] = true
236
+ raise 'Beijing, we have a problem !'
237
+ end
238
+ @engine.register_participant :troublespotter do |wi|
239
+ workitem = wi
240
+ @tracer << 'err...'
241
+ end
242
+
243
+ #noisy
244
+
245
+ wfid = @engine.launch(pdef)
246
+ wait_for(wfid)
247
+
248
+ #er = @engine.process(wfid).errors.first
249
+ #puts er.message
250
+ #puts er.trace
251
+
252
+ assert_equal 'err...', @tracer.to_s
253
+ assert_equal 4, workitem.error.size
254
+ assert_equal 'RuntimeError', workitem.error[2]
255
+ assert_equal true, workitem.fields['seen']
256
+ end
154
257
  end
155
258
 
@@ -82,8 +82,9 @@ class FtSubprocessesTest < Test::Unit::TestCase
82
82
 
83
83
  wait_for(:alpha)
84
84
  wait_for(:alpha)
85
- wait_for(1)
85
+ wait_for(3)
86
86
 
87
+ assert_equal 2, wfids.size
87
88
  assert_equal 2, wfids.sort.uniq.size
88
89
  end
89
90
 
@@ -66,7 +66,11 @@ else uses the in-memory Ruote::Engine (fastest, but no persistence at all)
66
66
  lib, path = pers
67
67
  $:.unshift(File.join(path, 'lib'))
68
68
 
69
- load File.join(path, %w[ test integration_connection.rb ])
69
+ begin
70
+ load File.join(path, %w[ test functional_connection.rb ])
71
+ rescue LoadError => le
72
+ load File.join(path, %w[ test integration_connection.rb ])
73
+ end
70
74
 
71
75
  new_storage(opts)
72
76
 
@@ -15,7 +15,10 @@ def l (t)
15
15
  puts "=== #{t} :"
16
16
  puts `ruby#{_v} #{t} #{ARGV.join(' ')}`
17
17
 
18
- exit $?.exitstatus if $?.exitstatus != 0
18
+ es = $?.exitstatus
19
+ es = es.nil? ? 66 : es.to_s.to_i
20
+
21
+ exit(es) if es != 0
19
22
  else
20
23
  load(t)
21
24
  end
@@ -0,0 +1,46 @@
1
+
2
+ #require 'open3'
3
+
4
+ TEST = ARGV[0]
5
+
6
+ STORAGES = %w[ fs dm couch redis beanstalk ].unshift(nil)
7
+
8
+ unless TEST
9
+ puts %{
10
+
11
+ USAGE :
12
+
13
+ ruby test/functional/vertical.rb path/to/test.rb
14
+
15
+ will run the given test with against all the storage implementations.
16
+
17
+ #{STORAGES}
18
+
19
+ }
20
+ exit 0
21
+ end
22
+
23
+ STORAGES.each do |storage|
24
+
25
+ dashdash = `ruby -v`.match(/^ruby 1\.9\./) ? '' : '--'
26
+ storage = storage.nil? ? '' : "--#{storage}"
27
+
28
+ command = "ruby #{TEST} #{dashdash} #{storage}"
29
+ puts('-' * 80)
30
+ puts("#{command}")
31
+
32
+ #Open3.popen3("#{command} 2>&1") do |_, stdout, _|
33
+ # loop do
34
+ # s = stdout.read(7)
35
+ # break unless s
36
+ # $stdout.print(s)
37
+ # $stdout.flush
38
+ # end
39
+ #end
40
+ # popen3 is nice, but it doesn't set $?
41
+
42
+ puts `#{command} 2>&1`
43
+
44
+ puts("\nFAILED\n\n") if $?.exitstatus.to_i != 0
45
+ end
46
+
@@ -24,6 +24,7 @@ class UtStorage < Test::Unit::TestCase
24
24
  'message' => 'testing')
25
25
  end
26
26
  def teardown
27
+
27
28
  @s.get_many('dogfood').each { |d| @s.delete(d) }
28
29
  end
29
30
 
@@ -92,6 +93,19 @@ class UtStorage < Test::Unit::TestCase
92
93
  assert_nil r
93
94
  end
94
95
 
96
+ def test_put_update_rev_twice
97
+
98
+ doc = { '_id' => 'ouinouin', 'type' => 'dogfood', 'message' => 'more' }
99
+
100
+ r = @s.put(doc, :update_rev => true)
101
+ assert_nil r
102
+
103
+ doc = { '_id' => 'ouinouin', 'type' => 'dogfood', 'message' => 'more' }
104
+
105
+ r = @s.put(doc, :update_rev => true)
106
+ assert_not_nil r
107
+ end
108
+
95
109
  def test_delete_fail
96
110
 
97
111
  assert_raise(ArgumentError) do
@@ -153,7 +167,7 @@ class UtStorage < Test::Unit::TestCase
153
167
  @s.put('_id' => 'nada', 'type' => 'dogfood', 'message' => 'testing')
154
168
  @s.put('_id' => 'estereo', 'type' => 'dogfood', 'message' => 'testing')
155
169
 
156
- assert_equal %w[ estereo nada ouinouin toto ], @s.ids('dogfood')
170
+ assert_equal %w[ estereo nada ouinouin toto ], @s.ids('dogfood').sort
157
171
  end
158
172
 
159
173
  def test_get_many
@@ -165,6 +179,8 @@ class UtStorage < Test::Unit::TestCase
165
179
  assert_equal 31, @s.get_many('dogfood').size
166
180
  assert_equal 10, @s.get_many('dogfood', nil, :limit => 10).size
167
181
  assert_equal 1, @s.get_many('dogfood', /!7$/).size
182
+ assert_equal 30, @s.get_many('dogfood', /^xx!/).size
183
+ assert_equal 30, @s.get_many('dogfood', /x/).size
168
184
  end
169
185
  end
170
186
 
@@ -1,17 +1,37 @@
1
1
 
2
- puts "\n\n\n== in memory"
2
+ dashdash = `ruby -v`.match(/^ruby 1\.9\./) ? '' : '--'
3
+
4
+ puts("\n\n== in memory")
3
5
  puts
4
6
  puts `ruby test/unit/storage.rb`
7
+ puts("\nFAILED") if $?.exitstatus.to_i != 0
8
+
9
+ puts("\n\n== fs")
10
+ puts
11
+ puts `ruby test/unit/storage.rb #{dashdash} --fs`
12
+ puts("\nFAILED") if $?.exitstatus.to_i != 0
13
+
14
+ puts("\n\n== route-couch")
15
+ puts
16
+ #puts `ruby -r patron -r yajl test/unit/storage.rb #{dashdash} --couch`
17
+ puts `ruby test/unit/storage.rb #{dashdash} --couch`
18
+ puts("\nFAILED") if $?.exitstatus.to_i != 0
5
19
 
6
- puts "\n\n\n== fs_storage"
20
+ puts("\n\n== route-dm")
7
21
  puts
8
- puts `ruby test/unit/storage.rb --fs`
22
+ #puts `ruby -r yajl test/unit/storage.rb #{dashdash} --dm`
23
+ puts `ruby test/unit/storage.rb #{dashdash} --dm`
24
+ puts("\nFAILED") if $?.exitstatus.to_i != 0
9
25
 
10
- puts "\n\n\n== couch_storage"
26
+ puts("\n\n== route-redis")
11
27
  puts
12
- puts `ruby -r patron -r yajl test/unit/storage.rb --couch`
28
+ #puts `ruby -r yajl test/unit/storage.rb #{dashdash} --redis`
29
+ puts `ruby test/unit/storage.rb #{dashdash} --redis`
30
+ puts("\nFAILED") if $?.exitstatus.to_i != 0
13
31
 
14
- puts "\n\n\n== dm_storage"
32
+ puts("\n\n== route-beanstalk")
15
33
  puts
16
- puts `ruby -r yajl test/unit/storage.rb --dm`
34
+ #puts `ruby -r yajl test/unit/storage.rb #{dashdash} --beanstalk`
35
+ puts `ruby test/unit/storage.rb #{dashdash} --beanstalk`
36
+ puts("\nFAILED") if $?.exitstatus.to_i != 0
17
37
 
@@ -47,5 +47,41 @@ class LookupTest < Test::Unit::TestCase
47
47
 
48
48
  assert_equal({"customer.name"=>"bravo"}, h)
49
49
  end
50
+
51
+ def test_hash_unset
52
+
53
+ h = { 'customer' => { 'name' => 'alpha', 'rank' => '1st' } }
54
+ r = Ruote.unset(h, 'customer.rank')
55
+
56
+ assert_equal('1st', r)
57
+ assert_equal({ 'customer' => { 'name' => 'alpha' } }, h)
58
+ end
59
+
60
+ def test_array_unset
61
+
62
+ h = { 'customers' => %w[ alpha bravo charly ] }
63
+ r = Ruote.unset(h, 'customers.1')
64
+
65
+ assert_equal('bravo', r)
66
+ assert_equal({ 'customers' => %w[ alpha charly ] }, h)
67
+ end
68
+
69
+ def test_array_unset_fail
70
+
71
+ h = { 'customers' => %w[ alpha bravo charly ] }
72
+ r = Ruote.unset(h, 'customers.x')
73
+
74
+ assert_equal(nil, r)
75
+ assert_equal({ 'customers' => %w[ alpha bravo charly ] }, h)
76
+ end
77
+
78
+ def test_unset_fail
79
+
80
+ h = { 'customer' => { 'name' => 'alpha', 'rank' => '1st' } }
81
+ r = Ruote.unset(h, 'customer.rank.0')
82
+
83
+ assert_equal(nil, r)
84
+ assert_equal({ 'customer' => { 'name' => 'alpha', 'rank' => '1st' } }, h)
85
+ end
50
86
  end
51
87
 
@@ -75,6 +75,26 @@ class PdefParserTest < Test::Unit::TestCase
75
75
  Ruote::Parser.to_xml(TREE1, :indent => 2).strip)
76
76
  end
77
77
 
78
+ def test_if_to_xml
79
+
80
+ tree = Ruote.process_definition do
81
+ _if 'nada' do
82
+ participant 'nemo'
83
+ end
84
+ end
85
+
86
+ assert_equal(
87
+ %{
88
+ <?xml version="1.0" encoding="UTF-8"?>
89
+ <define>
90
+ <if test="nada">
91
+ <participant ref="nemo"/>
92
+ </if>
93
+ </define>
94
+ }.strip,
95
+ Ruote::Parser.to_xml(tree, :indent => 2).strip)
96
+ end
97
+
78
98
  def test_to_ruby
79
99
 
80
100
  #puts Ruote::Parser.to_ruby(TREE1)
@@ -96,5 +116,28 @@ end
96
116
 
97
117
  assert_equal TREE1.to_json, Ruote::Parser.to_json(TREE1)
98
118
  end
119
+
120
+ DEF1 = %{
121
+ Ruote.process_definition do
122
+ sequence do
123
+ alpha
124
+ set :field => 'f', :value => 'v'
125
+ bravo
126
+ end
127
+ end
128
+ }
129
+
130
+ def test_from_ruby_file
131
+
132
+ fn = File.expand_path(File.join(File.dirname(__FILE__), '_ut_16_def1.rb'))
133
+
134
+ File.open(fn, 'wb') { |f| f.write(DEF1) }
135
+
136
+ assert_equal(
137
+ ["define", {}, [["sequence", {}, [["alpha", {}, []], ["set", {"field"=>"f", "value"=>"v"}, []], ["bravo", {}, []]]]]],
138
+ Ruote::Parser.parse(fn))
139
+
140
+ FileUtils.rm(fn)
141
+ end
99
142
  end
100
143
 
@@ -7,7 +7,7 @@
7
7
 
8
8
  require File.join(File.dirname(__FILE__), '..', 'test_helper.rb')
9
9
 
10
- require 'ruote/fei'
10
+ require 'ruote'
11
11
 
12
12
 
13
13
  class UtFeiTest < Test::Unit::TestCase
@@ -86,6 +86,33 @@ class UtFeiTest < Test::Unit::TestCase
86
86
  assert_equal(
87
87
  '0_0_1!!20100224-fake',
88
88
  Ruote::FlowExpressionId.from_id('wi!store!0_0_1!!20100224-fake').to_storage_id)
89
+
90
+ assert_equal(
91
+ '0_0_1!!20100224-fake',
92
+ Ruote::FlowExpressionId.from_id('eng!0_0_1!!20100224-fake').to_storage_id)
93
+ assert_equal(
94
+ 'eng',
95
+ Ruote::FlowExpressionId.from_id('eng!0_0_1!!20100224-fake').engine_id)
96
+ end
97
+
98
+ def test_extract_h
99
+
100
+ assert_equal(
101
+ { 'engine_id' => 'engine',
102
+ 'expid' => '0_0_1',
103
+ 'sub_wfid' => '',
104
+ 'wfid' => '20100224-fake' },
105
+ Ruote::FlowExpressionId.extract_h('0_0_1!!20100224-fake'))
106
+ end
107
+
108
+ def test_extract
109
+ assert_equal(
110
+ Ruote::FlowExpressionId.new(
111
+ { 'engine_id' => 'engine',
112
+ 'expid' => '0_0_1',
113
+ 'sub_wfid' => '',
114
+ 'wfid' => '20100224-fake' }),
115
+ Ruote::FlowExpressionId.extract('0_0_1!!20100224-fake'))
89
116
  end
90
117
  end
91
118
 
@@ -44,5 +44,28 @@ class UtWorkitemTest < Test::Unit::TestCase
44
44
  w0.set_field('customer.address', [ 'Cornwall Square 10b', 'Singapore-La' ])
45
45
  assert_equal 'Cornwall Square 10b', w0.lookup('customer.address.0')
46
46
  end
47
+
48
+ #def test_indifferent_access
49
+ # w0 = Ruote::Workitem.new(
50
+ # 'fields' => { 'customer' => 'john' })
51
+ # assert_equal 'john', w0.fields['customer']
52
+ # assert_equal 'john', w0.fields[:customer]
53
+ #end
54
+
55
+ def test_sid
56
+
57
+ f0 = { 'expid' => '0', 'wfid' => '20101224-baba', 'engine_id' => 'engine' }
58
+ w0 = Ruote::Workitem.new('fei' => f0, 'fields' => { 'a' => 'A' })
59
+
60
+ assert_equal '0!!20101224-baba', w0.sid
61
+ end
62
+
63
+ def test_wfid
64
+
65
+ f0 = { 'expid' => '0', 'wfid' => '20101224-baba', 'engine_id' => 'engine' }
66
+ w0 = Ruote::Workitem.new('fei' => f0, 'fields' => { 'a' => 'A' })
67
+
68
+ assert_equal '20101224-baba', w0.wfid
69
+ end
47
70
  end
48
71