amqp 0.9.10 → 1.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/.travis.yml +0 -3
  2. data/CHANGELOG +4 -0
  3. data/Gemfile +1 -0
  4. data/README.md +72 -81
  5. data/amqp.gemspec +14 -5
  6. data/docs/08Migration.textile +0 -4
  7. data/docs/AMQP091ModelExplained.textile +0 -5
  8. data/docs/Bindings.textile +0 -4
  9. data/docs/Clustering.textile +0 -4
  10. data/docs/ConnectingToTheBroker.textile +1 -5
  11. data/docs/ConnectionEncryptionWithTLS.textile +0 -4
  12. data/docs/DocumentationGuidesIndex.textile +0 -4
  13. data/docs/Durability.textile +0 -4
  14. data/docs/ErrorHandling.textile +40 -106
  15. data/docs/Exchanges.textile +0 -4
  16. data/docs/GettingStarted.textile +6 -10
  17. data/docs/PatternsAndUseCases.textile +1 -4
  18. data/docs/Queues.textile +0 -4
  19. data/docs/RabbitMQVersions.textile +0 -4
  20. data/docs/RunningTests.textile +0 -4
  21. data/docs/TestingWithEventedSpec.textile +0 -4
  22. data/docs/Troubleshooting.textile +0 -4
  23. data/docs/VendorSpecificExtensions.textile +0 -4
  24. data/examples/error_handling/hello_world_producer.rb +1 -1
  25. data/examples/issues/issue_121.rb +23 -0
  26. data/examples/patterns/request_reply/client.rb +2 -1
  27. data/examples/patterns/request_reply/server.rb +1 -0
  28. data/examples/publishing/returned_messages.rb +1 -1
  29. data/lib/amqp.rb +0 -7
  30. data/lib/amqp/channel.rb +15 -33
  31. data/lib/amqp/client.rb +2 -2
  32. data/lib/amqp/compatibility/ruby187_patchlevel_check.rb +4 -4
  33. data/lib/amqp/connection.rb +0 -1
  34. data/lib/amqp/consumer.rb +2 -2
  35. data/lib/amqp/exceptions.rb +1 -10
  36. data/lib/amqp/exchange.rb +5 -5
  37. data/lib/amqp/queue.rb +23 -47
  38. data/lib/amqp/session.rb +4 -4
  39. data/lib/amqp/version.rb +1 -1
  40. data/spec/integration/basic_get_spec.rb +24 -80
  41. data/spec/integration/basic_return_spec.rb +3 -3
  42. data/spec/integration/channel_level_exception_with_multiple_channels_spec.rb +1 -0
  43. data/spec/integration/exchange_declaration_spec.rb +102 -71
  44. data/spec/integration/extensions/rabbitmq/publisher_confirmations_spec.rb +17 -1
  45. data/spec/integration/fanout_exchange_routing_spec.rb +1 -1
  46. data/spec/integration/immediate_messages_spec.rb +59 -0
  47. data/spec/integration/multiple_consumers_per_queue_spec.rb +101 -39
  48. data/spec/integration/queue_redeclaration_with_incompatible_attributes_spec.rb +12 -25
  49. data/spec/integration/regressions/concurrent_publishing_on_the_same_channel_spec.rb +1 -1
  50. data/spec/integration/reply_queue_communication_spec.rb +2 -1
  51. data/spec/integration/store_and_forward_spec.rb +9 -6
  52. data/spec/integration/topic_subscription_spec.rb +4 -5
  53. data/spec/spec_helper.rb +2 -8
  54. data/spec/unit/amqp/connection_spec.rb +1 -3
  55. metadata +112 -116
  56. data/examples/deprecated/default_thread_local_channel_instance.rb +0 -34
  57. data/examples/legacy/ack.rb +0 -70
  58. data/examples/legacy/callbacks.rb +0 -45
  59. data/examples/legacy/clock.rb +0 -74
  60. data/examples/legacy/hashtable.rb +0 -60
  61. data/examples/legacy/logger.rb +0 -92
  62. data/examples/legacy/multiclock.rb +0 -56
  63. data/examples/legacy/pingpong.rb +0 -51
  64. data/examples/legacy/primes-simple.rb +0 -29
  65. data/examples/legacy/primes.rb +0 -74
  66. data/examples/legacy/stocks.rb +0 -59
  67. data/lib/amqp/deprecated/fork.rb +0 -17
  68. data/lib/amqp/deprecated/logger.rb +0 -100
  69. data/lib/amqp/deprecated/mq.rb +0 -22
  70. data/lib/amqp/deprecated/rpc.rb +0 -169
  71. data/lib/amqp/ext/em.rb +0 -3
  72. data/lib/amqp/ext/emfork.rb +0 -72
  73. data/lib/amqp/logger.rb +0 -19
  74. data/lib/amqp/rpc.rb +0 -20
  75. data/lib/mq.rb +0 -35
  76. data/lib/mq/logger.rb +0 -4
  77. data/lib/mq/rpc.rb +0 -4
  78. data/spec/integration/remove_individual_binding_spec.rb +0 -51
