amqp 1.0.0.pre2 → 1.0.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.
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