rosetta_queue 0.4.0 → 0.5.0

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.
@@ -1,11 +1,17 @@
1
- == 0.4.x (git)
1
+ == 0.5.0 (the "Resource Cleanup" release)
2
+ === New Features (Relevance Inc.)
3
+ * Fixed a socket leak in Producer::publish by using open on the Adapter (at least for Stomp, but probably others too).
4
+ * Add Adapter::open, which has semantics like File::open (ie auto-disconnecting the socket after the block),
5
+ * Removed Adapter::instance due to it's confusing name (it was not a singleton as the name suggested).
6
+ * Allow specifying a key when adding handlers to a consumer, to allow multiple instances of same consumer.
7
+ * Removed dependency on message_handler when calling Adapter#disconnect. (Chris Wyckoff)
2
8
 
3
9
  == 0.4.0
4
10
  === New features
5
11
  * Allows for custom exception handling logic to be registered for publishing and consuming actions. See ExceptionHandler for more info. (Ben Mabey)
6
12
  * RQ was doing a blanket rescue for publishing and consuming and then logging the errors. If you still want this behaviour you will need to register a block/class to do that. Again, see ExceptionHandler for more details.
7
13
  * Added core time extension when ActiveSupport not present. (Chris Wyckoff)
8
- === Bufixes
14
+ === Bugfixes
9
15
  * Closing the connection after publishing message now instead of unsubscribing. (Chris Wyckoff)
10
16
 
11
17
 
@@ -16,7 +22,7 @@
16
22
  * Added .delete method to Consumer class (Chris Wyckoff - Lead Media Partners)
17
23
  * Allows user to purge a queue.
18
24
  * Works for AMQP adapters only.
19
- === Bufixes
25
+ === Bugfixes
20
26
  * client :ack now working. (Chris Wyckoff - Lead Media Partners)
21
27
 
22
28
  == 0.1.4
@@ -1,4 +1,5 @@
1
1
  ---
2
- :minor: 4
3
- :patch: 0
4
2
  :major: 0
3
+ :minor: 5
4
+ :build:
5
+ :patch: 0
File without changes
File without changes
File without changes
@@ -4,7 +4,6 @@ require('rosetta_queue/core_ext/string') unless defined? ActiveSupport
4
4
  require('rosetta_queue/core_ext/time') unless defined? ActiveSupport
5
5
 
6
6
  require 'rosetta_queue/adapter'
7
- require 'rosetta_queue/base'
8
7
  require 'rosetta_queue/consumer'
9
8
  require 'rosetta_queue/destinations'
10
9
  require 'rosetta_queue/exceptions'
@@ -22,9 +22,21 @@ module RosettaQueue
22
22
  raise AdapterException, "Adapter type '#{adapter_prefix}' does not match existing adapters!"
23
23
  end
24
24
 
25
- def instance
25
+ # Yield a new (connected) adapter, run whatever is in the block, and then disconnect after the
26
+ # block evaluates
27
+ def open
26
28
  raise AdapterException, "Adapter type was never defined!" unless @adapter_class
27
- @adapter_class.new({:user => @user, :password => @password, :host => @host, :port => @port, :opts => opts})
29
+ adapter = @adapter_class.new({:user => @user, :password => @password, :host => @host, :port => @port, :opts => opts})
30
+
31
+ if block_given?
32
+ begin
33
+ yield adapter
34
+ ensure
35
+ adapter.disconnect
36
+ end
37
+ end
38
+
39
+ adapter
28
40
  end
29
41
 
30
42
  private
@@ -20,13 +20,13 @@ module RosettaQueue
20
20
  exchange_strategy_for(destination, opts).delete(destination)
21
21
  end
22
22
 
23
- def disconnect(message_handler)
24
- destination = destination_for(message_handler)
25
- exchange_strategy_for(destination).unsubscribe
23
+ def disconnect
24
+ @exchange_strategy.unsubscribe if @exchange_strategy
26
25
  end
27
26
 
28
27
  def receive_once(destination, opts={})
29
- exchange_strategy_for(destination, opts).receive_once(destination) do |msg|
28
+ @exchange_strategy = exchange_strategy_for(destination, opts)
29
+ @exchange_strategy.receive_once(destination) do |msg|
30
30
  return msg
31
31
  end
32
32
  end
@@ -34,15 +34,53 @@ module RosettaQueue
34
34
  def receive_with(message_handler)
35
35
  options = options_for(message_handler)
36
36
  destination = destination_for(message_handler)
37
- exchange_strategy_for(destination, options).receive(destination, message_handler)
37
+ @exchange_strategy = exchange_strategy_for(destination, options)
38
+ @exchange_strategy.receive(destination, message_handler)
38
39
  end
39
40
 