@@ -67,6 +67,22 @@ describe "Publisher confirmation(s)" do
67
67
  @channel2 = AMQP::Channel.new
68
68
  end
69
69
 
70
+ it 'should increment publisher_index confirming channel' do
71
+ channel3 = AMQP::Channel.new
72
+ exchange = channel3.fanout("amqpgem.tests.fanout0", :auto_delete => true)
73
+
74
+ channel3.confirm_select
75
+ channel3.publisher_index.should == 0
76
+
77
+ EventMachine.add_timer(0.5) do
78
+ exchange.publish("Hi")
79
+ end
80
+
81
+ done(2.0) do
82
+ channel3.publisher_index.should == 1
83
+ end
84
+ end
85
+
70
86
 
71
87
  context "when messages are transient" do
72
88
  context "and routable" do
@@ -116,7 +132,7 @@ describe "Publisher confirmation(s)" do
116
132
  end
117
133
 
118
134
  EventMachine.add_timer(0.5) do
119
- exchange.publish("Hi", :persistent => false)
135
+ exchange.publish("Hi", :persistent => false, :immediately => true)
120
136
  end
121
137
 
122
138
  done(2.0) do
@@ -77,7 +77,7 @@ describe AMQP::Exchange, "of type fanout" do
77
77
  end
78
78
 
79
79
  # for Rubinius, it is surprisingly slow on this workload
