amqp 0.8.0.rc13 → 0.8.0.rc14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. data/.rspec +2 -1
  2. data/.travis.yml +8 -2
  3. data/.yardopts +1 -0
  4. data/CHANGELOG +9 -0
  5. data/Gemfile +17 -11
  6. data/README.md +26 -16
  7. data/amqp.gemspec +2 -2
  8. data/bin/ci/before_build.sh +21 -0
  9. data/docs/08Migration.textile +199 -5
  10. data/docs/AMQP091ModelExplained.textile +322 -0
  11. data/docs/Bindings.textile +24 -4
  12. data/docs/Clustering.textile +1 -1
  13. data/docs/ConnectingToTheBroker.textile +98 -82
  14. data/docs/ConnectionEncryptionWithTLS.textile +65 -5
  15. data/docs/DocumentationGuidesIndex.textile +93 -13
  16. data/docs/Durability.textile +1 -1
  17. data/docs/ErrorHandling.textile +458 -94
  18. data/docs/Exchanges.textile +901 -87
  19. data/docs/GettingStarted.textile +278 -143
  20. data/docs/PatternsAndUseCases.textile +420 -0
  21. data/docs/Queues.textile +730 -178
  22. data/docs/RabbitMQVersions.textile +18 -3
  23. data/docs/RunningTests.textile +1 -1
  24. data/docs/TestingWithEventedSpec.textile +121 -0
  25. data/docs/Troubleshooting.textile +15 -1
  26. data/docs/VendorSpecificExtensions.textile +1 -1
  27. data/docs/diagrams/001_hello_world_example_routing.png +0 -0
  28. data/docs/diagrams/002_blabbr_example_routing.png +0 -0
  29. data/docs/diagrams/003_weathr_example_routing.png +0 -0
  30. data/docs/diagrams/004_fanout_exchange.png +0 -0
  31. data/docs/diagrams/005_direct_exchange.png +0 -0
  32. data/docs/diagrams/redhat/direct_exchange.png +0 -0
  33. data/docs/diagrams/redhat/fanout_exchange.png +0 -0
  34. data/docs/diagrams/redhat/topic_exchange.png +0 -0
  35. data/examples/error_handling/automatic_recovery_of_channel_and_queues.rb +50 -0
  36. data/examples/error_handling/automatically_recovering_hello_world_consumer.rb +51 -0
  37. data/examples/error_handling/automatically_recovering_hello_world_consumer_that_uses_a_server_named_queue.rb +51 -0
  38. data/examples/error_handling/basic_connection_failover.rb +22 -0
  39. data/examples/error_handling/channel_level_exception.rb +9 -2
  40. data/examples/error_handling/connection_level_exception.rb +8 -1
  41. data/examples/error_handling/connection_level_exception_with_objects.rb +49 -0
  42. data/examples/error_handling/connection_loss_handler.rb +1 -5
  43. data/examples/error_handling/hello_world_producer.rb +43 -0
  44. data/examples/error_handling/insufficient_permissions.rb +54 -0
  45. data/examples/error_handling/manual_connection_and_channel_recovery.rb +71 -0
  46. data/examples/error_handling/queue_exclusivity_violation.rb +41 -0
  47. data/examples/error_handling/queue_name_violation.rb +31 -0
  48. data/examples/exchanges/autodeletion_of_exchanges.rb +1 -4
  49. data/examples/guides/queues/01a_declaring_a_server_named_queue_using_queue_constructor.rb +7 -8
  50. data/examples/guides/queues/01b_declaring_a_queue_using_queue_constructor.rb +7 -8
  51. data/examples/guides/queues/02a_declaring_a_durable_shared_queue.rb +5 -8
  52. data/examples/guides/queues/02b_declaring_a_durable_shared_queue.rb +5 -8
  53. data/examples/guides/queues/03a_declaring_a_temporary_exclusive_queue.rb +7 -8
  54. data/examples/guides/queues/04_bind_a_queue_using_exchange_instance.rb +9 -10
  55. data/examples/guides/queues/05_bind_a_queue_using_exchange_name.rb +8 -10
  56. data/examples/guides/queues/06_subscribe_to_receive_messages.rb +10 -12
  57. data/examples/guides/queues/07_fetch_a_message_from_the_queue.rb +14 -14
  58. data/examples/guides/queues/08_unsubscribing_a_consumer.rb +13 -16
  59. data/examples/guides/queues/09_unbinding_from_exchange.rb +16 -22
  60. data/examples/guides/queues/10_purge_a_queue.rb +13 -18
  61. data/examples/guides/queues/11_deleting_a_queue.rb +14 -19
  62. data/examples/guides/queues/12_objects_that_consume_messages.rb +69 -0
  63. data/examples/guides/queues/13_objects_that_consume_messages_take_two.rb +89 -0
  64. data/examples/hello_world.rb +1 -3
  65. data/examples/hello_world_with_an_empty_string.rb +5 -6
  66. data/examples/inspecting_server_information.rb +45 -0
  67. data/examples/issues/issue_93.rb +23 -0
  68. data/examples/issues/issue_94.rb +23 -0
  69. data/examples/patterns/command/consumer.rb +45 -0
  70. data/examples/patterns/command/producer.rb +26 -0
  71. data/examples/patterns/request_reply/client.rb +29 -0
  72. data/examples/patterns/request_reply/server.rb +26 -0
  73. data/examples/publishing/publishing_a_one_off_message.rb +6 -4
  74. data/examples/publishing/returned_messages.rb +2 -10
  75. data/examples/queues/accessing_message_metadata.rb +15 -13
  76. data/examples/queues/queue_status.rb +12 -15
  77. data/examples/routing/fanout_routing.rb +33 -0
  78. data/examples/routing/headers_routing.rb +17 -15
  79. data/examples/routing/round_robin_with_direct_exchange.rb +39 -0
  80. data/examples/routing/round_robin_with_the_default_exchange.rb +38 -0
  81. data/examples/routing/unroutable_mandatory_message_is_returned.rb +33 -0
  82. data/examples/routing/weather_updates.rb +15 -20
  83. data/examples/tls/using_tls.rb +41 -0
  84. data/lib/amqp/bit_set.rb +80 -0
  85. data/lib/amqp/broker.rb +72 -0
  86. data/lib/amqp/channel.rb +93 -13
  87. data/lib/amqp/client.rb +11 -22
  88. data/lib/amqp/compatibility/ruby187_patchlevel_check.rb +2 -0
  89. data/lib/amqp/connection.rb +2 -3
  90. data/lib/amqp/consumer.rb +208 -0
  91. data/lib/amqp/deprecated/fork.rb +2 -0
  92. data/lib/amqp/deprecated/mq.rb +2 -0
  93. data/lib/amqp/exchange.rb +6 -4
  94. data/lib/amqp/extensions/rabbitmq.rb +3 -1
  95. data/lib/amqp/header.rb +76 -14
  96. data/lib/amqp/int_allocator.rb +96 -0
  97. data/lib/amqp/logger.rb +2 -0
  98. data/lib/amqp/queue.rb +242 -86
  99. data/lib/amqp/rpc.rb +2 -0
  100. data/lib/amqp/session.rb +169 -9
  101. data/lib/amqp/utilities/event_loop_helper.rb +2 -0
  102. data/lib/amqp/utilities/server_type.rb +2 -0
  103. data/lib/amqp/version.rb +2 -2
  104. data/lib/mq.rb +4 -2
  105. data/lib/mq/logger.rb +3 -1
  106. data/lib/mq/rpc.rb +3 -1
  107. data/spec/integration/authentication_spec.rb +17 -10
  108. data/spec/integration/automatic_binding_for_default_direct_exchange_spec.rb +1 -1
  109. data/spec/integration/automatic_recovery_predicate_spec.rb +68 -0
  110. data/spec/integration/basic_get_spec.rb +2 -1
  111. data/spec/integration/{extensions/basic_return_spec.rb → basic_return_spec.rb} +2 -1
  112. data/spec/integration/channel_level_exception_handling_spec.rb +53 -0
  113. data/spec/integration/connection_level_exception_handling_spec.rb +49 -0
  114. data/spec/integration/declare_and_immediately_bind_a_server_named_queue_spec.rb +38 -17
  115. data/spec/integration/declare_one_hundred_server_named_queues_spec.rb +44 -0
  116. data/spec/integration/direct_exchange_routing_spec.rb +125 -0
  117. data/spec/integration/exchange_declaration_spec.rb +75 -46
  118. data/spec/integration/extensions/rabbitmq/publisher_confirmations_spec.rb +180 -0
  119. data/spec/integration/{workload_distribution_spec.rb → fanout_exchange_routing_spec.rb} +10 -9
  120. data/spec/integration/headers_exchange_routing_spec.rb +269 -0
  121. data/spec/integration/hello_world_spec.rb +77 -0
  122. data/spec/integration/immediate_messages_spec.rb +59 -0
  123. data/spec/integration/mandatory_messages_spec.rb +52 -0
  124. data/spec/integration/message_metadata_access_spec.rb +106 -0
  125. data/spec/integration/multiple_consumers_per_queue_spec.rb +319 -0
  126. data/spec/integration/ordering_of_published_messages_spec.rb +96 -0
  127. data/spec/integration/queue_declaration_spec.rb +8 -8
  128. data/spec/integration/queue_status_spec.rb +66 -0
  129. data/spec/integration/recovery/per_channel_automatic_recovery_on_graceful_broker_shutdown_spec.rb +76 -0
  130. data/spec/integration/recovery/per_channel_automatic_recovery_spec.rb +72 -0
  131. data/spec/integration/redelivery_of_unacknowledged_messages_spec.rb +96 -0
  132. data/spec/integration/regressions/concurrent_publishing_on_the_same_channel_spec.rb +91 -0
  133. data/spec/integration/regressions/empty_message_body_spec.rb +56 -0
  134. data/spec/integration/regressions/issue66_spec.rb +2 -1
  135. data/spec/integration/reply_queue_communication_spec.rb +2 -1
  136. data/spec/integration/store_and_forward_spec.rb +4 -3
  137. data/spec/integration/topic_subscription_spec.rb +2 -1
  138. data/spec/integration/tx_commit_spec.rb +124 -0
  139. data/spec/integration/tx_rollback_spec.rb +167 -0
  140. data/spec/spec_helper.rb +44 -71
  141. data/spec/unit/amqp/bit_set_spec.rb +127 -0
  142. data/spec/unit/amqp/channel_id_allocation_spec.rb +40 -0
  143. data/spec/unit/amqp/connection_spec.rb +4 -2
  144. data/spec/unit/amqp/int_allocator_spec.rb +116 -0
  145. metadata +92 -26
  146. data/CONTRIBUTORS +0 -29
  147. data/docs/Routing.textile +0 -30
  148. data/examples/real-world/task-queue/README.textile +0 -3
  149. data/examples/real-world/task-queue/consumer.rb +0 -27
  150. data/examples/real-world/task-queue/producer.rb +0 -22
  151. data/spec/unit/amqp/basic_spec.rb +0 -39
  152. data/tasks.rb +0 -4
