ruote-amqp 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,126 +1,234 @@
1
1
 
2
- require File.join(File.dirname(__FILE__), 'spec_helper')
2
+ require 'spec_helper'
3
3
 
4
- require 'ruote/participant'
5
4
 
5
+ describe Ruote::Amqp::Receiver do
6
6
 
7
- describe RuoteAMQP::Receiver do
7
+ before(:all) do
8
+
9
+ ensure_em_is_running
10
+ end
11
+
12
+ before(:each) do
13
+
14
+ @dashboard = Ruote::Dashboard.new(Ruote::Worker.new(Ruote::HashStorage.new))
15
+
16
+ @dashboard.noisy = ENV['NOISY'].to_s == 'true'
17
+
18
+ @dashboard.register(
19
+ :toto,
20
+ Ruote::Amqp::Participant,
21
+ :exchange => [ 'direct', '' ],
22
+ :routing_key => 'alpha')
23
+
24
+ @queue = AMQP::Channel.new.queue('alpha')
25
+ end
8
26
 
9
27
  after(:each) do
10
- purge_engine
28
+
29
+ @dashboard.shutdown
30
+ @receiver.shutdown
31
+
32
+ #@queue.status { |mc, acc| p [ :messages, mc, :active_consumers, acc ] }
33
+ @queue.delete
11
34
  end
12
35
 
13
- it "handles replies" do
36
+ #
37
+ # A participant that spits back an error (over AMQP)
38
+ #
39
+ class ParticipantWithError
40
+ include Ruote::LocalParticipant
14
41
 
15
- pdef = Ruote.process_definition :name => 'test' do
16
- set :field => 'foo', :value => 'foo'
17
- sequence do
18
- echo '${f:foo}'
19
- amqp :queue => 'test3'
20
- echo '${f:foo}'
21
- end
42
+ def initialize(options)
43
+
44
+ @options = options
22
45
  end
23
46
 
24
- @engine.register_participant(:amqp, RuoteAMQP::ParticipantProxy)
47
+ def on_workitem
48
+
49
+ wi = workitem.h
50
+ wi['error'] = @options['error']
25
51
 
26
- RuoteAMQP::Receiver.new(@engine)
52
+ exchange = AMQP::Exchange.new(AMQP::Channel.new, :direct, '')
53
+ exchange.publish(Rufus::Json.encode(wi), :routing_key => 'alpha')
27
54
 
28
- wfid = @engine.launch(pdef)
55
+ # no replying to the engine
56
+ end
29
57
 
30
- workitem = nil
58
+ def on_cancel
31
59
 
32
- begin
33
- Timeout::timeout(5) do
60
+ # nothing
61
+ end
62
+ end
34
63
 
35
- MQ.queue('test3', :durable => true).subscribe { |msg|
36
- wi = Ruote::Workitem.new(Rufus::Json.decode(msg))
37
- workitem = wi if wi.wfid == wfid
38
- }
64
+ context 'plain receiver' do
39
65
 
40
- loop do
41
- break unless workitem.nil?
42
- sleep 0.1
66
+ before(:each) do
67
+
68
+ @receiver = Ruote::Amqp::Receiver.new(@dashboard, @queue)
69
+
70
+ sleep 0.100 # give some time for the receiver to settle in
71
+ end
72
+
73
+ context 'with workitems' do
74
+
75
+ it 'grabs workitems from a queue' do
76
+
77
+ pdef = Ruote.define do
78
+ toto
43
79
  end
80
+
81
+ wfid = @dashboard.launch(pdef)
82
+ r = @dashboard.wait_for(wfid)
83
+
84
+ r['action'].should == 'terminated'
85
+ end
86
+
87
+ it 'offers a hook for errors' do
88
+
89
+ $errs = []
90
+
91
+ def @receiver.handle_error(e)
92
+ $errs << e
93
+ end
94
+
95
+ exchange = AMQP::Exchange.new(AMQP::Channel.new, :direct, '')
96
+
97
+ exchange.publish('nada zero', :routing_key => 'alpha')
98
+ exchange.publish('nada one', :routing_key => 'alpha')
99
+
100
+ sleep 0.300
101
+
102
+ $errs.size.should == 2
44
103
  end