40
41
  def send_message(destination, message, options=nil)
41
- exchange_strategy_for(destination, options).publish(destination, message)
42
+ @exchange_strategy = exchange_strategy_for(destination, options)
43
+ @exchange_strategy.publish(destination, message)
42
44
  end
43
45
 
44
46
  def unsubscribe; end
45
47
 
46
48
  end
49
+
50
+ class AmqpEventedAdapter < Amqp
51
+
52
+ def exchange_strategy_for(destination, options)
53
+ case destination
54
+ when /^fanout\./
55
+ @exchange ||= EventedExchange::FanoutExchange.new(@adapter_settings, options)
56
+ when /^topic\./
57
+ raise "Sorry. RosettaQueue can not process AMQP topics yet"
58
+ when /^queue\./
59
+ @exchange ||= EventedExchange::DirectExchange.new(@adapter_settings, options)
60
+ else
61
+ @exchange ||= EventedExchange::DirectExchange.new(@adapter_settings, options)
62
+ end
63
+ end
64
+ end
65
+
66
+
67
+ # This AMQP adapter utilizes the synchronous AMPQ client 'Bunny'
68
+ # by celldee (http://github.com/celldee/bunny)
69
+ class AmqpSynchAdapter < Amqp
70
+
71
+ def exchange_strategy_for(destination, options={})
72
+ case destination
73
+ when /^fanout\./
74
+ @exchange ||= SynchExchange::FanoutExchange.new(@adapter_settings, options)
75
+ when /^topic\./
76
+ raise "Sorry. RosettaQueue can not process AMQP topics yet"
77
+ when /^queue\./
78
+ @exchange ||= SynchExchange::DirectExchange.new(@adapter_settings, options)
79
+ else
80
+ @exchange ||= SynchExchange::DirectExchange.new(@adapter_settings, options)
81
+ end
82
+ end
83
+ end
84
+
47
85
  end
48
86
  end
@@ -5,23 +5,6 @@ require File.expand_path(File.dirname(__FILE__) + "/amqp.rb")
5
5
  module RosettaQueue
6
6
  module Gateway
7
7
 
8
- class AmqpEventedAdapter < Amqp
9
- private
10
-
11
- def exchange_strategy_for(destination, options)
12
- case destination
13
- when /^fanout\./
14
- @exchange ||= EventedExchange::FanoutExchange.new(@adapter_settings, options)
15
- when /^topic\./
16
- raise "Sorry. RosettaQueue can not process AMQP topics yet"
17
- when /^queue\./
18
- @exchange ||= EventedExchange::DirectExchange.new(@adapter_settings, options)
19
- else
20
- @exchange ||= EventedExchange::DirectExchange.new(@adapter_settings, options)
21
- end
22
- end
23
- end
24
-
25
8
  module EventedExchange
26
9
 
27
10
  class BaseExchange
@@ -34,6 +17,10 @@ module RosettaQueue
34
17
  conn.queue(destination).delete(@options)
35
18
  end
36
19
 
20
+ def unsubscribe
21
+ @queue.unsubscribe if @queue
22
+ end
23
+
37
24
  protected
38
25
 
39
26
  def channel
@@ -55,18 +42,17 @@ module RosettaQueue
55
42
  def publish(destination, message, options={})
56
43
  raise AdapterException, "Messages need to be published in an EventMachine run block (e.g., EM.run { RosettaQueue::Producer.publish(:foo, msg) } " unless EM.reactor_running?
57
44
 
58
- queue = channel.queue(destination, options)
59
- queue.publish(message, options)
45
+ @queue = channel.queue(destination, options)
46
+ @queue.publish(message, options)
60
47
  RosettaQueue.logger.info("Publishing to #{destination} :: #{message}")
61
- queue.unsubscribe
62
48
  end
63
49
 
64
50
  def receive(destination, message_handler)
65
51
  raise AdapterException, "Consumers need to run in an EventMachine 'run' block. Try wrapping them inside the evented consumer manager." unless EM.reactor_running?
66
52
 
67
- queue = channel.queue(destination, @options)
53
+ @queue = channel.queue(destination, @options)
68
54
  ack = @options[:ack]
69
- queue.subscribe(@options) do |header, msg|
55
+ @queue.subscribe(@options) do |header, msg|
70
56
  RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
71
57
  message_handler.handle_message(msg)
72
58
  header.ack if ack
@@ -76,9 +62,9 @@ module RosettaQueue
76
62
  def receive_once(destination, options={})
77
63
  raise AdapterException, "Consumers need to run in an EventMachine 'run' block. (e.g., EM.run { RosettaQueue::Consumer.receive }" unless EM.reactor_running?
78
64
 
79
- queue = channel.queue(destination, @options)
65
+ @queue = channel.queue(destination, @options)
80
66
  ack = @options[:ack]
