rosetta_queue 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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