45
- rescue Timeout::Error
46
- violated "Timeout waiting for message"
47
104
  end
48
105
 
49
- workitem.fields['foo'] = "bar"
106
+ context 'with launchitems' do
50
107
 
51
- MQ.queue('ruote_workitems', :durable => true).publish(Rufus::Json.encode(workitem.to_h), :persistent => true)
108
+ it 'accepts launchitems' do
52
109
 
53
- @engine.wait_for(wfid)
110
+ @dashboard.register('noop', Ruote::NoOpParticipant)
54
111
 
55
- @engine.should_not have_errors
56
- @engine.should_not have_remaining_expressions
112
+ launchitem = {
113
+ 'definition' => Ruote.define { noop },
114
+ 'fields' => { 'kilroy' => 'was here' }
115
+ }
57
116
 
58
- @tracer.to_s.should == "foo\nbar"
59
- end
117
+ exchange = AMQP::Exchange.new(AMQP::Channel.new, :direct, '')
118
+ exchange.publish(Rufus::Json.encode(launchitem), :routing_key => 'alpha')
60
119
 
61
- it "launches processes" do
120
+ r = @dashboard.wait_for('terminated')
62
121
 
63
- json = {
64
- 'definition' => %{
65
- Ruote.process_definition :name => 'test' do
66
- sequence do
67
- echo '${f:foo}'
68
- end
69
- end
70
- },
71
- 'fields' => { 'foo' => 'bar' }
72
- }.to_json
122
+ r['workitem']['fields']['kilroy'].should == 'was here'
123
+ end
124
+ end
125
+
126
+ context 'with errors' do
127
+
128
+ it 'propagates errors passed back as strings' do
129
+
130
+ @dashboard.register_participant(
131
+ 'alf', ParticipantWithError, 'error' => 'something went wrong')
132
+
133
+ wfid = @dashboard.launch(Ruote.define { alf })
134
+ r = @dashboard.wait_for(wfid)
135
+
136
+ r['action'].should == 'error_intercepted'
137
+
138
+ r['error']['class'].should == 'Ruote::Amqp::RemoteError'
139
+ r['error']['message'].should == 'something went wrong'
140
+ end
141
+
142
+ it 'propagates errors passed back as hashes' do
143
+
144
+ @dashboard.register_participant(
145
+ 'alf',
146
+ ParticipantWithError,
147
+ 'error' => {
148
+ 'class' => 'ArgumentError', 'message' => 'something missing' })
149
+
150
+ wfid = @dashboard.launch(Ruote.define { alf })
151
+ r = @dashboard.wait_for(wfid)
152
+
153
+ r['action'].should == 'error_intercepted'
154
+
155
+ r['error']['class'].should == 'ArgumentError'
156
+ r['error']['message'].should == 'something missing'
157
+ end
73
158
 
74
- RuoteAMQP::Receiver.new(@engine, :launchitems => true, :unsubscribe => true)
159
+ it 'propagates errors passed back as whatever' do
75
160
 
76
- MQ.queue(
77
- 'ruote_workitems', :durable => true
78
- ).publish(
79
- json, :persistent => true
80
- )
161
+ @dashboard.register_participant(
162
+ 'alf', ParticipantWithError, 'error' => %w[ not good ])
81
163
 
82
- sleep 0.5
164
+ wfid = @dashboard.launch(Ruote.define { alf })
165
+ r = @dashboard.wait_for(wfid)
83
166
 
84
- @engine.should_not have_errors
85
- @engine.should_not have_remaining_expressions
167
+ r['action'].should == 'error_intercepted'
86
168
 
