amqp 1.0.0.pre2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/.travis.yml +3 -0
  2. data/README.md +80 -72
  3. data/amqp.gemspec +5 -13
  4. data/docs/08Migration.textile +4 -0
  5. data/docs/AMQP091ModelExplained.textile +6 -1
  6. data/docs/Bindings.textile +4 -0
  7. data/docs/Clustering.textile +4 -0
  8. data/docs/ConnectingToTheBroker.textile +4 -0
  9. data/docs/ConnectionEncryptionWithTLS.textile +4 -0
  10. data/docs/DocumentationGuidesIndex.textile +4 -0
  11. data/docs/Durability.textile +4 -0
  12. data/docs/ErrorHandling.textile +4 -0
  13. data/docs/Exchanges.textile +4 -0
  14. data/docs/GettingStarted.textile +4 -0
  15. data/docs/PatternsAndUseCases.textile +4 -1
  16. data/docs/Queues.textile +4 -0
  17. data/docs/RabbitMQVersions.textile +4 -0
  18. data/docs/RunningTests.textile +4 -0
  19. data/docs/TestingWithEventedSpec.textile +4 -0
  20. data/docs/Troubleshooting.textile +4 -0
  21. data/docs/VendorSpecificExtensions.textile +4 -0
  22. data/examples/error_handling/automatic_recovery_of_channel_and_queues.rb +1 -1
  23. data/examples/error_handling/automatically_recovering_hello_world_consumer.rb +1 -1
  24. data/examples/error_handling/automatically_recovering_hello_world_consumer_that_uses_a_server_named_queue.rb +1 -1
  25. data/examples/error_handling/connection_level_exception.rb +1 -1
  26. data/examples/error_handling/connection_level_exception_with_objects.rb +1 -1
  27. data/examples/error_handling/connection_loss_handler.rb +4 -3
  28. data/examples/error_handling/hello_world_producer.rb +1 -1
  29. data/examples/error_handling/manual_connection_and_channel_recovery.rb +1 -1
  30. data/examples/extensions/rabbitmq/publisher_confirmations_with_transient_messages.rb +1 -1
  31. data/examples/extensions/rabbitmq/using_alternate_exchanges.rb +1 -1
  32. data/examples/guides/getting_started/01_hello_world.rb +1 -1
  33. data/examples/guides/getting_started/02_hello_world_dslified.rb +1 -1
  34. data/examples/hello_world.rb +1 -1
  35. data/examples/hello_world_with_an_empty_string.rb +1 -1
  36. data/examples/hello_world_with_eventmachine_in_a_separate_thread.rb +2 -2
  37. data/examples/hello_world_with_large_payload.rb +41 -41
  38. data/examples/patterns/request_reply/client.rb +1 -2
  39. data/examples/patterns/request_reply/server.rb +0 -1
  40. data/examples/publishing/returned_messages.rb +1 -1
  41. data/examples/queues/accessing_message_metadata.rb +1 -1
  42. data/examples/queues/cancel_default_consumer.rb +1 -1
  43. data/lib/amqp/channel.rb +34 -16
  44. data/lib/amqp/client.rb +2 -2
  45. data/lib/amqp/connection.rb +2 -1
  46. data/lib/amqp/consumer.rb +2 -2
  47. data/lib/amqp/exceptions.rb +11 -2
  48. data/lib/amqp/exchange.rb +5 -5
  49. data/lib/amqp/queue.rb +51 -26
  50. data/lib/amqp/session.rb +5 -5
  51. data/lib/amqp/version.rb +1 -1
  52. data/spec/integration/basic_get_spec.rb +82 -27
  53. data/spec/integration/basic_return_spec.rb +3 -3
  54. data/spec/integration/channel_level_exception_with_multiple_channels_spec.rb +0 -1
  55. data/spec/integration/exchange_declaration_spec.rb +71 -102
  56. data/spec/integration/extensions/rabbitmq/publisher_confirmations_spec.rb +1 -1
  57. data/spec/integration/fanout_exchange_routing_spec.rb +1 -1
  58. data/spec/integration/multiple_consumers_per_queue_spec.rb +3 -160
  59. data/spec/integration/queue_redeclaration_with_incompatible_attributes_spec.rb +25 -12
  60. data/spec/integration/regressions/concurrent_publishing_on_the_same_channel_spec.rb +1 -1
  61. data/spec/integration/remove_individual_binding_spec.rb +51 -0
  62. data/spec/integration/reply_queue_communication_spec.rb +1 -2
  63. data/spec/integration/store_and_forward_spec.rb +6 -9
  64. data/spec/integration/topic_subscription_spec.rb +5 -4
  65. data/spec/spec_helper.rb +8 -2
  66. data/spec/unit/amqp/connection_spec.rb +3 -1
  67. metadata +93 -109
  68. data/spec/integration/immediate_messages_spec.rb +0 -59