81
- queue.pop(@options) do |header, msg|
67
+ @queue.pop(@options) do |header, msg|
82
68
  RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
83
69
  header.ack if ack
84
70
  yield Filters.process_receiving(msg)
@@ -93,19 +79,19 @@ module RosettaQueue
93
79
  def publish(dest, msg, opts)
94
80
  raise AdapterException, "Messages need to be published in an EventMachine run block (e.g., EM.run { RosettaQueue::Producer.publish(:foo, msg) } " unless EM.reactor_running?
95
81
 
96
- exchange = channel.fanout(fanout_name_for(dest), opts)
97
- exchange.publish(msg, opts)
82
+ @queue = channel.fanout(fanout_name_for(dest), opts)
83
+ @queue.publish(msg, opts)
98
84
  RosettaQueue.logger.info("Publishing to fanout #{dest} :: #{msg}")
99
85
  end
100
86
 
101
87
  def receive(destination, message_handler)
102
88
  raise AdapterException, "Consumers need to run in an EventMachine 'run' block. Try wrapping them inside the evented consumer manager." unless EM.reactor_running?
103
89
 
104
- queue = channel.queue("queue_#{self.object_id}")
90
+ @queue = channel.queue("queue_#{self.object_id}")
105
91
  exchange = channel.fanout(fanout_name_for(destination), @options)
106
92
  ack = @options[:ack]
107
93
 
108
- queue.bind(exchange).subscribe(@options) do |header, msg|
94
+ @queue.bind(exchange).subscribe(@options) do |header, msg|
109
95
  RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
110
96
  message_handler.handle_message(msg)
111
97
  header.ack if ack
@@ -115,11 +101,11 @@ module RosettaQueue
115
101
  def receive_once(destination, opts={})
116
102
  raise AdapterException, "Consumers need to run in an EventMachine 'run' block. (e.g., EM.run { RosettaQueue::Consumer.receive }" unless EM.reactor_running?
117
103
 
118
- queue = channel.queue("queue_#{self.object_id}")
104
+ @queue = channel.queue("queue_#{self.object_id}")
119
105
  exchange = channel.fanout(fanout_name_for(destination), opts)
120
106
  ack = @options[:ack]
121
107
 
122
- queue.bind(exchange).pop(opts) do |header, msg|
108
+ @queue.bind(exchange).pop(opts) do |header, msg|
123
109
  RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
124
110
  header.ack if ack
125
111
  yield Filters.process_receiving(msg)
@@ -4,25 +4,6 @@ require File.expand_path(File.dirname(__FILE__) + "/amqp.rb")
4
4
  module RosettaQueue
5
5
  module Gateway
6
6
 
7
- # This AMQP adapter utilizes the synchronous AMPQ client 'Bunny'
8
- # by celldee (http://github.com/celldee/bunny)
9
- class AmqpSynchAdapter < Amqp
10
- private
11
-
12
- def exchange_strategy_for(destination, options={})
13
- case destination
14
- when /^fanout\./
15
- @exchange ||= SynchExchange::FanoutExchange.new(@adapter_settings, options)
16
- when /^topic\./
17
- raise "Sorry. RosettaQueue can not process AMQP topics yet"
18
- when /^queue\./
19
- @exchange ||= SynchExchange::DirectExchange.new(@adapter_settings, options)
20
- else
21
- @exchange ||= SynchExchange::DirectExchange.new(@adapter_settings, options)
22
- end
23
- end
24
- end
25
-
26
7
  module SynchExchange
27
8
 
28
9
  class BaseExchange
@@ -58,9 +39,8 @@ module RosettaQueue
58
39
 
59
40
  def publish(destination, message, options={})
60
41
  RosettaQueue.logger.info("Publishing to #{destination} :: #{message}")
61
- queue = conn.queue(destination, options)
62
- queue.publish(message, options)
63
- conn.stop
42
+ @queue = conn.queue(destination, options)
43
+ @queue.publish(message, options)
64
44
  end
65
45
 
66
46
  def receive(destination, message_handler)
@@ -88,8 +68,8 @@ module RosettaQueue
88
68
  include Fanout
89
69
 
90
70
  def publish(destination, message, options={})
91
- exchange = conn.exchange(fanout_name_for(destination), options.merge({:type => :fanout}))
92
- exchange.publish(message, options)
71
+ @queue = conn.exchange(fanout_name_for(destination), options.merge({:type => :fanout}))
72
+ @queue.publish(message, options)
93
73
  RosettaQueue.logger.info("Publishing to fanout #{destination} :: #{message}")
94
74
  end
95
75
 
@@ -3,8 +3,9 @@ module RosettaQueue
3
3
 