87
- @tracer.to_s.should == 'bar'
169
+ r['error']['class'].should == 'Ruote::Amqp::RemoteError'
170
+ r['error']['message'].should == %w[ not good ].inspect
171
+ end
172
+ end
88
173
  end
89
174
 
90
- it 'accepts a custom :queue' do
175
+ context 'launch_only receiver' do
91
176
 
92
- #@engine.noisy = true
177
+ before(:each) do
93
178
 
94
- RuoteAMQP::Receiver.new(
95
- @engine, :queue => 'mario', :launchitems => true, :unsubscribe => true)
179
+ @receiver = Ruote::Amqp::Receiver.new(
180
+ #@dashboard, @queue, 'launch_only' => true)
181
+ @dashboard, @queue, :launch_only => true)
182
+
183
+ sleep 0.100 # give some time for the receiver to settle in
184
+ end
96
185
 
97
- @engine.register_participant 'alpha', Ruote::StorageParticipant
186
+ # ...
98
187
 
99
- json = Rufus::Json.encode({
100
- 'definition' => "Ruote.define { alpha }"
101
- })
188
+ it 'accepts launchitems' do
102
189
 
103
- MQ.queue(
104
- 'ruote_workitems', :durable => true
105
- ).publish(
106
- json, :persistent => true
107
- )
190
+ @dashboard.register('noop', Ruote::NoOpParticipant)
108
191
 
109
- sleep 1
192
+ launchitem = {
193
+ 'definition' => Ruote.define { noop },
194
+ 'fields' => { 'launch' => 'yes' }
195
+ }
110
196
 
111
- @engine.processes.size.should == 0
112
- # nothing happened
197
+ exchange = AMQP::Exchange.new(AMQP::Channel.new, :direct, '')
198
+ exchange.publish(Rufus::Json.encode(launchitem), :routing_key => 'alpha')
113
199
 
114
- MQ.queue(
115
- 'mario', :durable => true
116
- ).publish(
117
- json, :persistent => true
118
- )
200
+ r = @dashboard.wait_for('terminated')
119
201
 
120
- sleep 1
202
+ r['workitem']['fields']['launch'].should == 'yes'
203
+ end
204
+
205
+ it 'discards workitems' do
206
+
207
+ pdef = Ruote.define do
208
+ toto
209
+ end
121
210
 
122
- @engine.processes.size.should == 1
123
- # launch happened
211
+ wfid = @dashboard.launch(pdef)
212
+ @dashboard.wait_for('dispatched')
213
+ sleep 0.500
214
+
215
+ @dashboard.ps(wfid).should_not == nil
216
+ end
217
+
218
+ it 'discards errors' do
219
+
220
+ @dashboard.register_participant(
221
+ 'alf', ParticipantWithError, 'error' => 'something went wrong')
222
+
223
+ wfid = @dashboard.launch(Ruote.define { alf })
224
+ @dashboard.wait_for('dispatched')
225
+ sleep 0.500
226
+
227
+ status = @dashboard.ps(wfid)
228
+
229
+ status.should_not == nil
230
+ status.errors.size.should == 0
231
+ end
124
232
  end
125
233
  end
126
234
 
data/spec/spec_helper.rb CHANGED
@@ -1,79 +1,21 @@
1
1
 
2
- require 'rubygems'
3
- require 'rspec'
2
+ require 'rufus-json/automatic'
3
+ require 'ruote/amqp'
4
4
 
5
- $:.unshift(File.join(File.dirname(__FILE__), '../lib'))
6
- $:.unshift(File.join(File.dirname(__FILE__), '../../ruote/lib'))
5
+ Dir[File.expand_path('../support/**/*.rb', __FILE__)].each { |f| require(f) }
7
6
 