@@ -22,7 +22,7 @@ module AMQP
22
22
  # @see AMQP.connect
23
23
  # @api plugin
24
24
  #
25
- # @see http://bit.ly/ks8MXK Connecting to The Broker documentation guide
25
+ # @see http://rubyamqp.info/articles/connecting_to_broker/ Connecting to The Broker documentation guide
26
26
  def self.connect(connection_string_or_options = {}, options = {}, &block)
27
27
  opts = case connection_string_or_options
28
28
  when String then
@@ -82,7 +82,7 @@ module AMQP
82
82
  #
83
83
  # @raise [ArgumentError] When connection URI schema is not amqp or amqps, or the path contains multiple segments
84
84
  #
85
- # @see http://bit.ly/ks8MXK Connecting to The Broker documentation guide
85
+ # @see http://rubyamqp.info/articles/connecting_to_broker/ Connecting to The Broker documentation guide
86
86
  # @api public
87
87
  def self.parse_connection_uri(connection_string)
88
88
  AMQ::Client::Settings.parse_amqp_url(connection_string)
@@ -54,7 +54,7 @@ module AMQP
54
54
  # Pass it a block if you want a piece of code to be run once default connection
55
55
  # is successfully closed.
56
56
  #
57
- # @note If default connection was never estabilished or is in the closing state already,
57
+ # @note If default connection was never established or is in the closing state already,
58
58
  # this method has no effect.
59
59
  # @api public
60
60
  def self.stop(reply_code = 200, reply_text = "Goodbye", &block)
@@ -192,6 +192,7 @@ module AMQP
192
192
  # @option connection_options_or_string [String] :username ("guest") Username to use. Also can be specified as :user.
193
193
  # @option connection_options_or_string [String] :password ("guest") Password to use. Also can be specified as :pass.
194
194
  # @option connection_options_or_string [Hash] :ssl TLS (SSL) parameters to use.
195
+ # @option connection_options_or_string [Fixnum] :heartbeat (0) Connection heartbeat, in seconds. 0 means no heartbeat. Can also be configured server-side starting with RabbitMQ 3.0.
195
196
  # @option connection_options_or_string [#call] :on_tcp_connection_failure A callable object that will be run if connection to server fails
196
197
  # @option connection_options_or_string [#call] :on_possible_authentication_failure A callable object that will be run if authentication fails (see Authentication failure section)
197
198
  #
@@ -139,7 +139,7 @@ module AMQP
139
139
  # @return [Consumer] self
140
140
  #
141
141
  # @api public
142
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.8.3.13.)
142
+ # @see http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Reference.pdf AMQP 0.9.1 protocol documentation (Section 1.8.3.13.)
143
143
  def acknowledge(delivery_tag)
144
144
  super(delivery_tag)
145
145
  end # acknowledge(delivery_tag)
@@ -148,7 +148,7 @@ module AMQP
148
148
  # @return [Consumer] self
149
149
  #
150
150
  # @api public
151
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.8.3.14.)
151
+ # @see http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Reference.pdf AMQP 0.9.1 protocol documentation (Section 1.8.3.14.)
152
152
  def reject(delivery_tag, requeue = true)
153
153
  super(delivery_tag, requeue)
154
154
  end # reject(delivery_tag, requeue = true)
@@ -30,7 +30,7 @@ module AMQP
30
30
  @settings = settings
31
31
  @cause = cause
32
32
 
33
- super("Could not estabilish TCP connection to #{@settings[:host]}:#{@settings[:port]}")
33
+ super("Could not establish TCP connection to #{@settings[:host]}:#{@settings[:port]}")
34
34
  end # TCPConnectionFailed
35
35
  end
36
36
 
@@ -43,8 +43,17 @@ module AMQP
43
43
  def initialize(settings)
44
44
  @settings = settings
45
45
 