@@ -0,0 +1,180 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ require "amqp/extensions/rabbitmq"
6
+
7
+
8
+ describe "confirm.select" do
9
+
10
+ #
11
+ # Environment
12
+ #
13
+
14
+ include EventedSpec::AMQPSpec
15
+ include EventedSpec::SpecHelper
16
+
17
+ default_options AMQP_OPTS
18
+ default_timeout 3
19
+
20
+ amqp_before do
21
+ @channel = AMQP::Channel.new
22
+ end
23
+
24
+
25
+ context "with :nowait attribute off" do
26
+ it "results in a confirm.select-ok response" do
27
+ @channel.confirm_select do |select_ok|
28
+ done
29
+ end
30
+ end
31
+ end
32
+
33
+
34
+ context "with :nowait attribute set" do
35
+ it "results in NOT confirm.select-ok response" do
36
+ lambda do
37
+ @channel.confirm_select(:nowait => true) do
38
+ fail "Should never be called"
39
+ end
40
+ end.should raise_error(ArgumentError, /makes no sense/)
41
+
42
+ @channel.confirm_select(:nowait => true)
43
+
44
+ done(0.5)
45
+ end
46
+ end
47
+ end
48
+
49
+
50
+
51
+
52
+ describe "Publisher confirmation(s)" do
53
+
54
+ #
55
+ # Environment
56
+ #
57
+
58
+ include EventedSpec::AMQPSpec
59
+ include EventedSpec::SpecHelper
60
+
61
+ default_options AMQP_OPTS
62
+ default_timeout 3
63
+
64
+
65
+ amqp_before do
66
+ @channel1 = AMQP::Channel.new
67
+ @channel2 = AMQP::Channel.new
68
+ end
69
+
70
+
71
+ context "when messages are transient" do
72
+ context "and routable" do
73
+ it "are confirmed as soon as they arrive on all the queues they were routed to" do
74
+ events = Array.new
75
+
76
+ exchange = @channel2.fanout("amqpgem.tests.fanout1", :auto_delete => true)
77
+ queue = @channel1.queue("", :auto_delete => true).bind(exchange).subscribe do |metadata, payload|
78
+ events << :basic_delivery
79
+ end
80
+
81
+ @channel2.confirm_select
82
+ @channel2.on_ack do |basic_ack|
83
+ events << :basic_ack
84
+ end
85
+ exchange.on_return do |basic_return, metadata, payload|
86
+ fail "Should never happen"
87
+ end
88
+
89
+ EventMachine.add_timer(0.5) do
90
+ exchange.publish("Hi", :persistent => false, :mandatory => true)
91
+ end
92
+
93
+ done(2.0) do
94
+ events.should include(:basic_ack)
95
+ events.should include(:basic_delivery)
96
+ end
97
+ end
98
+ end
99
+
100
+
101
+ context "and can be delivered immediately" do
102
+ it "are confirmed as soon as they arrive on all the queues they were routed to" do
103
+ events = Array.new
104
+
105
+ exchange = @channel2.fanout("amqpgem.tests.fanout2", :auto_delete => true)
106
+ queue = @channel1.queue("", :auto_delete => true).bind(exchange).subscribe do |metadata, payload|
107
+ events << :basic_delivery
108
+ end
109
+
110
+ @channel2.confirm_select
111
+ @channel2.on_ack do |basic_ack|
112
+ events << :basic_ack
113
+ end
114
+ exchange.on_return do |basic_return, metadata, payload|
115
+ fail "Should never happen"
116
+ end
117
+
118
+ EventMachine.add_timer(0.5) do
119
+ exchange.publish("Hi", :persistent => false, :immediately => true)
120
+ end
121
+
122
+ done(2.0) do
123
+ events.should include(:basic_ack)
124
+ events.should include(:basic_delivery)
125
+ end
126
+ end
127
+ end
128
+
129
+
130
+
131
+ context "and NOT routable" do
132
+ it "are delivered immediately after basic.return" do
133
+ events = Array.new
134
+
135
+ queue = @channel1.queue("", :auto_delete => true)
136
+ exchange = @channel2.fanout("amqpgem.tests.fanout3", :auto_delete => true)
137
+
138
+ @channel2.confirm_select
139
+ @channel2.on_ack do |basic_ack|
140
+ events << :basic_ack
141
+ end
142
+ exchange.on_return do |basic_return, metadata, payload|
143
+ events << :basic_return
144
+ end
145
+
146
+ EventMachine.add_timer(0.5) do
147
+ exchange.publish("Hi", :persistent => false, :mandatory => true)
148
+ end
149
+
150
+ done(2.0) { events.should == [:basic_return, :basic_ack] }
151
+ end
152
+ end
153
+
154
+
155
+
156
+ context "and CAN NOT be delivered immediately" do
157
+ it "are delivered immediately after basic.return" do
158
+ events = Array.new
159
+
160
+ queue = @channel1.queue("", :auto_delete => true)
161
+ exchange = @channel2.fanout("amqpgem.tests.fanout4", :auto_delete => true)
162
+
163
+ @channel2.confirm_select
164
+ @channel2.on_ack do |basic_ack|
165
+ events << :basic_ack
166
+ end
167
+ exchange.on_return do |basic_return, metadata, payload|
168
+ events << :basic_return
169
+ end
170
+
171
+ EventMachine.add_timer(0.5) do
172
+ exchange.publish("Hi", :persistent => false, :mandatory => true)
173
+ end
174
+
175
+ done(2.0) { events.should == [:basic_return, :basic_ack] }
176
+ end
177
+ end
178
+
179
+ end
180
+ end
@@ -1,4 +1,5 @@
1
- # -*- coding: utf-8 -*-
1
+ # encoding: utf-8
2
+
2
3
  require "spec_helper"