8
- #gem 'amqp', '=0.6.7'
9
-
10
- require 'fileutils'
11
- require 'json'
12
- require 'timeout'
13
-
14
- require 'ruote/engine'
15
- require 'ruote/worker'
16
- require 'ruote/storage/hash_storage'
17
- require 'ruote/log/test_logger'
18
-
19
- require 'ruote-amqp'
20
-
21
- Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each { |path|
22
- require(path)
23
- }
24
-
25
-
26
- # AMQP magic worked here
27
- AMQP.settings[:host] = 'localhost'
28
- AMQP.settings[:vhost] = 'ruote-test'
29
- AMQP.settings[:user] = 'ruote'
30
- AMQP.settings[:pass] = 'ruote'
31
-
32
- #AMQP.logging = true
33
7
 
34
8
  RSpec.configure do |config|
35
9
 
36
- config.include(RuoteSpecHelpers)
37
-
38
- config.before(:each) do
39
- @tracer = Tracer.new
40
-
41
- @engine = Ruote::Engine.new(
42
- Ruote::Worker.new(
43
- Ruote::HashStorage.new(
44
- 's_logger' => [ 'ruote/log/test_logger', 'Ruote::TestLogger' ])))
45
-
46
- @engine.add_service('tracer', @tracer)
47
- end
48
-
49
- config.after(:each) do
50
- @engine.shutdown
51
- @engine.context.storage.purge!
52
- end
53
-
54
- config.after(:all) do
55
- base = File.expand_path(File.dirname(__FILE__) + '/..')
56
- FileUtils.rm_rf(base + '/logs')
57
- FileUtils.rm_rf(base + '/work')
58
- end
59
- end
60
-
10
+ # == Mock Framework
11
+ #
12
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
13
+ #
14
+ # config.mock_with :mocha
15
+ # config.mock_with :flexmock
16
+ # config.mock_with :rr
17
+ config.mock_with :rspec
61
18
 
62
- class Tracer
63
- def initialize
64
- @trace = ''
65
- end
66
- def to_s
67
- @trace.to_s.strip
68
- end
69
- def << s
70
- @trace << s
71
- end
72
- def clear
73
- @trace = ''
74
- end
75
- def puts s
76
- @trace << "#{s}\n"
77
- end
19
+ config.include RuoteAmqpHelper
78
20
  end
79
21
 
@@ -0,0 +1,40 @@
1
+
2
+ module RuoteAmqpHelper
3
+
4
+ def ensure_em_is_running
5
+
6
+ unless @em
7
+ @em = Thread.new { EM.run {} }
8
+ sleep 0.5
9
+ end
10
+ end
11
+
12
+ def count_amqp_objects
13
+
14
+ objects = {}
15
+
16
+ ObjectSpace.each_object do |o|
17
+
18
+ next unless [
19
+ AMQP::Queue, AMQP::Channel, AMQP::Exchange
20
+ ].include?(o.class)
21
+
22
+ k = o.class.to_s
23
+
24
+ objects[k] ||= 0
25
+ objects[k] = objects[k] + 1
26
+ end
27
+
28
+ objects
29
+ end
30
+
31
+ def display_amqp_object_count
32
+
33
+ objects = count_amqp_objects
34
+
35
+ objects.keys.sort.each do |k|
36
+ puts "#{k}: #{objects[k]}"
37
+ end
38
+ end
39
+ end
40
+
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruote-amqp
3
3
  version: !ruby/object:Gem::Version
4
- hash: 7
4
+ hash: 3
5
5
  prerelease:
6
6
  segments:
7
7
  - 2
8
- - 2
8
+ - 3
9
9
  - 0
10
- version: 2.2.0
10
+ version: 2.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Kenneth Kalmer
@@ -16,8 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-03-01 00:00:00 +09:00
20
- default_executable:
19
+ date: 2012-09-02 00:00:00 Z
21
20
  dependencies:
22
21
  - !ruby/object:Gem::Dependency
23
22
  name: amqp
@@ -25,14 +24,13 @@ dependencies:
25
24
  requirement: &id001 !ruby/object:Gem::Requirement
26
25
  none: false
27
26
  requirements:
28
- - - "="
27
+ - - ~>
29
28
  - !ruby/object:Gem::Version