46
- super("AMQP broker closed TCP connection before authentication succeeded: this usually means authentication failure due to misconfiguration. Settings are #{settings.inspect}")
46
+ super("AMQP broker closed TCP connection before authentication succeeded: this usually means authentication failure due to misconfiguration. Settings are #{filtered_settings.inspect}")
47
47
  end # initialize(settings)
48
+
49
+ def filtered_settings
50
+ filtered_settings = settings.dup
51
+ [:pass, :password].each do |sensitve_setting|
52
+ filtered_settings[sensitve_setting] &&= '[filtered]'
53
+ end
54
+
55
+ filtered_settings
56
+ end
48
57
  end # PossibleAuthenticationFailureError
49
58
 
50
59
 
@@ -134,9 +134,9 @@ module AMQP
134
134
  # @see Channel#topic
135
135
  # @see Channel#headers
136
136
  # @see Queue
137
- # @see http://bit.ly/hw2ELX AMQP 0.9.1 specification (Section 2.1.1)
138
- # @see http://bit.ly/hw2ELX AMQP 0.9.1 specification (Section 2.1.5)
139
- # @see http://bit.ly/hw2ELX AMQP 0.9.1 specification (Section 3.1.3)
137
+ # @see http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Specification.pdf AMQP 0.9.1 specification (Section 2.1.1)
138
+ # @see http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Specification.pdf AMQP 0.9.1 specification (Section 2.1.5)
139
+ # @see http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Specification.pdf AMQP 0.9.1 specification (Section 3.1.3)
140
140
  class Exchange < AMQ::Client::Exchange
141
141
 
142
142
  #
@@ -162,7 +162,7 @@ module AMQP
162
162
  # AMQP::Exchange.default(channel).publish("make clean", routing_key => "tasks")
163
163
  #
164
164
  # @see Exchange
165
- # @see http://bit.ly/hw2ELX AMQP 0.9.1 specification (Section 2.1.2.4)
165
+ # @see http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Specification.pdf AMQP 0.9.1 specification (Section 2.1.2.4)
166
166
  # @note Do not confuse default exchange with amq.direct: amq.direct is a pre-defined direct
167
167
  # exchange that doesn't have any special routing semantics.
168
168
  # @return [Exchange] An instance that corresponds to the default exchange (of type direct).
@@ -292,7 +292,7 @@ module AMQP
292
292
  # @see Channel#topic
293
293
  # @see Channel#headers
294
294
  # @see Queue
295
- # @see http://bit.ly/hw2ELX AMQP 0.9.1 specification (Section 3.1.3)
295
+ # @see http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Specification.pdf AMQP 0.9.1 specification (Section 3.1.3)
296
296
  #
297
297
  # @return [Exchange]
298
298
  # @api public
@@ -97,7 +97,7 @@ module AMQP
97
97
  #
98
98
  # h2. Queue durability and persistence of messages.
99
99
  #
100
- # Learn more in our {file:docs/Durability.textile Durability guide}.
100
+ # Learn more in our {http://rubyamqp.info/articles/durability/}.
101
101
  #
102
102
  #
103
103
  # h2. Message ordering
@@ -112,11 +112,11 @@ module AMQP
112
112
  # Learn more in {file:docs/ErrorHandling.textile Error Handling guide}.
113
113
  #
114
114
  #
115
- # @note Please make sure you read {file:docs/Durability.textile Durability guide} that covers exchanges durability vs. messages
115
+ # @note Please make sure you read {http://rubyamqp.info/articles/durability/} that covers exchanges durability vs. messages
116
116
  # persistence.
117
117
  #
118
118
  #
119
- # @see http://bit.ly/hw2ELX AMQP 0.9.1 specification (Section 2.1.1)
119
+ # @see http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Specification.pdf AMQP 0.9.1 specification (Section 2.1.1)
120
120
  # @see AMQP::Exchange
121
121
  class Queue < AMQ::Client::Queue
122
122
 
@@ -221,7 +221,11 @@ module AMQP
221
221
  #
222
222
  # @api public
223
223
  def once_declared(&block)
224
- @declaration_deferrable.callback(&block)
224
+ @declaration_deferrable.callback do
225
+ # guards against cases when deferred operations
226
+ # don't complete before the channel is closed
227
+ block.call if @channel.open?
228
+ end
225
229
  end # once_declared(&block)
226
230
 
227
231
 
@@ -281,14 +285,8 @@ module AMQP
281
285
  # @api public
282
286
  # @see Queue#unbind
283
287
  def bind(exchange, opts = {}, &block)
