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
@@ -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