bmabey-rosetta_queue 0.2.0 → 0.3.3
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.
- 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
|