4
4
  class FakeAdapter
5
5
 
6
- def initialize
6
+ def initialize(adapter_settings = {})
7
7
  @messages = []
8
+ @open = true
8
9
  end
9
10
 
10
11
  def send_message(queue, message, headers)
@@ -19,6 +20,14 @@ module RosettaQueue
19
20
  @messages.map {|message| message['queue']}
20
21
  end
21
22
 
23
+ def disconnect
24
+ @open = false
25
+ end
26
+
27
+ def open?
28
+ @open == true
29
+ end
30
+
22
31
  end
23
32
 
24
33
  end
@@ -32,11 +32,11 @@ module RosettaQueue
32
32
  end
33
33
 
34
34
  def receive
35
- raise "Null Adpater is in use, you can not consume messages!"
35
+ raise "Null Adapter is in use, you can not consume messages!"
36
36
  end
37
37
 
38
38
  def receive_with(message_handler)
39
- raise "Null Adpater is in use, you can not consume messages!"
39
+ raise "Null Adapter is in use, you can not consume messages!"
40
40
  end
41
41
 
42
42
  def send_message(queue, message, options)
@@ -19,8 +19,8 @@ module RosettaQueue
19
19
  true)
20
20
  end
21
21
 
22
- def disconnect(message_handler)
23
- unsubscribe(destination_for(message_handler))
22
+ def disconnect
23
+ unsubscribe if @destination
24
24
  @conn.disconnect
25
25
  end
26
26
 
@@ -31,38 +31,38 @@ module RosettaQueue
31
31
  end
32
32
 
33
33
  def receive_once(destination, opts)
34
- subscribe(destination, opts)
35
- msg = receive(opts).body
36
- unsubscribe(destination)
37
- RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
34
+ @destination, @options = destination, opts
35
+ subscribe
36
+ msg = receive(@options).body
37
+ unsubscribe
38
+ RosettaQueue.logger.info("Receiving from #{@destination} :: #{msg}")
38
39
  filter_receiving(msg)
39
40
  end
40
41
 
41
42
  def receive_with(message_handler)
42
- options = options_for(message_handler)
43
- destination = destination_for(message_handler)
44
- @conn.subscribe(destination, options)
45
-
43
+ @destination, @options = destination_for(message_handler), options_for(message_handler)
44
+ subscribe
46
45
  running do
47
- msg = receive(options).body
46
+ msg = receive(@options).body
48
47
  Thread.current[:processing] = true
49
- RosettaQueue.logger.info("Receiving from #{destination} :: #{msg}")
48
+ RosettaQueue.logger.info("Receiving from #{@destination} :: #{msg}")
50
49
  message_handler.handle_message(msg)
51
50
  Thread.current[:processing] = false
52
51
  end
53
52
  end
54
53
 
55
54
  def send_message(destination, message, options)
56
- RosettaQueue.logger.info("Publishing to #{destination} :: #{message}")
57
- @conn.send(destination, message, options)
55
+ @destination = destination
56
+ RosettaQueue.logger.info("Publishing to #{@destination} :: #{message}")
57
+ @conn.send(@destination, message, options)
58
58
  end
59
59
 
60
- def subscribe(destination, options)
61
- @conn.subscribe(destination, options)
60
+ def subscribe
61
+ @conn.subscribe(@destination, @options)
62
62
  end
63
63
 
64
- def unsubscribe(destination)
65
- @conn.unsubscribe(destination)
64
+ def unsubscribe
65
+ @conn.unsubscribe(@destination)
66
66
  end
67
67
 
68
68
  private
@@ -73,16 +73,5 @@ module RosettaQueue
73
73
 
74
74
  end
75
75
 
76
- class StompAdapterProxy
77
-
78
- def initialize(adapter, msg)
79
- @adapter, @msg = adapter, msg
80
- end
81
-
82
- def ack
83
- @adapter.ack(@msg)
84
- end
85
- end
86
-
87
76
  end
88
77
  end
@@ -1,15 +1,15 @@
1
1
  module RosettaQueue
2
- class Consumer < Base
2
+ class Consumer
3
3
 
4
4
  def self.receive(destination, options = {})
5
- RosettaQueue::Adapter.instance.receive_once(Destinations.lookup(destination), options)
5
+ RosettaQueue::Adapter.open { |a| return a.receive_once(Destinations.lookup(destination), options) }
6
6
 
7
- rescue Exception=>e
7
+ rescue Exception=>e
8
8
  RosettaQueue.logger.error("Caught exception in Consumer.receive: #{$!}\n" + e.backtrace.join("\n\t"))
9
9
  end
10
10
 
11
11
  def self.delete(destination, options={})