3
4
 
4
5
  describe "Workload distribution" do
@@ -14,7 +15,7 @@ describe "Workload distribution" do
14
15
  em_after { AMQP.cleanup_state }
15
16
 
16
17
  default_options AMQP_OPTS
17
- default_timeout 5
18
+ default_timeout 6
18
19
 
19
20
  amqp_before do
20
21
  @channel = AMQP::Channel.new
@@ -88,7 +89,7 @@ describe "Workload distribution" do
88
89
  end
89
90
 
90
91
  # for Rubinius, it is surprisingly slow on this workload
91
- done(1.5) {
92
+ done(3.5) {
92
93
  [@queue1, @queue2, @queue3].each do |q|
93
94
  @received_messages[q.name].size.should == @expected_number_of_messages[q.name]
94
95
 
@@ -111,7 +112,7 @@ describe "Workload distribution" do
111
112
  end
112
113
 
113
114
  # 6 seconds are for Rubinius, it is surprisingly slow on this workload
114
- done(1.5) {
115
+ done(3.5) {
115
116
  [@queue1, @queue2, @queue3].each do |q|
116
117
  @received_messages[q.name].size.should == @expected_number_of_messages[q.name]
117
118
 
@@ -134,7 +135,7 @@ describe "Workload distribution" do
134
135
  end
135
136
 
136
137
  # 6 seconds are for Rubinius, it is surprisingly slow on this workload
137
- done(1.5) {
138
+ done(3.5) {
138
139
  [@queue1, @queue2, @queue3].each do |q|
139
140
  @received_messages[q.name].size.should == @expected_number_of_messages[q.name]
140
141
 
@@ -157,7 +158,7 @@ describe "Workload distribution" do
157
158
  end
158
159
 
159
160
  # 6 seconds are for Rubinius, it is surprisingly slow on this workload
160
- done(1.5) {
161
+ done(3.5) {
161
162
  [@queue1, @queue2, @queue3].each do |q|
162
163
  @received_messages[q.name].size.should == @expected_number_of_messages[q.name]
163
164
 
@@ -179,7 +180,7 @@ describe "Workload distribution" do
179
180
  end
180
181
 
181
182
  # 6 seconds are for Rubinius, it is surprisingly slow on this workload
182
- done(1.5) {
183
+ done(3.5) {
183
184
  [@queue1, @queue2, @queue3].each do |q|
184
185
  @received_messages[q.name].size.should == @expected_number_of_messages[q.name]
185
186
 
@@ -208,7 +209,7 @@ describe "Workload distribution" do
208
209
  end
209
210
 
210
211
  # 6 seconds are for Rubinius, it is surprisingly slow on this workload
211
- done(1.5) {
212
+ done(3.5) {
212
213
  [@queue1, @queue2, @queue3].each do |q|
213
214
  @received_messages[q.name].size.should == @expected_number_of_messages[q.name]
214
215
 
@@ -230,7 +231,7 @@ describe "Workload distribution" do
230
231
  end
231
232
 
232
233
  # 6 seconds are for Rubinius, it is surprisingly slow on this workload
233
- done(1.5) {
234
+ done(3.5) {
234
235
  [@queue1, @queue2, @queue3].each do |q|
235
236
  @received_messages[q.name].size.should == @expected_number_of_messages[q.name]
236
237
 
@@ -0,0 +1,269 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe "Headers exchange" do
6
+
7
+ #
8
+ # Environment
9
+ #
10
+
11
+ include EventedSpec::AMQPSpec
12
+
13
+ default_timeout 5
14
+
15
+ amqp_before do
16
+ @connection = AMQP.connect
17
+ @channel = AMQP::Channel.new(@connection)
18
+
19
+ @channel.on_error do |ch, channel_close|
20
+ fail "A channel-level exception: #{channel_close.inspect}"
21
+ end
22
+ end
23
+
24
+ after(:all) do
25
+ AMQP.cleanup_state
26
+ done
27
+ end
28
+
29
+
30
+ #
31
+ # Examples
32
+ #
33
+
34
+ # it would be following good practices to split this into
35
+ # 2 separate examples but I think this particular example
36
+ # is complete because it demonstrates routing in cases when
37
+ # different queues are bound with x-match = any AND x-match = all. MK.
38
+ it "can route messages based on any or all of N headers" do
39
+ exchange = @channel.headers("amq.match", :durable => true)
40
+
41
+ linux_and_ia64_messages = []
42
+ @channel.queue("", :auto_delete => true).bind(exchange, :arguments => { 'x-match' => 'all', :arch => "IA64", :os => 'linux' }).subscribe do |metadata, payload|
43
+ linux_and_ia64_messages << [metadata, payload]
44
+ end
45
+
46
+ linux_and_x86_messages = []
47
+ @channel.queue("", :auto_delete => true).bind(exchange, :arguments => { 'x-match' => 'all', :arch => "x86", :os => 'linux' }).subscribe do |metadata, payload|
48
+ linux_and_x86_messages << [metadata, payload]
49
+ end
50
+
51
+ any_linux_messages = []
52
+ @channel.queue("", :auto_delete => true).bind(exchange, :arguments => { :os => 'linux' }).subscribe do |metadata, payload|
53
+ any_linux_messages << [metadata, payload]
54
+ end
55
+
56
+ osx_or_octocore_messages = []
57
+ @channel.queue("", :auto_delete => true).bind(exchange, :arguments => { 'x-match' => 'any', :os => 'macosx', :cores => 8 }).subscribe do |metadata, payload|
58
+ osx_or_octocore_messages << [metadata, payload]
59
+ end
60
+
61
+ riak_messages = []
62
+ @channel.queue("", :auto_delete => true).bind(exchange, :arguments => { :package => { :name => 'riak', :version => '0.14.2' } }).subscribe do |metadata, payload|
63
+ riak_messages << [metadata, payload]
64
+ end
65
+
66
+
67
+ EventMachine.add_timer(0.5) do
68
+ exchange.publish "For linux/IA64", :headers => { :arch => "IA64", :os => 'linux' }
69
+ exchange.publish "For linux/x86", :headers => { :arch => "x86", :os => 'linux' }
70
+ exchange.publish "For any linux", :headers => { :os => 'linux' }
71
+ exchange.publish "For OS X", :headers => { :os => 'macosx' }
72
+ exchange.publish "For solaris/IA64", :headers => { :os => 'solaris', :arch => 'IA64' }
73
+ exchange.publish "For ocotocore", :headers => { :cores => 8 }
74
+
75
+ exchange.publish "For nodes with Riak 0.14.2", :headers => { :package => { :name => 'riak', :version => '0.14.2' } }
76
+ end
77
+
78
+ done(4.5) {
79
+ linux_and_ia64_messages.size.should == 1
80
+ linux_and_x86_messages.size.should == 1
81
+ any_linux_messages.size.should == 3
82
+ osx_or_octocore_messages.size.should == 2
83
+
84
+ riak_messages.size.should == 1
85
+ }
86
+ end
87
+ end
88
+
89
+
90
+
91
+
92
+
93
+ describe "Multiple consumers" do
94
+ include EventedSpec::AMQPSpec
95
+ default_options AMQP_OPTS
96
+ default_timeout 5
97
+
98
+ describe "bound to a queue with the same single header" do
99
+
100
+ #
101
+ # Environment
102
+ #
103
+
104
+ amqp_before do
105
+ @channel = AMQP::Channel.new
106
+ @channel.on_error do |ch, close|
107
+ raise "Channel-level error!: #{close.inspect}"
108
+ end
109
+
110
+ @queue = @channel.queue("", :auto_delete => true)
111
+ @exchange = @channel.headers("amqpgem.tests.integration.headers.exchange1", :auto_delete => true)
112
+
113
+ @queue.bind(@exchange, :arguments => { :slug => "all" })
114
+ end
115
+
116
+
117
+
118
+ it "get messages distributed to them in a round-robin manner" do
119
+ mailbox1 = Array.new
120
+ mailbox2 = Array.new
121
+
122
+ consumer1 = AMQP::Consumer.new(@channel, @queue).consume.on_delivery { |metadata, payload| mailbox1 << payload }
123
+ consumer2 = AMQP::Consumer.new(@channel, @queue).consume.on_delivery { |metadata, payload| mailbox2 << payload }
124
+
125
+
126
+ EventMachine.add_timer(0.5) do
127
+ 12.times { @exchange.publish(".", :headers => { :slug => "all" }) }
128
+ 12.times { @exchange.publish(".", :headers => { :slug => "rspec" }) }
129
+ end
130
+
131
+ done(3.5) {
132
+ mailbox1.size.should == 6
133
+ mailbox2.size.should == 6
134
+ }
135
+ end
136
+ end
137
+
138
+
139
+
140
+ describe "bound to a queue with the same two header & x-match = all" do
141
+
142
+ #
143
+ # Environment
144
+ #
145
+
146
+ amqp_before do
147
+ @channel = AMQP::Channel.new
148
+ @channel.on_error do |ch, close|
149
+ raise "Channel-level error!: #{close.inspect}"
150
+ end
151
+
152
+ @queue = @channel.queue("", :auto_delete => true)
153
+ @exchange = @channel.headers("amqpgem.tests.integration.headers.exchange1", :auto_delete => true)
154
+
155
+ @queue.bind(@exchange, :arguments => { :slug => "all", :arch => "ia64", 'x-match' => 'all' })
156
+ end
157
+
158
+
159
+ it "get messages distributed to them in a round-robin manner" do
160
+ mailbox1 = Array.new
161
+ mailbox2 = Array.new
162
+
163
+ consumer1 = AMQP::Consumer.new(@channel, @queue).consume.on_delivery { |metadata, payload| mailbox1 << payload }
164
+ consumer2 = AMQP::Consumer.new(@channel, @queue).consume.on_delivery { |metadata, payload| mailbox2 << payload }
165
+
166
+ EventMachine.add_timer(0.5) do
167
+ 12.times { @exchange.publish(".", :headers => { :slug => "all", :arch => "ia64" }) }
168
+ 12.times { @exchange.publish(".", :headers => { :slug => "rspec", :arch => "ia64" }) }
169
+ end
170
+
171
+ done(3.5) {
172
+ mailbox1.size.should == 6
173
+ mailbox2.size.should == 6
174
+ }
175
+ end
176
+ end
177
+
178
+
179
+
180
+ describe "bound to 2 queues with the same two header & x-match = all" do
181
+
182
+ #
183
+ # Environment
184
+ #
185
+
186
+ amqp_before do
187
+ @channel = AMQP::Channel.new
188
+ @channel.on_error do |ch, close|
189
+ raise "Channel-level error!: #{close.inspect}"
190
+ end
191
+
192
+ @queue1 = @channel.queue("", :auto_delete => true)
193
+ @queue2 = @channel.queue("", :auto_delete => true)
194
+ @exchange = @channel.headers("amqpgem.tests.integration.headers.exchange1", :auto_delete => true)
195
+
196
+ args = { :slug => "all", :arch => "ia64", 'x-match' => 'all' }
197
+ @queue1.bind(@exchange, :arguments => args)
198
+ @queue2.bind(@exchange, :arguments => args)
199
+ end
200
+
201
+ it "get messages distributed to both queues, and in a round-robin manner between consumers on one queue" do
202
+ mailbox1 = Array.new
203
+ mailbox2 = Array.new
204
+ mailbox3 = Array.new
205
+ mailbox4 = Array.new
206
+
207
+ consumer1 = AMQP::Consumer.new(@channel, @queue1).consume.on_delivery { |metadata, payload| mailbox1 << payload }
208
+ consumer2 = AMQP::Consumer.new(@channel, @queue1).consume.on_delivery { |metadata, payload| mailbox2 << payload }
209
+ consumer3 = AMQP::Consumer.new(@channel, @queue2).consume.on_delivery { |metadata, payload| mailbox3 << payload }
210
+ consumer4 = AMQP::Consumer.new(@channel, @queue2).consume.on_delivery { |metadata, payload| mailbox4 << payload }
211
+
212
+ EventMachine.add_timer(0.5) do
213
+ 12.times { |i| @exchange.publish("all-#{i}", :headers => { :slug => "all", :arch => "ia64" }) }
214
+ 16.times { |i| @exchange.publish("rspec-#{i}", :headers => { :slug => "rspec", :arch => "ia64" }) }
215
+ end
216
+
217
+ done(3.5) {
218
+ mailbox1.size.should == 6
219
+ mailbox1.should == ["all-0", "all-2", "all-4", "all-6", "all-8", "all-10"]
220
+
221
+ mailbox2.size.should == 6
222
+ mailbox2.should == ["all-1", "all-3", "all-5", "all-7", "all-9", "all-11"]
223
+
224
+ mailbox3.size.should == 6
225
+ mailbox4.size.should == 6
226
+ }
227
+ end
228
+ end
229
+
230
+
231
+
232
+
233
+ describe "bound to a queue with the same two header & x-match = any" do
234
+
235
+ #
236
+ # Environment
237
+ #
238
+
239
+ amqp_before do
240
+ @channel = AMQP::Channel.new
241
+ @channel.on_error do |ch, close|
242
+ raise "Channel-level error!: #{close.inspect}"
243
+ end
244
+
245
+ @queue = @channel.queue("", :auto_delete => true)
246
+ @exchange = @channel.headers("amqpgem.tests.integration.headers.exchange1", :auto_delete => true)
247
+
248
+ @queue.bind(@exchange, :arguments => { :slug => "all", :arch => "ia64", 'x-match' => 'any' })
249
+ end
250
+
251
+ it "get messages distributed to them in a round-robin manner" do
252
+ mailbox1 = Array.new
253
+ mailbox2 = Array.new
254
+
255
+ consumer1 = AMQP::Consumer.new(@channel, @queue).consume.on_delivery { |metadata, payload| mailbox1 << payload }
256
+ consumer2 = AMQP::Consumer.new(@channel, @queue).consume.on_delivery { |metadata, payload| mailbox2 << payload }
257
+
258
+ EventMachine.add_timer(0.5) do
259
+ 12.times { @exchange.publish(".", :headers => { :slug => "all", :arch => "ia64" }) }
260
+ 4.times { @exchange.publish(".", :headers => { :slug => "rspec", :arch => "ia64" }) }
261
+ end
262
+
263
+ done(3.5) {
264
+ mailbox1.size.should == 8
265
+ mailbox2.size.should == 8
266
+ }
267
+ end
268
+ end
269
+ end