30
- hash: 3
29
+ hash: 25
31
30
  segments:
32
31
  - 0
33
- - 7
34
- - 0
35
- version: 0.7.0
32
+ - 9
33
+ version: "0.9"
36
34
  type: :runtime
37
35
  version_requirements: *id001
38
36
  - !ruby/object:Gem::Dependency
@@ -43,12 +41,12 @@ dependencies:
43
41
  requirements:
44
42
  - - ">="
45
43
  - !ruby/object:Gem::Version
46
- hash: 7
44
+ hash: 3
47
45
  segments:
48
46
  - 2
49
- - 2
47
+ - 3
50
48
  - 0
51
- version: 2.2.0
49
+ version: 2.3.0
52
50
  type: :runtime
53
51
  version_requirements: *id002
54
52
  - !ruby/object:Gem::Dependency
@@ -71,18 +69,17 @@ dependencies:
71
69
  requirement: &id004 !ruby/object:Gem::Requirement
72
70
  none: false
73
71
  requirements:
74
- - - ">="
72
+ - - ~>
75
73
  - !ruby/object:Gem::Version
76
- hash: 5
74
+ hash: 19
77
75
  segments:
78
76
  - 2
79
- - 2
80
- - 1
81
- version: 2.2.1
77
+ - 8
78
+ version: "2.8"
82
79
  type: :development
83
80
  version_requirements: *id004
84
81
  description: "\n\
85
- AMQP participant/listener pair for ruote 2.1\n "
82
+ AMQP participant/listener pair for ruote\n "
86
83
  email:
87
84
  - kenneth.kalmer@gmail.com
88
85
  - jmettraux@gmail.com
@@ -94,27 +91,24 @@ extra_rdoc_files: []
94
91
 
95
92
  files:
96
93
  - Rakefile
97
- - lib/ruote-amqp/launchitem_listener.rb
98
- - lib/ruote-amqp/participant.rb
99
- - lib/ruote-amqp/receiver.rb
100
- - lib/ruote-amqp/version.rb
101
- - lib/ruote-amqp/workitem_listener.rb
94
+ - lib/ruote/amqp/alert_participant.rb
95
+ - lib/ruote/amqp/participant.rb
96
+ - lib/ruote/amqp/receiver.rb
97
+ - lib/ruote/amqp/version.rb
98
+ - lib/ruote/amqp.rb
102
99
  - lib/ruote-amqp.rb
103
- - spec/launchitem_listener_spec.rb
100
+ - spec/alert_participant_spec.rb
104
101
  - spec/participant_spec.rb
102
+ - spec/participant_subclass_spec.rb
105
103
  - spec/receiver_spec.rb
106
- - spec/ruote_amqp_spec.rb
107
104
  - spec/spec_helper.rb
108
- - spec/support/ruote_helpers.rb
109
- - spec/support/ruote_matchers.rb
110
- - spec/workitem_listener_spec.rb
105
+ - spec/support/ruote_amqp_helper.rb
111
106
  - ruote-amqp.gemspec
112
107
  - CHANGELOG.txt
113
108
  - CREDITS.txt
114
- - PostInstall.txt
109
+ - LICENSE.txt
115
110
  - TODO.txt
116
- - README.rdoc
117
- has_rdoc: true
111
+ - README.md
118
112
  homepage: http://ruote.rubyforge.org
119
113
  licenses: []
120
114
 
@@ -144,9 +138,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
144
138
  requirements: []
145
139
 
146
140
  rubyforge_project: ruote
147
- rubygems_version: 1.5.0
141
+ rubygems_version: 1.8.15
148
142
  signing_key:
149
143
  specification_version: 3
150
- summary: AMQP participant/listener pair for ruote 2.1
144
+ summary: AMQP participant/listener pair for ruote
151
145
  test_files: []
152
146
 