12
- RosettaQueue::Adapter.instance.delete(Destinations.lookup(destination), options)
12
+ RosettaQueue::Adapter.open { |a| a.delete(Destinations.lookup(destination), options)}
13
13
 
14
14
  rescue Exception=>e
15
15
  RosettaQueue.logger.error("Caught exception in Consumer.delete: #{$!}\n" + e.backtrace.join("\n\t"))
@@ -26,5 +26,11 @@ module RosettaQueue
26
26
  RosettaQueue.logger.error("Caught exception in Consumer#receive: #{$!}\n" + e.backtrace.join("\n\t"))
27
27
  end
28
28
 
29
+ private
30
+
31
+ def connection
32
+ @conn ||= Adapter.open
33
+ end
34
+
29
35
  end
30
36
  end
@@ -15,8 +15,7 @@ module RosettaQueue
15
15
  @consumers = {}
16
16
  end
17
17
 
18
- def add(message_handler)
19
- key = message_handler.class.to_s.underscore.to_sym
18
+ def add(message_handler, key = message_handler.class.to_s.underscore.to_sym)
20
19
  @consumers[key] = Consumer.new(message_handler)
21
20
  end
22
21
 
@@ -1,3 +1,4 @@
1
+ require 'eventmachine'
1
2
  require 'rosetta_queue/consumer_managers/base'
2
3
  require 'mq'
3
4
 
@@ -1,6 +1,6 @@
1
1
  module RosettaQueue
2
2
 
3
- class Producer < Base
3
+ class Producer
4
4
  include MessageHandler
5
5
 
6
6
  def self.publish(destination, message, options = {})
@@ -11,10 +11,12 @@ module RosettaQueue
11
11
  :destination => destination,
12
12
  :options => options}
13
13
  }) do
14
- RosettaQueue::Adapter.instance.send_message(
15
- Destinations.lookup(destination),
16
- Filters.process_sending(message),
17
- options)
14
+ RosettaQueue::Adapter.open do |a|
15
+ a.send_message(
16
+ Destinations.lookup(destination),
17
+ Filters.process_sending(message),
18
+ options)
19
+ end
18
20
  end
19
21
  end
20
22
  end
@@ -12,9 +12,9 @@ module RosettaQueue
12
12
  describe ".reset" do
13
13
  it "should clear all definitions" do
14
14
  Adapter.define { |a| a.type = "null" }
15
- Adapter.instance.should be_instance_of(RosettaQueue::Gateway::NullAdapter)
15
+ Adapter.open.should be_instance_of(RosettaQueue::Gateway::NullAdapter)
16
16
  Adapter.reset
17
- running { Adapter.instance }.should raise_error(AdapterException)
17
+ running { Adapter.open }.should raise_error(AdapterException)
18
18
  end
19
19
  end
20
20
 
@@ -31,11 +31,11 @@ module RosettaQueue
31
31
  end
32
32
 
33
33
  describe "adapter not type set" do
34
- it "should raise an error when .instance is called" do
34
+ it "should raise an error when .open 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.open }.should raise_error(AdapterException)
39
39
  end
40
40
  end
41
41
 
@@ -45,8 +45,8 @@ module RosettaQueue
45
45
  Adapter.define { |a| a.type = "null" }
46
46
  end
47
47
 
48
- it "should return adapter instance" do
49
- Adapter.instance.class.should == RosettaQueue::Gateway::NullAdapter
48
+ it "should return adapter open" do
49
+ Adapter.open.class.should == RosettaQueue::Gateway::NullAdapter
50
50
  end
51
51
 
52
52
  end
@@ -64,7 +64,7 @@ module RosettaQueue
64
64
  end
65
65
 
66
66
  def do_process
67
- Adapter.instance
67
+ Adapter.open
68
68
  end
69
69
 
70
70
  it "should set opts as an empty has unless variable is set" do
@@ -92,10 +92,54 @@ module RosettaQueue
92
92
  end
93
93
 
94
94
  it "should raise an adapter exception" do
95
- running { Adapter.instance }.should raise_error("Adapter options should be a hash")
95
+ running { Adapter.open }.should raise_error("Adapter options should be a hash")
96
96
  end
97
97
  end
98
98
 
99
99
  end
