ruote-amqp 0.9.20

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ === 0.9.20 2009-07-13
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,20 @@
1
+ History.txt
2
+ Manifest.txt
3
+ PostInstall.txt
4
+ README.rdoc
5
+ Rakefile
6
+ lib/ruote-amqp.rb
7
+ lib/ruote-amqp/listener.rb
8
+ lib/ruote-amqp/participant.rb
9
+ lib/spec/ruote.rb
10
+ lib/spec/ruote_example_group.rb
11
+ lib/spec/ruote_helpers.rb
12
+ lib/spec/ruote_matchers.rb
13
+ script/console
14
+ script/destroy
15
+ script/generate
16
+ spec/listener_spec.rb
17
+ spec/participant_spec.rb
18
+ spec/spec.opts
19
+ spec/spec_helper.rb
20
+ tasks/rspec.rake
data/PostInstall.txt ADDED
@@ -0,0 +1,12 @@
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 ADDED
@@ -0,0 +1,67 @@
1
+ = ruote-amqp
2
+
3
+ * http://github.com/kennethkalmer/ruote-amqp
4
+ * http://openwfe.rubyforge.org
5
+
6
+ == DESCRIPTION:
7
+
8
+ ruote-amqp provides an AMQP participant/listener pair that allows you to
9
+ distribute workitems out to AMQP consumers for processing.
10
+
11
+ To learn more about remote participants in ruote please see
12
+ http://openwfe.rubyforge.org/part.html
13
+
14
+ == FEATURES/PROBLEMS:
15
+
16
+ * Flexible participant for sending workitems
17
+ * Flexible listener for receiving replies
18
+ * Fully evented (thanks to the amqp gem)
19
+
20
+ == SYNOPSIS:
21
+
22
+ Please review the detailed RDOC in RuoteAMQP::Participant and Ruote::AMQP::Listener
23
+
24
+ == REQUIREMENTS:
25
+
26
+ * ruote[http://openwfe.rubyforge.org] 0.9.20 or later
27
+ * amqp[http://github.com/tmm1/amqp] 0.6.1 or later
28
+
29
+ NOTE: It might be required that you build the amqp gem yourself
30
+
31
+ == INSTALL:
32
+
33
+ * sudo gem install ruote-amqp
34
+
35
+ == DAEMON-KIT:
36
+
37
+ Although the RuoteAMQP gem will work perfectly well with any AMQP consumer,
38
+ it is recommended that you use daemon-kit[http://github.com/kennethkalmer/daemon-kit]
39
+ to write your remote participants.
40
+
41
+ daemon-kit offers plenty of convenience for remote participants and includes
42
+ a code generator for ruote remote participants.
43
+
44
+ == LICENSE:
45
+
46
+ (The MIT License)
47
+
48
+ Copyright (c) 2009 Kenneth Kalmer
49
+
50
+ Permission is hereby granted, free of charge, to any person obtaining
51
+ a copy of this software and associated documentation files (the
52
+ 'Software'), to deal in the Software without restriction, including
53
+ without limitation the rights to use, copy, modify, merge, publish,
54
+ distribute, sublicense, and/or sell copies of the Software, and to
55
+ permit persons to whom the Software is furnished to do so, subject to
56
+ the following conditions:
57
+
58
+ The above copyright notice and this permission notice shall be
59
+ included in all copies or substantial portions of the Software.
60
+
61
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
62
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
63
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
64
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
65
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
66
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
67
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+ require 'fileutils'
5
+ require './lib/ruote-amqp'
6
+
7
+ Hoe.plugin :newgem
8
+ # Hoe.plugin :website
9
+ # Hoe.plugin :cucumberfeatures
10
+
11
+ # Generate all the Rake tasks
12
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
13
+ $hoe = Hoe.spec 'ruote-amqp' do
14
+ self.developer 'Kenneth Kalmer', 'kenneth.kalmer@gmail.com'
15
+ self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
16
+ self.rubyforge_name = self.name # TODO this is default value
17
+ self.extra_deps = [['ruote','= 0.9.20'], ['amqp', '= 0.6.0']]
18
+
19
+ end
20
+
21
+ require 'newgem/tasks'
22
+ Dir['tasks/**/*.rake'].each { |t| load t }
23
+
24
+ # TODO - want other tests/tasks run by default? Add them to the list
25
+ # remove_task :default
26
+ # task :default => [:spec, :features]
data/lib/ruote-amqp.rb ADDED
@@ -0,0 +1,26 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ begin
5
+ require 'openwfe'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ gem 'ruote', '>= 0.9.20'
9
+ require 'openwfe'
10
+ end
11
+ require 'openwfe/version'
12
+
13
+ if OpenWFE::OPENWFERU_VERSION < '0.9.20'
14
+ raise "ruote-amqp requires at least ruote-0.9.20"
15
+ end
16
+
17
+ require 'yaml'
18
+ require 'json'
19
+ require 'mq'
20
+
21
+ module RuoteAMQP
22
+ VERSION = '0.9.20'
23
+
24
+ autoload 'Participant', 'ruote-amqp/participant'
25
+ autoload 'Listener', 'ruote-amqp/listener'
26
+ end
@@ -0,0 +1,92 @@
1
+ require 'openwfe/service'
2
+ require 'openwfe/listeners/listener'
3
+
4
+ module RuoteAMQP
5
+
6
+ #
7
+ # = AMQP Listeners
8
+ #
9
+ # Used in conjunction with the AMQPParticipant, the AMQPListener
10
+ # subscribes to a specific direct exchange and monitors for
11
+ # incoming workitems. It expects workitems to arrive serialized as
12
+ # JSON (prefered), XML or YAML.
13
+ #
14
+ # == Configuration
15
+ #
16
+ # AMQP configuration is handled by directly manipulating the values of
17
+ # the +AMQP.settings+ hash, as provided by the AMQP gem. No
18
+ # defaults are set by the participant. The only +option+ parsed by
19
+ # the initializer of the listener is the +queue+ key (Hash
20
+ # expected). If no +queue+ key is set, the listener will subscribe
21
+ # to the +ruote+ direct exchange for workitems, otherwise it will
22
+ # subscribe to the direct exchange provided.
23
+ #
24
+ # The participant requires version 0.6.1 or later of the amqp gem.
25
+ #
26
+ # == Usage
27
+ #
28
+ # Register the listener with the engine:
29
+ #
30
+ # engine.register_listener( OpenWFE::Extras::AMQPListener )
31
+ #
32
+ # The listener leverages the asynchronous nature of the amqp gem,
33
+ # so no timers are setup when initialized.
34
+ #
35
+ # See the AMQPParticipany docs for information on sending
36
+ # workitems out to remote participants, and have them send replies
37
+ # to the correct direct exchange specified in the workitem
38
+ # attributes.
39
+ #
40
+ class Listener < OpenWFE::Service
41
+ include OpenWFE::WorkItemListener
42
+
43
+ # Listening queue
44
+ @@queue = 'ruote'
45
+
46
+ class << self
47
+
48
+ def queue
49
+ @@queue
50
+ end
51
+
52
+ end
53
+
54
+ # Only one option is used (:queue) to determine where to listen
55
+ # for work
56
+ def initialize( service_name, options )
57
+
58
+ if q = options.delete(:queue)
59
+ @@queue = q
60
+ end
61
+
62
+ super( service_name, options )
63
+
64
+ #if AMQP.connection.nil?
65
+ @em_thread = Thread.new { EM.run } unless EM.reactor_running?
66
+ #end
67
+
68
+ MQ.queue( @@queue, :durable => true ).subscribe do |message|
69
+ workitem = decode_workitem( message )
70
+ ldebug { "workitem from '#{@@queue}': #{workitem.inspect}" }
71
+ handle_item( workitem )
72
+ end
73
+ end
74
+
75
+ def stop
76
+ linfo { "Stopping..." }
77
+
78
+ AMQP.stop { EM.stop } #if EM.reactor_running? }
79
+ @em_thread.join if @em_thread
80
+ end
81
+
82
+ private
83
+
84
+ # Complicated guesswork that needs to happen here to detect the format
85
+ def decode_workitem( msg )
86
+ ldebug { "decoding workitem from: #{msg}" }
87
+
88
+ hash = JSON.parse(msg)
89
+ OpenWFE.workitem_from_h( hash )
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,153 @@
1
+ module RuoteAMQP
2
+
3
+ # = AMQP Participants
4
+ #
5
+ # The AMQPParticipant allows you to send workitems (serialized as
6
+ # JSON) or messages to any AMQP queues right from the process
7
+ # definition. When combined with the AMQPListener you can easily
8
+ # leverage an extremely powerful local/remote participant
9
+ # combinations.
10
+ #
11
+ # By default the participant relies on the presence of an AMQP
12
+ # listener. Workitems are sent and no replies are given to the
13
+ # engine. The participant can be configured to reply to the engine
14
+ # immediately after queueing a message, see the usage section below.
15
+ #
16
+ # == Configuration
17
+ #
18
+ # AMQP configuration is handled by directly manipulating the
19
+ # values of the +AMQP.settings+ hash, as provided by the AMQP
20
+ # gem. No AMQP defaults are set by the participant.
21
+ #
22
+ # The participant requires version 0.6.1 or later of the amqp gem.
23
+ #
24
+ # == Usage
25
+ #
26
+ # Currently it's possible to send either workitems or messages
27
+ # directly to a specific queue, and have the engine wait for
28
+ # replies on another queue (see AMQPListener).
29
+ #
30
+ # Setting up the participant
31
+ #
32
+ # engine.register_participant(
33
+ # :amqp, OpenWFE::Extras::AMQPParticipant )
34
+ #
35
+ # Setup a participant that always replies to the engine
36
+ #
37
+ # engine.register_participant(
38
+ # :amp, OpenWFE::Extras::AMQPParticipant.new(:reply_by_default => true ) )
39
+ #
40
+ # Sending a message example
41
+ #
42
+ # class AmqpMessageExample0 < OpenWFE::ProcessDefinition
43
+ # sequence do
44
+ # amqp :queue => 'test', :message => 'foo'
45
+ # end
46
+ # end
47
+ #
48
+ # Sending a workitem
49
+ #
50
+ # class AmqpWorkitemExample0 < OpenWFE::ProcessDefinition
51
+ # sequence do
52
+ # amqp :queue => 'test'
53
+ # end
54
+ # end
55
+ #
56
+ # Let the participant reply to the engine without involving the listener
57
+ #
58
+ # class AmqpWaitExample < OpenWFE::ProcessDefinition
59
+ # sequence do
60
+ # amqp :queue => 'test', :reply_anyway => true
61
+ # end
62
+ # end
63
+ #
64
+ # When waiting for a reply it only makes sense to send a workitem.
65
+ #
66
+ # == Workitem modifications
67
+ #
68
+ # To ease replies, and additional workitem attribute is set:
69
+ #
70
+ # 'reply_queue'
71
+ #
72
+ # +reply_queue+ has the name of the queue where the AMQPListener
73
+ # expects replies from remote participants
74
+ #
75
+ # == AMQP notes
76
+ #
77
+ # The participant currently only makes use of direct
78
+ # exchanges. Possible future improvements might see use for topic
79
+ # and fanout exchanges as well.
80
+ #
81
+ # The direct exchanges are always marked as durable by the
82
+ # participant.
83
+ #
84
+ class Participant
85
+ include OpenWFE::LocalParticipant
86
+
87
+ # Accepts an options hash with the following keys:
88
+ #
89
+ # * :reply_by_default => (bool) false by default
90
+ def initialize( options = {} )
91
+ ensure_reactor!
92
+
93
+ @options = {
94
+ :reply_by_default => false
95
+ }.merge( options )
96
+ end
97
+
98
+ # Process the workitem at hand. By default the workitem will be
99
+ # published to the direct exchange specified in the +queue+
100
+ # workitem parameter. You can specify a +message+ workitem
101
+ # parameter to have that sent instead of the workitem.
102
+ #
103
+ # To force the participant to reply to the engine, set the
104
+ # +reply_anyway+ workitem parameter.
105
+ def consume( workitem )
106
+ ldebug { "consuming workitem" }
107
+ ensure_reactor!
108
+
109
+ if target_queue = workitem.params['queue']
110
+
111
+ q = MQ.queue( target_queue, :durable => true )
112
+
113
+ # Message or workitem?
114
+ if message = ( workitem.attributes['message'] || workitem.params['message'] )
115
+ ldebug { "sending message to queue: #{target_queue}" }
116
+ q.publish( message )
117
+
118
+ else
119
+ ldebug { "sending workitem to queue: #{target_queue}" }
120
+
121
+ q.publish( encode_workitem( workitem ) )
122
+ end
123
+ else
124
+ lerror { "no queue in workitem params!" }
125
+ end
126
+
127
+ if @options[:reply_by_default] || workitem.params['reply-anyway'] == true
128
+ reply_to_engine( workitem )
129
+ end
130
+
131
+ ldebug { "done" }
132
+ end
133
+
134
+ def stop
135
+ linfo { "Stopping..." }
136
+
137
+ AMQP.stop { EM.stop } #if EM.reactor_running? }
138
+ @em_thread.join if @em_thread
139
+ end
140
+
141
+ protected
142
+
143
+ # Encode (and extend) the workitem as JSON
144
+ def encode_workitem( wi )
145
+ wi.attributes['reply_queue'] = Listener.queue
146
+ JSON.generate( wi.to_h )
147
+ end
148
+
149
+ def ensure_reactor!
150
+ @em_thread = Thread.new { EM.run } unless EM.reactor_running?
151
+ end
152
+ end
153
+ end
data/lib/spec/ruote.rb ADDED
@@ -0,0 +1,5 @@
1
+ require File.dirname(__FILE__) + '/ruote_example_group.rb'
2
+ require File.dirname(__FILE__) + '/ruote_matchers.rb'
3
+ require File.dirname(__FILE__) + '/ruote_helpers.rb'
4
+
5
+ Spec::Example::ExampleGroupFactory.register(:ruote, Spec::Ruote::Example::RuoteExampleGroup)
@@ -0,0 +1,8 @@
1
+ module Spec
2
+ module Ruote
3
+ module Example
4
+ class RuoteExampleGroup < Spec::Example::ExampleGroup
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,24 @@
1
+ module RuoteSpecHelpers
2
+
3
+ def purge_engine
4
+ @engine.application_context.values.each do |s|
5
+ s.purge if s.respond_to?(:purge)
6
+ end
7
+ end
8
+
9
+ def run_definition( pdef )
10
+ fei = @engine.launch( pdef )
11
+ wait( fei )
12
+
13
+ @engine.should_not have_errors
14
+ @engine.should_not have_remaining_expressions
15
+
16
+ purge_engine
17
+ end
18
+
19
+ def wait( fei )
20
+ Thread.pass
21
+ return if @terminated_processes.include?( fei.wfid )
22
+ @engine.wait_for( fei )
23
+ end
24
+ end
@@ -0,0 +1,56 @@
1
+ Spec::Matchers.define :have_errors do |*args|
2
+ match do |engine|
3
+ @ps = if fei = args.shift
4
+ engine.process_status( fei )
5
+ else
6
+ engine.process_statuses.values.first
7
+ end
8
+
9
+ if @ps
10
+ @ps.errors.size != 0
11
+ else
12
+ false
13
+ end
14
+ end
15
+
16
+ failure_message_for_should do |engine|
17
+ "Expected engine to have errors, but didn't"
18
+ end
19
+ failure_message_for_should_not do |engine|
20
+ "Expected the engine to not have errors, but it did.\n" +
21
+ @ps.errors.values.map do |e|
22
+ " * error: #{e.error_class} \"#{e.stacktrace}\""
23
+ end.join("\n")
24
+ end
25
+ description do
26
+ #
27
+ end
28
+ end
29
+
30
+ Spec::Matchers.define :have_remaining_expressions do
31
+ match do |engine|
32
+ exp_count = engine.get_expression_storage.size
33
+
34
+ if exp_count == 1
35
+ false
36
+ else
37
+ 50.times { Thread.pass }
38
+ exp_count = engine.get_expression_storage.size
39
+ if exp_count == 1
40
+ false
41
+ else
42
+ true
43
+ end
44
+ end
45
+ end
46
+
47
+ failure_message_for_should do |engine|
48
+ "Expected engine to have processes remaining, but it didn't"
49
+ end
50
+ failure_message_for_should_not do |engine|
51
+ "Expected engine to have no processes remaining, but it did.#{engine.get_expression_storage.to_s}"
52
+ end
53
+ description do
54
+
55
+ end
56
+ end
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/ruote-amqp.rb'}"
9
+ puts "Loading ruote-amqp gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,53 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe RuoteAMQP::Listener do
4
+
5
+ it "should handle replies" do
6
+ pdef = <<-EOF
7
+ class AmqpParticipant2 < OpenWFE::ProcessDefinition
8
+
9
+ set :field => 'foo', :value => 'foo'
10
+
11
+ sequence do
12
+ echo '${f:foo}'
13
+ amqp :queue => 'test3'
14
+ echo '${f:foo}'
15
+ end
16
+ end
17
+ EOF
18
+
19
+ @engine.register_participant( :amqp, RuoteAMQP::Participant )
20
+
21
+ @engine.register_listener( RuoteAMQP::Listener )
22
+
23
+ fei = @engine.launch pdef
24
+
25
+ begin
26
+ Timeout::timeout(10) do
27
+ msg = nil
28
+ MQ.queue('test3').subscribe { |msg| @msg = msg }
29
+
30
+ loop do
31
+ break unless @msg.nil?
32
+ sleep 1
33
+ end
34
+ end
35
+ rescue Timeout::Error
36
+ violated "Timeout waiting for message"
37
+ end
38
+
39
+ wi = OpenWFE::InFlowWorkItem.from_h( JSON.parse( @msg ) )
40
+ wi.attributes['foo'] = "bar"
41
+
42
+ MQ.queue( wi.attributes['reply_queue'] ).publish( JSON.generate( wi.to_h ) )
43
+
44
+ wait( fei )
45
+
46
+ @engine.should_not have_errors( fei )
47
+ @engine.should_not have_remaining_expressions
48
+
49
+ @tracer.to_s.should == "foo\nbar"
50
+
51
+ purge_engine
52
+ end
53
+ end
@@ -0,0 +1,108 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe RuoteAMQP::Participant, :type => :ruote do
4
+
5
+ it "should support 'reply anyway' on expression parameter" do
6
+
7
+ pdef = <<-EOF
8
+ class AmqpParticipant0 < OpenWFE::ProcessDefinition
9
+
10
+ sequence do
11
+ amqp :queue => 'test1', 'reply_anyway' => true
12
+ echo 'done.'
13
+ end
14
+ end
15
+ EOF
16
+
17
+ @engine.register_participant( :amqp, RuoteAMQP::Participant )
18
+
19
+ run_definition( pdef )
20
+
21
+ @tracer.to_s.should == 'done.'
22
+
23
+ begin
24
+ Timeout::timeout(10) do
25
+ @msg = nil
26
+ MQ.queue('test1').subscribe { |msg| @msg = msg }
27
+
28
+ loop do
29
+ break unless @msg.nil?
30
+ sleep 1
31
+ end
32
+ end
33
+ rescue Timeout::Error
34
+ violated "Timeout waiting for message"
35
+ end
36
+
37
+ @msg.should match(/^\{.*\}$/) # JSON message by default
38
+ end
39
+
40
+ it "should support 'reply anyway' as participant configuration" do
41
+ pdef = <<-EOF
42
+ class AmqpParticipant0 < OpenWFE::ProcessDefinition
43
+
44
+ sequence do
45
+ amqp :queue => 'test4'
46
+ echo 'done.'
47
+ end
48
+ end
49
+ EOF
50
+
51
+ p = RuoteAMQP::Participant.new( :reply_by_default => true )
52
+ @engine.register_participant( :amqp, p )
53
+
54
+ run_definition( pdef )
55
+
56
+ @tracer.to_s.should == "done."
57
+
58
+ begin
59
+ Timeout::timeout(10) do
60
+ @msg = nil
61
+ MQ.queue('test4').subscribe { |msg| @msg = msg }
62
+
63
+ loop do
64
+ break unless @msg.nil?
65
+ sleep 1
66
+ end
67
+ end
68
+ rescue Timeout::Error
69
+ violated "Timeout waiting for message"
70
+ end
71
+
72
+ @msg.should match( /^\{.*\}$/) # JSON message by default
73
+ end
74
+
75
+ it "should support custom messages instead of workitems" do
76
+ pdef = <<-EOF
77
+ class AmqpParticipant1 < OpenWFE::ProcessDefinition
78
+
79
+ sequence do
80
+ amqp :queue => 'test2', :message => 'foo', 'reply_anyway' => true
81
+ echo 'done.'
82
+ end
83
+ end
84
+ EOF
85
+
86
+ @engine.register_participant( :amqp, RuoteAMQP::Participant )
87
+
88
+ run_definition( pdef )
89
+
90
+ @tracer.to_s.should == "done."
91
+
92
+ begin
93
+ Timeout::timeout(10) do
94
+ @msg = nil
95
+ MQ.queue('test2').subscribe { |msg| @msg = msg }
96
+
97
+ loop do
98
+ break unless @msg.nil?
99
+ sleep 1
100
+ end
101
+ end
102
+ rescue Timeout::Error
103
+ violated "Timeout waiting for message"
104
+ end
105
+
106
+ @msg.should == 'foo'
107
+ end
108
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,87 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
10
+ require 'ruote-amqp'
11
+ require 'spec/ruote'
12
+ require 'fileutils'
13
+
14
+ # AMQP magic worked here
15
+ AMQP.settings[:vhost] = '/ruote-test'
16
+ AMQP.settings[:user] = 'ruote'
17
+ AMQP.settings[:pass] = 'ruote'
18
+
19
+ Spec::Runner.configure do |config|
20
+
21
+ config.include( RuoteSpecHelpers )
22
+
23
+ config.before(:each) do
24
+ @tracer = Tracer.new
25
+
26
+ ac = {}
27
+
28
+ class << ac
29
+ alias :old_put :[]=
30
+ def []= (k, v)
31
+ raise("!!!!! #{k.class}\n#{k.inspect}") \
32
+ if k.class != String and k.class != Symbol
33
+ old_put(k, v)
34
+ end
35
+ end
36
+ #
37
+ # useful for tracking misuses of the application context
38
+
39
+ ac['__tracer'] = @tracer
40
+ ac[:ruby_eval_allowed] = true
41
+ ac[:definition_in_launchitem_allowed] = true
42
+
43
+ @engine = OpenWFE::Engine.new( ac )
44
+
45
+ @terminated_processes = []
46
+ @engine.get_expression_pool.add_observer(:terminate) do |c, fe, wi|
47
+ @terminated_processes << fe.fei.wfid
48
+ #p [ :terminated, @terminated_processes ]
49
+ end
50
+
51
+ if ENV['DEBUG']
52
+ $OWFE_LOG = Logger.new( STDOUT )
53
+ $OWFE_LOG.level = Logger::DEBUG
54
+ end
55
+ end
56
+
57
+ config.after(:each) do
58
+ @engine.stop
59
+ AMQP.stop { EM.stop }
60
+ sleep 0.001 while EM.reactor_running?
61
+ end
62
+
63
+ config.after(:all) do
64
+ base = File.expand_path( File.dirname(__FILE__) + '/..' )
65
+ FileUtils.rm_rf( base + '/logs' )
66
+ FileUtils.rm_rf( base + '/work' )
67
+ end
68
+ end
69
+
70
+
71
+ class Tracer
72
+ def initialize
73
+ @trace = ''
74
+ end
75
+ def to_s
76
+ @trace.to_s.strip
77
+ end
78
+ def << s
79
+ @trace << s
80
+ end
81
+ def clear
82
+ @trace = ''
83
+ end
84
+ def puts s
85
+ @trace << "#{s}\n"
86
+ end
87
+ end
data/tasks/rspec.rake ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
5
+ require 'spec'
6
+ end
7
+ begin
8
+ require 'spec/rake/spectask'
9
+ rescue LoadError
10
+ puts <<-EOS
11
+ To use rspec for testing you must install rspec gem:
12
+ gem install rspec
13
+ EOS
14
+ exit(0)
15
+ end
16
+
17
+ desc "Run the specs under spec/models"
18
+ Spec::Rake::SpecTask.new do |t|
19
+ t.spec_opts = ['--options', "spec/spec.opts"]
20
+ t.spec_files = FileList['spec/**/*_spec.rb']
21
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruote-amqp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.20
5
+ platform: ruby
6
+ authors:
7
+ - Kenneth Kalmer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-13 00:00:00 +02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ruote
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - "="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.9.20
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: amqp
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.6.0
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: hoe
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 2.3.2
44
+ version:
45
+ description: ruote-amqp provides an AMQP participant/listener pair that allows you to distribute workitems out to AMQP consumers for processing. To learn more about remote participants in ruote please see http://openwfe.rubyforge.org/part.html
46
+ email:
47
+ - kenneth.kalmer@gmail.com
48
+ executables: []
49
+
50
+ extensions: []
51
+
52
+ extra_rdoc_files:
53
+ - History.txt
54
+ - Manifest.txt
55
+ - PostInstall.txt
56
+ files:
57
+ - History.txt
58
+ - Manifest.txt
59
+ - PostInstall.txt
60
+ - README.rdoc
61
+ - Rakefile
62
+ - lib/ruote-amqp.rb
63
+ - lib/ruote-amqp/listener.rb
64
+ - lib/ruote-amqp/participant.rb
65
+ - lib/spec/ruote.rb
66
+ - lib/spec/ruote_example_group.rb
67
+ - lib/spec/ruote_helpers.rb
68
+ - lib/spec/ruote_matchers.rb
69
+ - script/console
70
+ - script/destroy
71
+ - script/generate
72
+ - spec/listener_spec.rb
73
+ - spec/participant_spec.rb
74
+ - spec/spec.opts
75
+ - spec/spec_helper.rb
76
+ - tasks/rspec.rake
77
+ has_rdoc: true
78
+ homepage: http://github.com/kennethkalmer/ruote-amqp
79
+ post_install_message: PostInstall.txt
80
+ rdoc_options:
81
+ - --main
82
+ - README.rdoc
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: "0"
90
+ version:
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: "0"
96
+ version:
97
+ requirements: []
98
+
99
+ rubyforge_project: ruote-amqp
100
+ rubygems_version: 1.3.1
101
+ signing_key:
102
+ specification_version: 2
103
+ summary: ruote-amqp provides an AMQP participant/listener pair that allows you to distribute workitems out to AMQP consumers for processing
104
+ test_files: []
105
+