data/PostInstall.txt DELETED
@@ -1,12 +0,0 @@
1
-
2
- For more information on ruote-amqp, see http://github.com/kennethkalmer/ruote-amqp
3
-
4
- Please note that this gem requires access to an AMQP broker and a good
5
- understanding of AMQP and remote participants in general.
6
-
7
- Join us in #ruote on Freenode or on the openwfe-users Google Group to discuss
8
- it's uses.
9
-
10
- You might also want to look at daemon-kit for help with writing external
11
- participants that communicate with ruote via AMQP.
12
-
data/README.rdoc DELETED
@@ -1,91 +0,0 @@
1
-
2
- = ruote-amqp
3
-
4
- * http://github.com/kennethkalmer/ruote-amqp
5
- * http://rdoc.info/projects/kennethkalmer/ruote-amqp
6
- * http://ruote.rubyforge.org
7
-
8
- == DESCRIPTION:
9
-
10
- ruote-amqp provides an AMQP participant/listener pair that allows you to
11
- distribute workitems out to AMQP consumers for processing, as well as launching
12
- processes over AMQP.
13
-
14
- To learn more about remote participants in ruote please see
15
- http://ruote.rubyforge.org/part_implementations.html
16
-
17
- == FEATURES/PROBLEMS:
18
-
19
- * Flexible participant for sending workitems
20
- * Flexible receiver for receiving replies
21
- * Flexible launch item listener for launching processes over AMQP
22
- * Fully evented (thanks to the amqp gem)
23
-
24
- == SYNOPSIS:
25
-
26
- Please review the rdoc in RuoteAMQP::Participant and Ruote::AMQP::Listener
27
-
28
- == REQUIREMENTS:
29
-
30
- * ruote[http://ruote.rubyforge.org] 2.2.0 or later
31
- * amqp[http://github.com/tmm1/amqp] 0.6.7 or later
32
- * rabbitmq[http://www.rabbitmq.com/] 1.6.0 or later
33
-
34
- == INSTALL:
35
-
36
- Please be sure to have read the requirements section above
37
-
38
- * sudo gem install ruote-amqp
39
-
40
- == TESTS:
41
-
42
- To run the tests you need the following requirements met, or the testing environment
43
- will fail horribly (or simply get stuck without output).
44
-
45
- === RabbitMQ vhost
46
-
47
- The tests use dedicated vhost on a running AMQP broker. To configure RabbitMQ
48
- you can run the following commands:
49
-
50
- # rabbitmqctl add_vhost ruote-test
51
- # rabbitmqctl add_user ruote ruote
52
- # rabbitmqctl set_permissions -p ruote-test ruote '.*' '.*' '.*'
53
-
54
- If you need to change the AMQP configuration used by the tests, edit the
55
- +spec/spec_helper.rb+ file.
56
-
57
- == DAEMON-KIT:
58
-
59
- Although the RuoteAMQP gem will work perfectly well with any AMQP consumer,
60
- it is recommended that you use daemon-kit[http://github.com/kennethkalmer/daemon-kit]
61
- to write your remote participants.
62
-
63
- daemon-kit offers plenty of convenience for remote participants and includes
64
- a code generator for ruote remote participants.
65
-
66
- DaemonKit doesn't currently support ruote 2.1, support is forthcoming.
67
-
68
- == LICENSE:
69
-
70
- (The MIT License)
71
-
72
- Copyright (c) 2010-2011 Kenneth Kalmer
73
-
74
- Permission is hereby granted, free of charge, to any person obtaining
75
- a copy of this software and associated documentation files (the
76
- 'Software'), to deal in the Software without restriction, including
77
- without limitation the rights to use, copy, modify, merge, publish,
78
- distribute, sublicense, and/or sell copies of the Software, and to
79
- permit persons to whom the Software is furnished to do so, subject to
80
- the following conditions:
81
-
82
- The above copyright notice and this permission notice shall be
83
- included in all copies or substantial portions of the Software.
84
-
85
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
86
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
87
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
88
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
89
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
90
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
91
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.