100
+
101
+ describe ".open" do
102
+
103
+ before(:each) do
104
+ Adapter.define do |a|
105
+ a.user = "foo"
106
+ a.password = "bar"
107
+ a.host = "localhost"
108
+ a.port = "9000"
109
+ a.type = "fake"
110
+ end
111
+ end
112
+
113
+ it "returns an open adapter if no block is given" do
114
+ adapter = Adapter.open
115
+ adapter.should be_open
116
+ end
117
+
118
+ it "yields a newly-instantiated adapter to the block" do
119
+ ran_block = false
120
+
121
+ Adapter.open do |a|
122
+ a.should_not be_nil
123
+ a.should be_instance_of(RosettaQueue::Gateway::FakeAdapter)
124
+ a.should be_open
125
+ ran_block = true
126
+ end
127
+
128
+ ran_block.should be_true
129
+ end
130
+
131
+ it "closes the adapter after the block is evaluated" do
132
+ Adapter.open {|a| "something" }.should_not be_open
133
+ end
134
+
135
+ it "closes the adapter even if the block raises an error" do
136
+ adapter = nil
137
+ begin
138
+ Adapter.open {|a| adapter = a; raise("some connection error here!") }
139
+ rescue => e;
140
+ end
141
+ adapter.should_not be_open
142
+ end
143
+ end
100
144
  end
101
145
  end
@@ -87,9 +87,35 @@ module RosettaQueue::Gateway
87
87
  end
88
88
 
89
89
  end
90
- end
91
90
 
91
+ describe "#disconnect" do
92
+
93
+ it "delegates to cached exchange strategy" do
94
+ # given
95
+ @adapter.receive_with(@handler)
96
+
97
+ # expect
98
+ @exchange_strategy.should_receive(:unsubscribe)
99
+
100
+ # when
101
+ @adapter.disconnect
102
+ end
103
+
104
+ context "subscription was never made" do
105
+
106
+ it "does not delegate to exchange strategy" do
107
+ # expect
108
+ @exchange_strategy.should_not_receive(:unsubscribe)
92
109
 
110
+ # when
111
+ @adapter.disconnect
112
+ end
113
+
114
+ end
115
+
116
+ end
117
+ end
118
+
93
119
  describe SynchExchange::DirectExchange do
94
120
 
95
121
  before(:each) do
@@ -32,6 +32,13 @@ module RosettaQueue
32
32
  end
33
33
 
34
34
  end
35
+
36
+ describe "#disconnect" do
37
+
38
+ it "allows disconnecting" do
39
+ @adapter.should respond_to(:disconnect)
40
+ end
41
+ end
35
42
 
36
43
  end
37
44
  end
@@ -83,42 +83,48 @@ module RosettaQueue
83
83
 
84
84
  describe "disconnect" do
85
85
 
86
- def do_disconnecting
87
- @adapter.disconnect(@handler)
88
- end
86
+ describe "simple disconnection without previously subscribing" do
89
87
 
90
- it "should unsubscribe connection" do
91
- when_disconnecting {
92
- @conn.should_receive("unsubscribe").with("foo")
93
- }
94
- end
95
-
96
- it "should disconnect connection" do
97
- when_disconnecting {
98
- @conn.should_receive("disconnect")
99
- }
100
- end
88
+ def do_disconnecting
89
+ @adapter.disconnect
90
+ end
101
91
 
102
- end
92
+ it "should NOT try to unsubscribe the connection" do
93
+ when_disconnecting {
94
+ @conn.should_receive("unsubscribe").never
95
+ }
96
+ end
103
97
 
104
- describe StompAdapterProxy do
98
+ it "should disconnect connection" do
99
+ when_disconnecting {
100
+ @conn.should_receive("disconnect")
101
+ }
102
+ end
105
103
 
106
- before(:each) do
107
- @adapter = mock("StompAdapter", :ack => nil)
108
- @proxy = StompAdapterProxy.new(@adapter, "foo")
109
104
  end
110
105
 
111
- context "#ack" do
106
+ describe "when given a previously-subscribed message handler to unsubscribe from" do
112
107
 
113
- it "should delegate to AMQP queue object" do
114
- # expect
115
- @adapter.should_receive(:ack).with("foo")
108
+ def do_disconnecting
109
+ @adapter.receive_with(@handler)
110
+ @adapter.disconnect
111
+ end
116
112
 
117
- # when
118
- @proxy.ack
113
+ it "should unsubscribe connection" do
114
+ when_disconnecting {
115
+ @conn.should_receive("unsubscribe").with("foo")
116
+ }
117
+ end
118
+
119
+ it "should disconnect connection" do
120
+ when_disconnecting {
121
+ @conn.should_receive("disconnect")
122
+ }
119
123
  end
120
124
 
121
125
  end
126
+
127
+
122
128
  end
123
129
 