80
- done(1.5) {
80
+ done(2.5) {
81
81
  [@queue1, @queue2, @queue3].each do |q|
82
82
  @received_messages[q.name].size.should == @expected_number_of_messages[q.name]
83
83
 
@@ -0,0 +1,59 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+
5
+ describe "When queue has no consumers" do
6
+
7
+ #
8
+ # Environment
9
+ #
10
+
11
+ include EventedSpec::AMQPSpec
12
+ default_timeout 1.5
13
+
14
+ amqp_before do
15
+ @producer_channel = AMQP::Channel.new
16
+ @consumer_channel = AMQP::Channel.new
17
+ end
18
+
19
+ # ...
20
+
21
+
22
+ #
23
+ # Examples
24
+ #
25
+
26
+ context "and message is published as :immediate" do
27
+ it "that message is returned to the publisher" do
28
+ exchange = @producer_channel.fanout("amq.fanout")
29
+ queue = @consumer_channel.queue("", :exclusive => true)
30
+
31
+ exchange.on_return do |basic_return, metadata, payload|
32
+ done if payload == "immediate message body"
33
+ end
34
+
35
+ queue.bind(exchange) do
36
+ exchange.publish "immediate message body", :immediate => true
37
+ end
38
+ end
39
+ end
40
+
41
+
42
+
43
+ context "and message is published as non :immediate" do
44
+ it "that message is dropped" do
45
+ exchange = @producer_channel.fanout("amq.fanout")
46
+ queue = @consumer_channel.queue("", :exclusive => true)
47
+
48
+ exchange.on_return do |basic_return, metadata, payload|
49
+ fail "Should not happen"
50
+ end
51
+
52
+ queue.bind(exchange) do
53
+ exchange.publish "non-immediate message body", :immediate => false
54
+ end
55
+
56
+ done(1.0)
57
+ end
58
+ end
59
+ end # describe
@@ -58,7 +58,7 @@ describe "Multiple non-exclusive consumers per queue" do
58
58
 
59
59
  EventMachine.add_timer(1.0) do
60
60
  messages.each do |message|
61
- exchange.publish(message, :mandatory => true, :routing_key => queue.name)
61
+ exchange.publish(message, :immediate => true, :mandatory => true, :routing_key => queue.name)
62
62
  end
63
63
  end
64
64
 
@@ -104,7 +104,7 @@ describe "Multiple non-exclusive consumers per queue" do
104
104
 
105
105
  EventMachine.add_timer(1.0) do
106
106
  messages.each do |message|
107
- exchange.publish(message, :mandatory => true, :routing_key => queue.name)
107
+ exchange.publish(message, :immediate => true, :mandatory => true, :routing_key => queue.name)
108
108
  end
109
109
  end
110
110
 
@@ -150,7 +150,7 @@ describe "Multiple non-exclusive consumers per queue" do
150
150
 
151
151
  EventMachine.add_timer(1.0) do
152
152
  messages.each do |message|
153
- exchange.publish(message, :mandatory => true, :routing_key => queue.name)
153
+ exchange.publish(message, :immediate => true, :mandatory => true, :routing_key => queue.name)
154
154
  end
155
155
  end
156
156
 
@@ -199,7 +199,7 @@ describe "Multiple non-exclusive consumers per queue" do
199
199
 
200
200
  EventMachine.add_timer(1.0) do
201
201
  messages.each do |message|
202
- exchange.publish(message, :mandatory => true, :routing_key => queue.name)
202
+ exchange.publish(message, :immediate => true, :mandatory => true, :routing_key => queue.name)
203
203
  end
204
204
  end
205
205
 
@@ -213,47 +213,109 @@ describe "Multiple non-exclusive consumers per queue" do
213
213
 
214
214
 
215
215
 
216
- context "with equal prefetch levels, a server-named queue and two consumers cancelled mid-flight" do
217
- it "have messages distributed to the only active consumer" do
218
- channel = AMQP::Channel.new
219
- channel.on_error do |ch, channel_close|
220
- raise(channel_close.reply_text)
221
- end
216
+ unless ENV["CI"]
217
+ context "with equal prefetch levels, a server-named queue and two consumers cancelled mid-flight" do
218
+ it "have messages distributed to the only active consumer" do
219
+ channel = AMQP::Channel.new
220
+ channel.on_error do |ch, channel_close|
221
+ raise(channel_close.reply_text)
222
+ end
222
223
 
223
- queue = channel.queue("", :auto_delete => true)
224
- consumer1 = AMQP::Consumer.new(channel, queue)
225
- consumer2 = AMQP::Consumer.new(channel, queue)
224
+ queue = channel.queue("", :auto_delete => true)
225
+ consumer1 = AMQP::Consumer.new(channel, queue)
226
+ consumer2 = AMQP::Consumer.new(channel, queue)
226
227
 
227
- consumer1.consume.on_delivery do |basic_deliver, metadata, payload|
228
- @consumer1_mailbox << payload
229
- end
228
+ consumer1.consume.on_delivery do |basic_deliver, metadata, payload|
229
+ @consumer1_mailbox << payload
230
+ end
230
231
 
231
- consumer2.consume(true).on_delivery do |metadata, payload|
232
- @consumer2_mailbox << payload
233
- end
234
- queue.subscribe do |metadata, payload|
235
- @consumer3_mailbox << payload
236
- end
237
- queue.unsubscribe
238
- consumer2.cancel
232
+ consumer2.consume(true).on_delivery do |metadata, payload|
233
+ @consumer2_mailbox << payload
234
+ end
235
+ queue.subscribe do |metadata, payload|
236
+ @consumer3_mailbox << payload
237
+ end
238
+ queue.unsubscribe
239
+ consumer2.cancel
239
240
 
240
241
 
241
- exchange = channel.default_exchange
242
- exchange.on_return do |basic_return, metadata, payload|
243
- raise(basic_return.reply_text)
244
- end
242
+ exchange = channel.default_exchange
243
+ exchange.on_return do |basic_return, metadata, payload|
244
+ raise(basic_return.reply_text)
245
+ end
245
246
 
246
- EventMachine.add_timer(1.0) do
247
- messages.each do |message|
248
- exchange.publish(message, :mandatory => true, :routing_key => queue.name)
247
+ EventMachine.add_timer(1.0) do
248
+ messages.each do |message|
249
+ exchange.publish(message, :immediate => true, :mandatory => true, :routing_key => queue.name)
250
+ end
249
251
  end
250
- end
251
252
 
252
- done(5.0) {
253
- @consumer1_mailbox.size.should == 100
254
- @consumer2_mailbox.size.should == 0
255
- @consumer3_mailbox.size.should == 0
256
- }
257
- end # it
258
- end # context
253
+ done(5.0) {
254
+ @consumer1_mailbox.size.should == 100
255
+ @consumer2_mailbox.size.should == 0
256
+ @consumer3_mailbox.size.should == 0
257
+ }
258
+ end # it
259
+ end # context
260
+
261
+
262
+
263
+ context "with equal prefetch levels and ALL consumers cancelled mid-flight" do
264
+ it "returns all immediate messages" do
265
+ @returned_messages = []
266
+
267
+ channel = AMQP::Channel.new
268
+ channel.on_error do |ch, channel_close|
269
+ raise(channel_close.reply_text)
270
+ end
271
+
272
+ queue = channel.queue("amqpgem.integration.roundrobin.queue1", :auto_delete => true) do
273
+ consumer1 = AMQP::Consumer.new(channel, queue)
274
+ consumer2 = AMQP::Consumer.new(channel, queue, "#{queue.name}-consumer-#{rand}-#{Time.now}", false, true)
275
+
276
+ consumer1.consume.on_delivery do |basic_deliver, metadata, payload|
277
+ @consumer1_mailbox << payload
278
+ end
279
+
280
+ consumer2.consume(true).on_delivery do |metadata, payload|
281
+ @consumer2_mailbox << payload
282
+ end
283
+
284
+ queue.subscribe do |metadata, payload|
285
+ @consumer3_mailbox << payload
286
+ end
287
+ queue.should be_subscribed
288
+ queue.unsubscribe
289
+ queue.should_not be_subscribed
290
+
291
+ consumer2.should be_subscribed
292
+ consumer2.callback.should_not be_nil
293
+ consumer2.cancel
294
+ consumer2.should_not be_subscribed
295
+ consumer2.callback.should be_nil
296
+
297
+ consumer1.should be_subscribed
298
+ consumer1.callback.should_not be_nil
299
+ consumer1.cancel
300
+ consumer1.should_not be_subscribed
301
+ consumer1.callback.should be_nil
302
+ end
303
+
304
+ exchange = channel.default_exchange
305
+ exchange.on_return do |basic_return, metadata, payload|
306
+ @returned_messages << payload
307
+ end
308
+
309
+ EventMachine.add_timer(1.0) do
310
+ messages.each do |message|
311
+ exchange.publish(message, :immediate => true, :mandatory => true, :routing_key => queue.name)
312
+ end
313
+ end
314
+
315
+ done(6.0) {
316
+ @returned_messages.size.should == 100
317
+ }
318
+ end # it
319
+ end # context
320
+ end
259
321
  end # describe
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe "AMQP queue redeclaration with different attributes" do
5
+ describe AMQP do
6
6
 
7
7
  #
8
8
  # Environment
@@ -17,7 +17,7 @@ describe "AMQP queue redeclaration with different attributes" do
17
17
  # Examples
18
18
  #
19
19
 
20
- context "when :durable value is different" do
20
+ context "when queue is redeclared with different attributes" do
21
21
  let(:name) { "amqp-gem.nondurable.queue" }
22
22
  let(:options) {
23
23
  { :durable => false, :exclusive => true, :auto_delete => true, :arguments => {}, :passive => false }
@@ -25,48 +25,35 @@ describe "AMQP queue redeclaration with different attributes" do
25
25
  let(:different_options) {
26
26
  { :durable => true, :exclusive => true, :auto_delete => true, :arguments => {}, :passive => false}
27
27
  }
28
+ let(:irrelevant_different_options) {
29
+ { :durable => false, :exclusive => true, :auto_delete => true, :arguments => {}, :passive => false, :header => {:random => 'stuff' } }
30
+ }
28
31
 
29
32
 
30
33
  it "should raise AMQP::IncompatibleOptionsError for incompatable options" do
31
34
  channel = AMQP::Channel.new
32
- channel.on_error do |ch, channel_close|
33
- @error_code = channel_close.reply_code
35
+ channel.on_error do |ch, close|
36
+ @callback_fired = true
34
37
  end
35
38
 
36
39
  channel.queue(name, options)
37
40
  expect {
38
41
  channel.queue(name, different_options)
39
42
  }.to raise_error(AMQP::IncompatibleOptionsError)
40
-
41
- done(0.5) {
42
- @error_code.should == 406
43
- }
43
+ done
44
44
  end
45
- end
46
-
47
- context "when :headers are different" do
48
- let(:name) { "amqp-gem.nondurable.queue" }
49
- let(:options) {
50
- { :durable => false, :exclusive => true, :auto_delete => true, :arguments => {}, :passive => false }
51
- }
52
- let(:different_options) {
53
- { :durable => false, :exclusive => true, :auto_delete => true, :arguments => {}, :passive => false, :header => {:random => 'stuff' } }
54
- }
55
45
 
56
46
  it "should not raise AMQP::IncompatibleOptionsError for irrelevant options" do
57
47
  channel = AMQP::Channel.new
58
- channel.on_error do |ch, channel_close|
59
- @error_code = channel_close.reply_code
48
+ channel.on_error do |ch, close|
49
+ @callback_fired = true
60
50
  end
61
51
 
62
52
  channel.queue(name, options)
63
53
  expect {
64
- channel.queue(name, different_options)
54
+ channel.queue(name, irrelevant_different_options)
65
55
  }.to_not raise_error(AMQP::IncompatibleOptionsError)
66
-
67
- done(0.5) {
68
- @error_code.should == 406
69
- }
56
+ done
70
57
  end
71
58
  end
72
59
  end # describe AMQP
@@ -73,7 +73,7 @@ if mri?
73
73
  20.times do
74
74
  Thread.new do
75
75
  messages.each do |message|
76
- exchange.publish(message, :routing_key => queue.name, :mandatory => true)
76
+ exchange.publish(message, :routing_key => queue.name, :immediate => true, :mandatory => true)
77
77
  end
78
78
  end
79
79
  end
@@ -53,7 +53,8 @@ describe "Exclusive server-named queue" do
53
53
  :reply_to => queue2.name,
54
54
  :app_id => "Client",
55
55
  :timestamp => request_timestamp,
56
- :mandatory => true)
56
+ :mandatory => true,
57
+ :immediate => true)
57
58
 
58
59
  done(0.2) {
59
60
  queue1.unsubscribe
@@ -53,16 +53,19 @@ describe "Store-and-forward routing" do
53
53
  @queue.subscribe(:ack => false) do |payload|
54
54
  payload.should_not be_nil
55
55
  number_of_received_messages += 1
56
- payload.should == dispatched_data
56
+ if RUBY_VERSION =~ /^1.9/
57
+ payload.force_encoding("UTF-8").should == dispatched_data
58
+ else
59
+ payload.should == dispatched_data
60
+ end
57
61
  end # subscribe
58
62
 
59
- delayed(0.3) do
60
- expected_number_of_messages.times do
61
- @exchange.publish(dispatched_data, :routing_key => @queue_name)
62
- end
63
+ expected_number_of_messages.times do
64
+ @exchange.publish(dispatched_data, :routing_key => @queue_name)
63
65
  end
64
66
 
65
- done(4.0) {
67
+ # 6 seconds are for Rubinius, it is surprisingly slow on this workload
68
+ done(6.0) {
66
69
  number_of_received_messages.should == expected_number_of_messages
67
70
  @queue.unsubscribe
68
71
  }
@@ -66,9 +66,9 @@ describe "Topic-based subscription" do
66
66
  # publish some messages none of our queues should be receiving
67
67
  3.times do
68
68
  @exchange.publish(626 + rand(1000)/400.0, :key => "nasdaq.goog")
69
- end
69
+ end # do
70
70
 
71
- done(0.5) {
71
+ done(0.4) {
72
72
  received_messages.should == expected_messages
73
73
  @aapl_queue.unsubscribe
74
74
  @amzn_queue.unsubscribe
@@ -117,7 +117,7 @@ describe "Topic-based subscription" do
117
117
  @exchange.publish("Blatche, Wall lead Wizards over Jazz 108-101", :key => "sports.nba.jazz")
118
118
  @exchange.publish("Deron Williams Receives NBA Cares Community Assist Award", :key => "sports.nba.jazz")
119
119
 
120
- done(0.6) {
120
+ done(0.2) {
121
121
  received_messages.should == expected_messages
122
122
 
123
123
  @nba_queue.unsubscribe
@@ -151,7 +151,6 @@ describe "Topic-based subscription" do
151
151
  @celtics_queue.name => 3
152
152
  }
153
153
 
154
-
155
154
  @sports_queue.bind(@exchange, :key => "sports.#").subscribe do |payload|
156
155
  received_messages[@sports_queue.name] += 1
157
156
  end
@@ -181,7 +180,7 @@ describe "Topic-based subscription" do
181
180
  @exchange.publish("Philadelphia's Daniel Briere has been named as an All-Star replacement for Jarome Iginla.", :key => "sports.nhl.allstargame")
182
181
  @exchange.publish("Devils blank Sid- and Malkin-less Penguins 2-0", :key => "sports.nhl.penguins")
183
182
 
184
- done(0.5) {
183
+ done(0.2) {
185
184
  received_messages.should == expected_messages
186
185
 
187
186
  @sports_queue.unsubscribe
@@ -15,12 +15,6 @@ puts "Using Ruby #{RUBY_VERSION}, amq-client #{AMQ::Client::VERSION} and amq-pro
15
15
 
16
16
  amqp_config = File.dirname(__FILE__) + '/amqp.yml'
17
17
 
18
- port = if ENV["TRACER"]
19
- 5673
20
- else
21
- 5672
22
- end
23
-
24
18
  if File.exists? amqp_config
25
19
  class Hash
26
20
  def symbolize_keys
@@ -34,7 +28,7 @@ if File.exists? amqp_config
34
28
  end
35
29
  AMQP_OPTS = YAML::load_file(amqp_config).symbolize_keys[:test]
36
30
  else
37
- AMQP_OPTS = {:host => 'localhost', :port => port}
31
+ AMQP_OPTS = {:host => 'localhost', :port => 5672}
38
32
  end
39
33
 
40
34
  # puts "AMQP_OPTS = #{AMQP_OPTS.inspect}"
@@ -88,4 +82,4 @@ module PlatformDetection
88
82
  def rubinius?
89
83
  defined?(RUBY_ENGINE) && (RUBY_ENGINE == 'rbx')
90
84
  end
91
- end
85
+ end