bmabey-rosetta_queue 0.2.0 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +6 -3
- data/README.rdoc +1 -193
- data/Rakefile +7 -1
- data/cucumber.yml +1 -1
- data/examples/sample_amqp_consumer.rb +13 -3
- data/examples/sample_amqp_fanout_consumer.rb +6 -3
- data/examples/sample_amqp_fanout_producer.rb +3 -2
- data/examples/sample_amqp_producer.rb +2 -1
- data/features/filtering.feature +13 -13
- data/features/messaging.feature +28 -20
- data/features/step_definitions/common_messaging_steps.rb +54 -17
- data/features/step_definitions/filtering_steps.rb +2 -2
- data/features/step_definitions/point_to_point_steps.rb +19 -9
- data/features/step_definitions/publish_subscribe_steps.rb +22 -8
- data/features/support/env.rb +2 -0
- data/features/support/sample_consumers.rb +6 -6
- data/lib/rosetta_queue.rb +1 -0
- data/lib/rosetta_queue/adapter.rb +6 -6
- data/lib/rosetta_queue/adapters/amqp.rb +6 -3
- data/lib/rosetta_queue/adapters/amqp_evented.rb +22 -22
- data/lib/rosetta_queue/adapters/amqp_synch.rb +42 -36
- data/lib/rosetta_queue/adapters/base.rb +3 -3
- data/lib/rosetta_queue/adapters/beanstalk.rb +5 -5
- data/lib/rosetta_queue/adapters/fake.rb +5 -5
- data/lib/rosetta_queue/adapters/null.rb +9 -9
- data/lib/rosetta_queue/adapters/stomp.rb +25 -12
- data/lib/rosetta_queue/base.rb +2 -2
- data/lib/rosetta_queue/consumer.rb +4 -4
- data/lib/rosetta_queue/consumer_managers/base.rb +8 -6
- data/lib/rosetta_queue/consumer_managers/evented.rb +5 -5
- data/lib/rosetta_queue/consumer_managers/threaded.rb +4 -4
- data/lib/rosetta_queue/core_ext/string.rb +3 -3
- data/lib/rosetta_queue/core_ext/time.rb +20 -0
- data/lib/rosetta_queue/destinations.rb +6 -6
- data/lib/rosetta_queue/filters.rb +8 -8
- data/lib/rosetta_queue/logger.rb +2 -2
- data/lib/rosetta_queue/message_handler.rb +10 -4
- data/lib/rosetta_queue/producer.rb +2 -2
- data/lib/rosetta_queue/spec_helpers/hash.rb +3 -3
- data/lib/rosetta_queue/spec_helpers/helpers.rb +8 -8
- data/lib/rosetta_queue/spec_helpers/publishing_matchers.rb +26 -26
- data/spec/rosetta_queue/adapter_spec.rb +27 -27
- data/spec/rosetta_queue/adapters/amqp_synchronous_spec.rb +21 -1
- data/spec/rosetta_queue/adapters/beanstalk_spec.rb +3 -3
- data/spec/rosetta_queue/adapters/fake_spec.rb +6 -6
- data/spec/rosetta_queue/adapters/null_spec.rb +5 -5
- data/spec/rosetta_queue/adapters/shared_adapter_behavior.rb +4 -4
- data/spec/rosetta_queue/adapters/shared_fanout_behavior.rb +1 -1
- data/spec/rosetta_queue/adapters/stomp_spec.rb +39 -18
- data/spec/rosetta_queue/consumer_managers/evented_spec.rb +6 -6
- data/spec/rosetta_queue/consumer_managers/shared_manager_behavior.rb +3 -3
- data/spec/rosetta_queue/consumer_managers/threaded_spec.rb +5 -5
- data/spec/rosetta_queue/consumer_spec.rb +13 -13
- data/spec/rosetta_queue/core_ext/string_spec.rb +3 -3
- data/spec/rosetta_queue/destinations_spec.rb +8 -8
- data/spec/rosetta_queue/filters_spec.rb +16 -16
- data/spec/rosetta_queue/producer_spec.rb +15 -15
- data/spec/rosetta_queue/shared_messaging_behavior.rb +6 -6
- metadata +3 -2
@@ -7,36 +7,36 @@
|
|
7
7
|
|
8
8
|
module RosettaQueue
|
9
9
|
class Filters
|
10
|
-
|
10
|
+
|
11
11
|
class << self
|
12
|
-
|
12
|
+
|
13
13
|
def define
|
14
14
|
yield self
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def reset
|
18
18
|
@receiving = nil
|
19
19
|
@sending = nil
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def receiving(&receiving_filter)
|
23
23
|
@receiving = receiving_filter
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def sending(&sending_filter)
|
27
27
|
@sending = sending_filter
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
def process_sending(message)
|
31
31
|
return message unless @sending
|
32
32
|
@sending.call(message)
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def process_receiving(message)
|
36
36
|
return message unless @receiving
|
37
37
|
@receiving.call(message)
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
data/lib/rosetta_queue/logger.rb
CHANGED
@@ -6,7 +6,7 @@ module RosettaQueue
|
|
6
6
|
def self.logger=(new_logger)
|
7
7
|
@logger = new_logger
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def self.logger
|
11
11
|
return @logger if @logger
|
12
12
|
raise MissingLogger, "No logger has been set for RosettaQueue. Please define one with RosettaQueue.logger=."
|
@@ -19,7 +19,7 @@ module RosettaQueue
|
|
19
19
|
class Logger < ::Logger
|
20
20
|
|
21
21
|
def format_message(severity, timestamp, progname, msg)
|
22
|
-
"[#{timestamp.to_formatted_s(:db)}] #{severity} #{msg}\n"
|
22
|
+
"[#{timestamp.to_formatted_s(:db)}] #{severity} -- : #{msg}\n"
|
23
23
|
end
|
24
24
|
|
25
25
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module RosettaQueue
|
2
2
|
module MessageHandler
|
3
|
-
|
3
|
+
|
4
4
|
module ClassMethods
|
5
5
|
|
6
6
|
attr_reader :destination, :options_hash
|
@@ -17,17 +17,23 @@ module RosettaQueue
|
|
17
17
|
@destination = destination
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
def self.included(receiver)
|
22
22
|
receiver.extend(ClassMethods)
|
23
|
+
attr_accessor :adapter_proxy
|
23
24
|
|
24
25
|
def destination
|
25
|
-
self.class.destination
|
26
|
+
self.class.destination
|
26
27
|
end
|
27
|
-
|
28
|
+
|
28
29
|
def options_hash
|
29
30
|
self.class.options_hash
|
30
31
|
end
|
32
|
+
|
33
|
+
def ack
|
34
|
+
adapter_proxy.ack unless adapter_proxy.nil?
|
35
|
+
end
|
36
|
+
|
31
37
|
end
|
32
38
|
end
|
33
39
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module RosettaQueue
|
2
|
-
|
2
|
+
|
3
3
|
class Producer < Base
|
4
4
|
include MessageHandler
|
5
5
|
|
6
6
|
def self.publish(destination, message, options = {})
|
7
7
|
RosettaQueue::Adapter.instance.send_message(Destinations.lookup(destination), Filters.process_sending(message), options)
|
8
8
|
|
9
|
-
rescue Exception=>e
|
9
|
+
rescue Exception => e
|
10
10
|
RosettaQueue.logger.error("Caught exception in Consumer.publish: #{$!}\n" + e.backtrace.join("\n\t"))
|
11
11
|
end
|
12
12
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class Hash
|
2
2
|
# To be used in conjuction with rspec's predicate matcher.
|
3
3
|
#
|
4
|
-
# For example, in story/feature or a functional spec you could say:
|
4
|
+
# For example, in story/feature or a functional spec you could say:
|
5
5
|
#
|
6
6
|
# expected_message = {'name' => 'Advertiser'}
|
7
7
|
# expected_message.should be_published_to(:advertiser_create)
|
@@ -13,9 +13,9 @@ class Hash
|
|
13
13
|
rescue Timeout::Error
|
14
14
|
raise "#{destination} should have received a message but did not NOTE: make sure there are no other processes which are polling messages"
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
# calling should == is kinda wierd, I know.. but in order to get a decent error message it is needed
|
18
18
|
received_message.should == self
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
end
|
@@ -4,18 +4,18 @@ module RosettaQueue
|
|
4
4
|
# World {|world| world.extend RosettaQueue::SpecHelpers }
|
5
5
|
module SpecHelpers
|
6
6
|
require 'open-uri'
|
7
|
-
|
8
|
-
# *Currently* only works with ActiveMQ being used as gateway.
|
7
|
+
|
8
|
+
# *Currently* only works with ActiveMQ being used as gateway.
|
9
9
|
# This will clear the queues defined in the RosettaQueue::Destinations mapping.
|
10
10
|
# TODO: Figure out a better spot for this to allow for other gateways...
|
11
11
|
def clear_queues
|
12
|
-
RosettaQueue::Destinations.queue_names.each do |name|
|
12
|
+
RosettaQueue::Destinations.queue_names.each do |name|
|
13
13
|
queue = name.gsub('/queue/','')
|
14
14
|
open("http://127.0.0.1:8161/admin/deleteDestination.action?JMSDestination=#{queue}&JMSDestinationType=queue")
|
15
15
|
end
|
16
16
|
end
|
17
|
-
|
18
|
-
# Publishes a given hash as json to the specified destination.
|
17
|
+
|
18
|
+
# Publishes a given hash as json to the specified destination.
|
19
19
|
# Example:
|
20
20
|
# publish_message(expected_message, :to => :client_status, :options => {...})
|
21
21
|
# The :options will be passed to the publisher and are optional.
|
@@ -23,14 +23,14 @@ module RosettaQueue
|
|
23
23
|
options[:options] ||= {:persistent => false}
|
24
24
|
RosettaQueue::Producer.publish(options[:to], message, options[:options])
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
# Consumes the first message on queue of consumer that is passed in and uses the consumer to handle it.
|
28
28
|
# Example:
|
29
29
|
# consume_once_with ClientStatusConsumer
|
30
30
|
def consume_once_with(consumer)
|
31
31
|
consumer.new.on_message(RosettaQueue::Consumer.receive(consumer.destination))
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
# Consumes the first message on queue and returns it.
|
35
35
|
# Example:
|
36
36
|
# message = consume_once :foo_queue
|
@@ -42,6 +42,6 @@ module RosettaQueue
|
|
42
42
|
sleep 1
|
43
43
|
Messaging::Consumer.receive(destination, :persistent => false).to_hash_from_json
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
end
|
47
47
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module RosettaQueue
|
2
2
|
module Matchers
|
3
|
-
|
3
|
+
|
4
4
|
class PublishAMessageTo
|
5
5
|
|
6
6
|
def initialize(expected_queue_name, options=nil)
|
@@ -10,14 +10,14 @@ module RosettaQueue
|
|
10
10
|
@expected_queue = expected_queue_name.is_a?(Symbol) ? RosettaQueue::Destinations.lookup(expected_queue_name) : expected_queue_name
|
11
11
|
end
|
12
12
|
|
13
|
-
def matches?(lambda_to_run)
|
13
|
+
def matches?(lambda_to_run)
|
14
14
|
#given
|
15
15
|
RosettaQueue::Adapter.stub!(:instance).and_return(fake_adapter = RosettaQueue::Gateway::FakeAdapter.new)
|
16
16
|
#when
|
17
17
|
lambda_to_run.call
|
18
18
|
#then
|
19
|
-
@actual_queues = fake_adapter.queues
|
20
|
-
@number_of_messages_published = @actual_queues.select{ |q| q == @expected_queue}.size
|
19
|
+
@actual_queues = fake_adapter.queues
|
20
|
+
@number_of_messages_published = @actual_queues.select{ |q| q == @expected_queue}.size
|
21
21
|
@number_of_messages_published == @how_many_messages_expected
|
22
22
|
end
|
23
23
|
|
@@ -32,7 +32,7 @@ module RosettaQueue
|
|
32
32
|
def description
|
33
33
|
"publish #{message_plural} to the '#{@expected_queue_name}' queue"
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
private
|
37
37
|
def message_plural
|
38
38
|
@how_many_messages_expected == 1 ? "a message" : "#{@how_many_messages_expected} messages"
|
@@ -42,16 +42,16 @@ module RosettaQueue
|
|
42
42
|
def publish_a_message_to(expected_queue)
|
43
43
|
PublishAMessageTo.new(expected_queue)
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
alias :publish_message_to :publish_a_message_to
|
47
|
-
|
47
|
+
|
48
48
|
def publish_messages_to(expected_queue, options)
|
49
49
|
PublishAMessageTo.new(expected_queue, options)
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
class PublishMessageMatcher
|
53
|
-
|
54
|
-
|
53
|
+
|
54
|
+
|
55
55
|
def matches?(lambda_to_run)
|
56
56
|
#given
|
57
57
|
RosettaQueue::Adapter.stub!(:instance).and_return(fake_adapter = RosettaQueue::Gateway::FakeAdapter.new)
|
@@ -61,30 +61,30 @@ module RosettaQueue
|
|
61
61
|
message = fake_adapter.messages_sent_to(@expected_queue).first || ''
|
62
62
|
@actual_message = message
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
protected
|
66
66
|
def extract_options(options)
|
67
|
-
if (expected_queue_name = options[:to])
|
67
|
+
if (expected_queue_name = options[:to])
|
68
68
|
@expected_queue = expected_queue_name.is_a?(Symbol) ? RosettaQueue::Destinations.lookup(expected_queue_name) : expected_queue_name
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
class PublishMessageWith < PublishMessageMatcher
|
74
|
-
|
74
|
+
|
75
75
|
def initialize(message_subset, options)
|
76
76
|
@message_subset = message_subset
|
77
77
|
extract_options(options)
|
78
78
|
end
|
79
79
|
|
80
|
-
def matches?(lambda_to_run)
|
80
|
+
def matches?(lambda_to_run)
|
81
81
|
super
|
82
82
|
Spec::Mocks::ArgumentConstraints::HashIncludingConstraint.new(@message_subset) == @actual_message
|
83
83
|
end
|
84
84
|
|
85
85
|
def failure_message
|
86
86
|
if @actual_message.blank?
|
87
|
-
"expected #{@message_subset.inspect} to be contained in a message but no message was published"
|
87
|
+
"expected #{@message_subset.inspect} to be contained in a message but no message was published"
|
88
88
|
else
|
89
89
|
"expected #{@message_subset.inspect} to be contained in the message: #{@actual_message.inspect}"
|
90
90
|
end
|
@@ -97,29 +97,29 @@ module RosettaQueue
|
|
97
97
|
def description
|
98
98
|
"publish a message with #{@message_subset.inspect}"
|
99
99
|
end
|
100
|
-
|
100
|
+
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
def publish_message_with(message_subset, options={})
|
104
104
|
PublishMessageWith.new(message_subset, options)
|
105
105
|
end
|
106
|
-
|
107
|
-
|
106
|
+
|
107
|
+
|
108
108
|
class PublishMessage < PublishMessageMatcher
|
109
|
-
|
109
|
+
|
110
110
|
def initialize(expected_message, options)
|
111
111
|
@expected_message = expected_message
|
112
112
|
extract_options(options)
|
113
113
|
end
|
114
114
|
|
115
|
-
def matches?(lambda_to_run)
|
115
|
+
def matches?(lambda_to_run)
|
116
116
|
super
|
117
117
|
@actual_message == @expected_message
|
118
118
|
end
|
119
119
|
|
120
120
|
def failure_message
|
121
121
|
if @actual_message.blank?
|
122
|
-
"expected #{@expected_message.inspect} to be published but no message was"
|
122
|
+
"expected #{@expected_message.inspect} to be published but no message was"
|
123
123
|
else
|
124
124
|
"expected #{@expected_message.inspect} to be published but the following was instead: #{@actual_message.inspect}"
|
125
125
|
end
|
@@ -132,13 +132,13 @@ module RosettaQueue
|
|
132
132
|
def description
|
133
133
|
"publish the message: #{@expected_message.inspect}"
|
134
134
|
end
|
135
|
-
|
135
|
+
|
136
136
|
end
|
137
|
-
|
137
|
+
|
138
138
|
def publish_message(exact_expected_message, options={})
|
139
139
|
PublishMessage.new(exact_expected_message, options)
|
140
140
|
end
|
141
|
-
|
141
|
+
|
142
142
|
end
|
143
143
|
end
|
144
144
|
|
@@ -1,14 +1,14 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../spec_helper'
|
2
2
|
|
3
3
|
module RosettaQueue
|
4
|
-
|
4
|
+
|
5
5
|
describe Adapter do
|
6
6
|
|
7
7
|
before(:each) do
|
8
8
|
@stomp_adapter = mock("Gateway::StompAdapter")
|
9
9
|
Adapter.reset
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
describe ".reset" do
|
13
13
|
it "should clear all definitions" do
|
14
14
|
Adapter.define { |a| a.type = "null" }
|
@@ -17,38 +17,38 @@ module RosettaQueue
|
|
17
17
|
running { Adapter.instance }.should raise_error(AdapterException)
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
describe ".type=" do
|
22
|
-
|
22
|
+
|
23
23
|
it "should raise error when adapter does not exist" do
|
24
|
-
running {
|
24
|
+
running {
|
25
25
|
Adapter.define do |a|
|
26
26
|
a.type = "foo"
|
27
27
|
end
|
28
28
|
}.should raise_error(AdapterException)
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
describe "adapter not type set" do
|
34
34
|
it "should raise an error when .instance is called" do
|
35
35
|
# given
|
36
36
|
Adapter.define { |a| }
|
37
37
|
# then & when
|
38
|
-
running { Adapter.instance }.should raise_error(AdapterException)
|
38
|
+
running { Adapter.instance }.should raise_error(AdapterException)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
describe "adapter type set" do
|
43
|
-
|
43
|
+
|
44
44
|
before(:each) do
|
45
45
|
Adapter.define { |a| a.type = "null" }
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
it "should return adapter instance" do
|
49
49
|
Adapter.instance.class.should == RosettaQueue::Gateway::NullAdapter
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
end
|
53
53
|
|
54
54
|
describe "adapter instantiation" do
|
@@ -61,41 +61,41 @@ module RosettaQueue
|
|
61
61
|
a.port = "9000"
|
62
62
|
a.type = "fake"
|
63
63
|
end
|
64
|
-
end
|
65
|
-
|
64
|
+
end
|
65
|
+
|
66
66
|
def do_process
|
67
67
|
Adapter.instance
|
68
68
|
end
|
69
69
|
|
70
70
|
it "should set opts as an empty has unless variable is set" do
|
71
|
-
during_process {
|
71
|
+
during_process {
|
72
72
|
RosettaQueue::Gateway::FakeAdapter.should_receive(:new).with({:user => "foo", :password => "bar", :host => "localhost", :port => "9000", :opts => {}})
|
73
73
|
}
|
74
|
-
end
|
74
|
+
end
|
75
75
|
|
76
76
|
describe "when setting options" do
|
77
77
|
before(:each) do
|
78
78
|
Adapter.define { |a| a.options = {:vhost => "baz"} }
|
79
|
-
end
|
80
|
-
|
79
|
+
end
|
80
|
+
|
81
81
|
it "should map adapter_settings to a hash" do
|
82
|
-
during_process {
|
82
|
+
during_process {
|
83
83
|
RosettaQueue::Gateway::FakeAdapter.should_receive(:new).with({:user => "foo", :password => "bar", :host => "localhost", :port => "9000", :opts => {:vhost => "baz"}})
|
84
84
|
}
|
85
|
-
end
|
86
|
-
end
|
85
|
+
end
|
86
|
+
end
|
87
87
|
|
88
88
|
describe "setting options incorrectly (options should always be set as a Hash)" do
|
89
|
-
|
89
|
+
|
90
90
|
before(:each) do
|
91
91
|
Adapter.define { |a| a.options = "baz" }
|
92
|
-
end
|
93
|
-
|
92
|
+
end
|
93
|
+
|
94
94
|
it "should raise an adapter exception" do
|
95
95
|
running { Adapter.instance }.should raise_error("Adapter options should be a hash")
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
100
|
end
|
101
101
|
end
|