284
- if self.server_named?
285
- @channel.once_open do
286
- @declaration_deferrable.callback do
287
- super(exchange, (opts[:key] || opts[:routing_key] || AMQ::Protocol::EMPTY_STRING), (opts[:nowait] || block.nil?), opts[:arguments], &block)
288
- end
289
- end
290
- else
291
- @channel.once_open do
288
+ @channel.once_open do
289
+ self.once_name_is_available do
292
290
  super(exchange, (opts[:key] || opts[:routing_key] || AMQ::Protocol::EMPTY_STRING), (opts[:nowait] || block.nil?), opts[:arguments], &block)
293
291
  end
294
292
  end
@@ -345,7 +343,8 @@ module AMQP
345
343
  # {Queue#subscribe} or {Queue#pop} call.
346
344
  #
347
345
  # @param [Exchange] Exchange to unbind from.
348
- #
346
+ # @option opts [String] :routing_key Binding routing key
347
+ # @option opts [Hash] :arguments Binding arguments
349
348
  # @option opts [Boolean] :nowait (true) If set, the server will not respond to the method. The client should
350
349
  # not wait for a reply method. If the server could not complete the
351
350
  # method it will raise a channel or connection exception.
@@ -357,7 +356,9 @@ module AMQP
357
356
  # @see Queue#bind
358
357
  def unbind(exchange, opts = {}, &block)
359
358
  @channel.once_open do
360
- super(exchange, (opts[:key] || opts[:routing_key] || AMQ::Protocol::EMPTY_STRING), opts[:arguments], &block)
359
+ self.once_name_is_available do
360
+ super(exchange, (opts[:key] || opts[:routing_key] || AMQ::Protocol::EMPTY_STRING), opts[:arguments], &block)
361
+ end
361
362
  end
362
363
  end
363
364
 
@@ -391,7 +392,9 @@ module AMQP
391
392
  # @see Queue#unbind
392
393
  def delete(opts = {}, &block)
393
394
  @channel.once_open do
394
- super(opts.fetch(:if_unused, false), opts.fetch(:if_empty, false), opts.fetch(:nowait, false), &block)
395
+ self.once_name_is_available do
396
+ super(opts.fetch(:if_unused, false), opts.fetch(:if_empty, false), opts.fetch(:nowait, false), &block)
397
+ end
395
398
  end
396
399
 
397
400
  # backwards compatibility
@@ -416,7 +419,9 @@ module AMQP
416
419
  # @see Queue#unbind
417
420
  def purge(opts = {}, &block)
418
421
  @channel.once_open do
419
- super(opts.fetch(:nowait, false), &block)
422
+ self.once_declared do
423
+ super(opts.fetch(:nowait, false), &block)
424
+ end
420
425
  end
421
426
 
422
427
  # backwards compatibility
@@ -477,11 +482,17 @@ module AMQP
477
482
  }
478
483
 
479
484
  @channel.once_open do
480
- # see AMQ::Client::Queue#get in amq-client
481
- self.get(!opts.fetch(:ack, false), &shim)
485
+ self.once_name_is_available do
486
+ # see AMQ::Client::Queue#get in amq-client
487
+ self.get(!opts.fetch(:ack, false), &shim)
488
+ end
482
489
  end
483
490
  else
484
- @channel.once_open { self.get(!opts.fetch(:ack, false)) }
491
+ @channel.once_open do
492
+ self.once_name_is_available do
493
+ self.get(!opts.fetch(:ack, false))
494
+ end
495
+ end
485
496
  end
486
497
  end
487
498
 
@@ -719,7 +730,9 @@ module AMQP
719
730
  opts[:nowait] = false if (@on_confirm_subscribe = opts[:confirm])
720
731
 
721
732
  @channel.once_open do
722
- self.once_declared do
733
+ self.once_name_is_available do
734
+ # guards against a pathological case race condition when a channel
735
+ # is opened and closed before delayed operations are completed.
723
736
  self.consume(!opts[:ack], opts[:exclusive], (opts[:nowait] || block.nil?), opts[:no_local], nil, &opts[:confirm])
724
737
 
725
738
  self.on_delivery(&block)
@@ -785,7 +798,7 @@ module AMQP
785
798
  # @api public
786
799
  def unsubscribe(opts = {}, &block)
787
800
  @channel.once_open do
788
- self.once_declared do
801
+ self.once_name_is_available do
789
802
  if @default_consumer