124
130
  end
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ module RosettaQueue
4
+ describe BaseManager do
5
+
6
+ describe "#add" do
7
+ it "allows adding a handler" do
8
+ BaseManager.new.add(Object.new)
9
+ end
10
+
11
+ it "wraps the handler with a consumer and stores it" do
12
+ handler = Object.new
13
+ Consumer.should_receive(:new).with(handler)
14
+ BaseManager.new.add(handler)
15
+ end
16
+
17
+ describe "storing the consumer" do
18
+ it "uses the class name as the key by default" do
19
+ handler = Object.new
20
+ manager = BaseManager.new
21
+ manager.add(handler)
22
+ manager.consumers.keys.should == [:object]
23
+ end
24
+
25
+ it "allows overriding the key name for cases where you have multiple instances of the same handler class" do
26
+ handler = Object.new
27
+ manager = BaseManager.new
28
+ manager.add(handler, :object_1)
29
+ manager.add(handler, :object_2)
30
+ manager.consumers.keys.should =~ [:object_1, :object_2]
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ end
@@ -16,14 +16,12 @@ module RosettaQueue
16
16
 
17
17
  before(:each) do
18
18
  @message = mock("message", "headers" => "foo", "body" => "message body")
19
- @adapter = mock("adpater", :subscribe => true, :unsubscribe => true, :disconnect => true, :receive_with => TestConsumer.new,
19
+ @adapter = mock("adapter", :subscribe => true, :unsubscribe => true, :disconnect => true, :receive_with => TestConsumer.new,
20
20
  :receive_once => @message.body, :ack => true)
21
- Adapter.stub!(:instance).and_return(@adapter)
21
+ Adapter.stub!(:open).and_yield(@adapter)
22
22
  Destinations.stub!(:lookup).and_return("/queue/foo")
23
23
  end
24
24
 
25
- it_should_behave_like "a messaging gateway object"
26
-
27
25
  attr_reader :adapter
28
26
  def gateway
29
27
  @gateway ||= Consumer.new(TestConsumer.new)
@@ -39,9 +37,10 @@ module RosettaQueue
39
37
  @consumer.receive
40
38
  end
41
39
 
42
- it "should pass message handler onto the adpater with #receive" do
40
+ it "should pass message handler onto the adapter with #receive" do
41
+ Adapter.stub!(:open).and_return(@adapter)
43
42
  when_receiving {
44
- @adapter.should_receive("receive_with").with(@message_handler)
43
+ @adapter.should_receive(:receive_with).with(@message_handler)
45
44
  }
46
45
  end
47
46
  end
@@ -12,44 +12,24 @@ module RosettaQueue
12
12
  describe Producer do
13
13
 
14
14
  before(:each) do
15
- @adapter = mock("adapter", :send_message => nil)
16
- RosettaQueue::Adapter.stub!(:instance).and_return(@adapter)
15
+ @adapter = mock("adapter", :send_message => nil, :disconnect => nil)
16
+ RosettaQueue::Adapter.stub!(:open).and_yield(@adapter)
17
17
  @gateway = TestProducer.new
18
18
 
19
19
  Destinations.stub!(:lookup).and_return("/queue/test_queue")
20
20
  end
21
21
 
22
- it_should_behave_like "a messaging gateway object"
23
22
  attr_reader :adapter, :gateway
24
23
 
25
-
26
- describe "#publish" do
27
-
28
- before(:each) do
29
- @adapter = mock("adpater", :send_message => nil)
30
- RosettaQueue::Adapter.stub!(:instance).and_return(@adapter)
31
- end
32
-
33
- it "should publish messages to queue with the options defined in the class" do
34
- # TO DO: REFACTOR #publish METHOD SO THAT YOU PASS IN MESSAGE HANDLER AS WITH CONSUMER
35
- pending
36
- # expect
37
- @adapter.should_receive(:send_message).with("/queue/test_queue", "Hello World!", {:persistent => false})
38
- # when
39
- @gateway.publish("Hello World!")
40
- end
41
-
42
- end
43
-
44
24
  describe ".publish" do
45
- it "should send the message to the adpater along with the options" do
25
+ it "should send the message to the adapter along with the options" do
46
26
  # expect
47
27
  @adapter.should_receive(:send_message).with("/queue/test_queue", "Hello World!", {:persistent => true})
48
28
  # when
49
29
  Producer.publish(:test_queue, "Hello World!", {:persistent => true})
50
30
  end
51
31
 
52
- it "delgates exception handling to the ExceptionHandler for :publishing" do
32
+ it "delegates exception handling to the ExceptionHandler for :publishing" do
53
33
  ExceptionHandler.should_receive(:handle).with(:publishing, anything)
54
34
  Producer.publish(:test_queue, "Hello World!", {:persistent => true})
55
35
  end
@@ -17,7 +17,6 @@ require 'rosetta_queue/spec_helpers'
17
17
  require 'rosetta_queue/consumer_managers/base'
18
18
  require 'rosetta_queue/consumer_managers/evented'
19
19
  require 'rosetta_queue/consumer_managers/threaded'
20
- require File.dirname(__FILE__) + '/rosetta_queue/shared_messaging_behavior.rb'
21
20
 
22
21
  class NullLogger
23
22
  def info(*args); end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rosetta_queue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Mabey
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-09-28 00:00:00 -06:00
13
+ date: 2009-12-21 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -38,6 +38,10 @@ files:
38
38
  - features/step_definitions/publish_subscribe_steps.rb
39
39
  - features/support/env.rb
40
40
  - features/support/sample_consumers.rb
41
+ - features/support/tmp/barconsumer.log
42
+ - features/support/tmp/fooconsumer.log
43
+ - features/support/tmp/point-to-point.log
44
+ - features/support/tmp/pub-sub.log
41
45
  - lib/rosetta_queue.rb
42
46
  - lib/rosetta_queue/adapter.rb
43
47
  - lib/rosetta_queue/adapters/amqp.rb
@@ -48,7 +52,6 @@ files:
48
52
  - lib/rosetta_queue/adapters/fake.rb
49
53
  - lib/rosetta_queue/adapters/null.rb
50
54
  - lib/rosetta_queue/adapters/stomp.rb
51
- - lib/rosetta_queue/base.rb
52
55
  - lib/rosetta_queue/consumer.rb
53
56
  - lib/rosetta_queue/consumer_managers/base.rb
54
57
  - lib/rosetta_queue/consumer_managers/evented.rb
@@ -74,6 +77,7 @@ files:
74
77
  - spec/rosetta_queue/adapters/shared_adapter_behavior.rb
75
78
  - spec/rosetta_queue/adapters/shared_fanout_behavior.rb
76
79
  - spec/rosetta_queue/adapters/stomp_spec.rb
80
+ - spec/rosetta_queue/consumer_managers/base_spec.rb
77
81
  - spec/rosetta_queue/consumer_managers/evented_spec.rb
78
82
  - spec/rosetta_queue/consumer_managers/shared_manager_behavior.rb
79
83
  - spec/rosetta_queue/consumer_managers/threaded_spec.rb
@@ -84,7 +88,6 @@ files:
84
88
  - spec/rosetta_queue/filters_spec.rb
85
89
  - spec/rosetta_queue/message_handler_spec.rb
86
90
  - spec/rosetta_queue/producer_spec.rb
87
- - spec/rosetta_queue/shared_messaging_behavior.rb
88
91
  - spec/spec.opts
89
92
  - spec/spec_helper.rb
90
93
  has_rdoc: true
@@ -111,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
114
  requirements: []
112
115
 
113
116
  rubyforge_project: rosetta-queue
114
- rubygems_version: 1.3.3
117
+ rubygems_version: 1.3.5
115
118
  signing_key:
116
119
  specification_version: 3
117
120
  summary: Messaging gateway API with adapters for many messaging systems available in Ruby.
@@ -124,6 +127,7 @@ test_files:
124
127
  - spec/rosetta_queue/adapters/shared_adapter_behavior.rb
125
128
  - spec/rosetta_queue/adapters/shared_fanout_behavior.rb
126
129
  - spec/rosetta_queue/adapters/stomp_spec.rb
130
+ - spec/rosetta_queue/consumer_managers/base_spec.rb
127
131
  - spec/rosetta_queue/consumer_managers/evented_spec.rb
128
132
  - spec/rosetta_queue/consumer_managers/shared_manager_behavior.rb
129
133
  - spec/rosetta_queue/consumer_managers/threaded_spec.rb
@@ -134,7 +138,6 @@ test_files:
134
138
  - spec/rosetta_queue/filters_spec.rb
135
139
  - spec/rosetta_queue/message_handler_spec.rb
136
140
  - spec/rosetta_queue/producer_spec.rb
137
- - spec/rosetta_queue/shared_messaging_behavior.rb
138
141
  - spec/spec_helper.rb
139
142
  - examples/sample_amqp_consumer.rb
140
143
  - examples/sample_amqp_fanout_consumer.rb
@@ -1,15 +0,0 @@
1
- module RosettaQueue
2
-
3
- class Base
4
-
5
- def disconnect
6
- connection.disconnect(@message_handler)
7
- end
8
-
9
- protected
10
- def connection
11
- @conn ||= Adapter.instance
12
- end
13
-
14
- end
15
- end
@@ -1,21 +0,0 @@
1
- module RosettaQueue
2
-
3
- describe "a messaging gateway object", :shared => true do
4
-
5
- it "#unsubscribe should be delegated to the adapter" do
6
- pending
7
- # expect
8
- adapter.should_receive("unsubscribe")
9
- # when
10
- gateway.unsubscribe
11
- end
12
-
13
- it "#disconnect should be delegated to the adapter" do
14
- # expect
15
- adapter.should_receive("disconnect")
16
- # when
17
- gateway.disconnect
18
- end
19
-
20
- end
21
- end