790
803
  @default_consumer.cancel(opts.fetch(:nowait, true), &block); @default_consumer = nil
791
804
  end
@@ -812,12 +825,14 @@ module AMQP
812
825
  shim = Proc.new { |q, declare_ok| block.call(declare_ok.message_count, declare_ok.consumer_count) }
813
826
 
814
827
  @channel.once_open do
815
- # we do not use self.declare here to avoid caching of @passive since that will cause unexpected side-effects during automatic
816
- # recovery process. MK.
817
- @connection.send_frame(AMQ::Protocol::Queue::Declare.encode(@channel.id, @name, true, @opts[:durable], @opts[:exclusive], @opts[:auto_delete], false, @opts[:arguments]))
828
+ self.once_name_is_available do
829
+ # we do not use self.declare here to avoid caching of @passive since that will cause unexpected side-effects during automatic
830
+ # recovery process. MK.
831
+ @connection.send_frame(AMQ::Protocol::Queue::Declare.encode(@channel.id, @name, true, @opts[:durable], @opts[:exclusive], @opts[:auto_delete], false, @opts[:arguments]))
818
832
 
819
- self.append_callback(:declare, &shim)
820
- @channel.queues_awaiting_declare_ok.push(self)
833
+ self.append_callback(:declare, &shim)
834
+ @channel.queues_awaiting_declare_ok.push(self)
835
+ end
821
836
  end
822
837
 
823
838
  self
@@ -883,6 +898,16 @@ module AMQP
883
898
  { :queue => name, :nowait => (block.nil? && !name.empty?) }.merge(opts)
884
899
  end
885
900
 
901
+ def once_name_is_available(&block)
902
+ if server_named?
903
+ self.once_declared do
904
+ block.call
905
+ end
906
+ else
907
+ block.call
908
+ end
909
+ end
910
+
886
911
  private
887
912
 
888
913
  # Default direct exchange that we use to publish messages directly to this queue.
@@ -110,7 +110,7 @@ module AMQP
110
110
 
111
111
 
112
112
  # Properly close connection with AMQ broker, as described in
113
- # section 2.2.4 of the {http://bit.ly/hw2ELX AMQP 0.9.1 specification}.
113
+ # section 2.2.4 of the {http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Specification.pdf AMQP 0.9.1 specification}.
114
114
  #
115
115
  # @api plugin
116
116
  # @see #close_connection
@@ -129,19 +129,19 @@ module AMQP
129
129
  # Server properties (product information, platform, et cetera)
130
130
  #
131
131
  # @return [Hash]
132
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.1.3)
132
+ # @see http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Reference.pdf AMQP 0.9.1 protocol documentation (Section 1.4.2.1.3)
133
133
  attr_reader :server_properties
134
134
 
135
135
  # Server capabilities (usually used to detect AMQP 0.9.1 extensions like basic.nack, publisher
136
136
  # confirms and so on)
137
137
  #
138
138
  # @return [Hash]
139
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.1.3)
139
+ # @see http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Reference.pdf AMQP 0.9.1 protocol documentation (Section 1.4.2.1.3)
140
140
  attr_reader :server_capabilities
141
141
 
142
142
  # Locales server supports
143
143
  #
144
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.1.3)
144
+ # @see http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Reference.pdf AMQP 0.9.1 protocol documentation (Section 1.4.2.1.3)
145
145
  attr_reader :server_locales
146
146
 
147
147
  # @return [AMQP::Broker] Broker this connection is established with
@@ -186,7 +186,7 @@ module AMQP
186
186
  super(&block)
187
187
  end
188
188
 
189
- # Defines a callback that will be run when initial TCP connection fails.
189
+ # Defines a callback that will be run when TCP connection to AMQP broker is lost (interrupted).
190
190
  # You can define only one callback.
191
191
  #
192
192
  # @api public
@@ -6,5 +6,5 @@ module AMQP
6
6
  #
7
7
  # @see AMQ::Protocol::VERSION
8
8
  # @return [String] AMQP gem version
9
- VERSION = '1.0.0.pre2'
9
+ VERSION = '1.0.0'
10
10
  end
@@ -24,9 +24,7 @@ describe AMQP::Queue, "#pop" do
24
24
  @exchange = @channel.fanout("amqpgem.integration.basic.get.queue", :auto_delete => true)
25
25
  @queue = @channel.queue(@queue_name, :auto_delete => true)
26
26
 
27
- @queue.bind(@exchange) do
28
- puts "Bound #{@exchange.name} => #{@queue.name}"
29
- end
27
+ @queue.bind(@exchange)
30
28
 
31
29
  @dispatched_data = "fetch me synchronously"
32
30
  end
@@ -61,36 +59,93 @@ describe AMQP::Queue, "#pop" do
61
59
 
62
60
  context "when THERE ARE messages in the queue" do
63
61
  it "yields message payload to the callback" do
64
- number_of_received_messages = 0
65
- expected_number_of_messages = 300
66
-
67
- expected_number_of_messages.times do |i|
68
- @exchange.publish(@dispatched_data + "_#{i}", :key => @queue_name)
69
- end
62
+ @channel.default_exchange.publish(@dispatched_data, :routing_key => @queue.name)
70
63
 
71
- @queue.status do |number_of_messages, number_of_consumers|
72
- expected_number_of_messages.times do
73
- @queue.pop do |headers, payload|
74
- payload.should_not be_nil
75
- number_of_received_messages += 1
76
- headers.message_count.should == (expected_number_of_messages - number_of_received_messages)
77
-
78
- if RUBY_VERSION =~ /^1.9/
79
- payload.force_encoding("UTF-8").should =~ /#{@dispatched_data}/
80
- else
81
- payload.should =~ /#{@dispatched_data}/
82
- end
83
- end # pop
84
- end # do
64
+ @queue.pop do |headers, payload|
65
+ payload.should == @dispatched_data
85
66
  end
86
67
 
87
- delayed(1.3) {
68
+ delayed(0.5) {
88
69
  # Queue.Get doesn't qualify for subscription, hence, manual deletion is required
89
70
  @queue.delete
90
71
  }
91
- done(2.5) {
92
- number_of_received_messages.should == expected_number_of_messages
93
- }
72
+ done(0.8)
94
73
  end # it
95
74
  end # context
75
+
76
+
77
+ context "with manual acknowledgements" do
78
+ default_timeout 4
79
+
80
+ let(:queue_name) { "amqpgem.integration.basic.get.acks.manual#{rand}" }
81
+
82
+ it "does not remove messages from the queue unless ack-ed" do
83
+ ch1 = AMQP::Channel.new
84
+ ch2 = AMQP::Channel.new
85
+
86
+ ch1.on_error do |ch, close_ok|
87
+ puts "Channel error: #{close_ok.reply_code} #{close_ok.reply_text}"
88
+ end
89
+
90
+ q = ch1.queue(queue_name, :exclusive => true)
91
+ x = ch1.default_exchange
92
+
93
+ q.purge
94
+ delayed(0.2) { x.publish(@dispatched_data, :routing_key => q.name) }
95
+
96
+ delayed(0.5) {
97
+ q.pop(:ack => true) do |meta, payload|
98
+ # never ack
99
+ end
100
+
101
+ ch1.close
102
+
103
+ EventMachine.add_timer(0.7) {
104
+ ch2.queue(queue_name, :exclusive => true).status do |number_of_messages, number_of_consumers|
105
+ number_of_messages.should == 1
106
+ done
107
+ end
108
+ }
109
+ }
110
+ end
111
+ end
112
+
113
+
114
+
115
+ context "with automatic acknowledgements" do
116
+ default_timeout 4
117
+
118
+ let(:queue_name) { "amqpgem.integration.basic.get.acks.automatic#{rand}" }
119
+
120
+ it "does remove messages from the queue after delivery" do
121
+ ch1 = AMQP::Channel.new
122
+ ch2 = AMQP::Channel.new
123
+
124
+ ch1.on_error do |ch, close_ok|
125
+ puts "Channel error: #{close_ok.reply_code} #{close_ok.reply_text}"
126
+ end
127
+
128
+ q = ch1.queue(queue_name, :exclusive => true)
129
+ x = ch1.default_exchange
130
+
131
+ q.purge
132
+ x.publish(@dispatched_data, :routing_key => q.name)
133
+
134
+ delayed(0.5) {
135
+ q.pop(:ack => false) do |meta, payload|
136
+ # never ack
137
+ end
138
+
139
+ ch1.close
140
+
141
+ EventMachine.add_timer(0.5) {
142
+ ch2.queue(queue_name, :exclusive => true).status do |number_of_messages, number_of_consumers|
143
+ number_of_messages.should == 0
144
+ done
145
+ end
146
+ }
147
+ }
148
+ end
149
+ end
150
+
96
151
  end # describe