amqp 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog.md +23 -6
- data/lib/amqp/channel.rb +3 -1
- data/lib/amqp/exchange.rb +140 -8
- data/lib/amqp/version.rb +1 -1
- data/spec/integration/exchange_declaration_spec.rb +22 -0
- data/spec/integration/exchange_to_exchange_binding_spec.rb +124 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7cd9670c82561f472831d5844d8aedf21704384
|
4
|
+
data.tar.gz: 72de0158e4620a8c11468fa6ae141770f5eb5c40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0590210e5493862466fc7c5bfaae3322f4fcd4c738f57eba25e811d4d76205b51b6bf327c44941f59a6b93a24436d6961baaafefeaf64c88b378a7faa6a24dba
|
7
|
+
data.tar.gz: b579abed8e4432158e908dd6d4e992c17e815029b89b3ccb6b0a7b15483eb2bb21a7dc49df7fe389e4d9adc04660b19d0dd8ef620a15578d880b18181932cfa9
|
data/ChangeLog.md
CHANGED
@@ -1,4 +1,26 @@
|
|
1
|
-
## Changes Between 1.2.
|
1
|
+
## Changes Between 1.2.x and 1.3.0
|
2
|
+
|
3
|
+
### Exchange-to-Exchange Bindings Support
|
4
|
+
|
5
|
+
amqp gem now supports [Exchange-to-Exchange Bindings](http://www.rabbitmq.com/e2e.html), a RabbitMQ
|
6
|
+
extension.
|
7
|
+
|
8
|
+
`AMQP::Exchange#bind` and `AMQP::Exchange#unbind` work very much like `AMQP::Queue#bind` and
|
9
|
+
`AMQP::Queue#unbind`, with the argument exchange being the source one.
|
10
|
+
|
11
|
+
Contributed by Stefan Kaes.
|
12
|
+
|
13
|
+
### Internal Exchange Declaration
|
14
|
+
|
15
|
+
amqp gem now supports declaration of internal exchanges
|
16
|
+
(used via exchange-to-exchange bindings, cannot be published to
|
17
|
+
by clients).
|
18
|
+
|
19
|
+
To declare an exchange as internal, add `:internal => true` to
|
20
|
+
declaration options.
|
21
|
+
|
22
|
+
Contributed by Stefan Kaes.
|
23
|
+
|
2
24
|
|
3
25
|
### Initial Connection Failures Retries
|
4
26
|
|
@@ -7,7 +29,6 @@ means connection retries succeed.
|
|
7
29
|
|
8
30
|
Contributed by Marius Hanne.
|
9
31
|
|
10
|
-
|
11
32
|
## Changes Between 1.1.0 and 1.2.0
|
12
33
|
|
13
34
|
### [Authentication Failure Notification](http://www.rabbitmq.com/auth-notification.html) Support
|
@@ -53,10 +74,6 @@ very short lived channels.
|
|
53
74
|
`ConnectionClosedError` from `amq-client` is now defined again.
|
54
75
|
|
55
76
|
|
56
|
-
### amq-protocol Update
|
57
|
-
|
58
|
-
Minimum `amq-protocol` version is now `1.9.0`.
|
59
|
-
|
60
77
|
### Fixed Exceptions in AMQP::Exchange#handle_declare_ok
|
61
78
|
|
62
79
|
`AMQP::Exchange#handle_declare_ok` no longer raises an exception
|
data/lib/amqp/channel.rb
CHANGED
@@ -172,7 +172,7 @@ module AMQP
|
|
172
172
|
|
173
173
|
attr_reader :id
|
174
174
|
|
175
|
-
attr_reader :exchanges_awaiting_declare_ok, :exchanges_awaiting_delete_ok
|
175
|
+
attr_reader :exchanges_awaiting_declare_ok, :exchanges_awaiting_delete_ok, :exchanges_awaiting_bind_ok, :exchanges_awaiting_unbind_ok
|
176
176
|
attr_reader :queues_awaiting_declare_ok, :queues_awaiting_delete_ok, :queues_awaiting_bind_ok, :queues_awaiting_unbind_ok, :queues_awaiting_purge_ok, :queues_awaiting_get_response
|
177
177
|
attr_reader :consumers_awaiting_consume_ok, :consumers_awaiting_cancel_ok
|
178
178
|
|
@@ -1424,6 +1424,8 @@ module AMQP
|
|
1424
1424
|
|
1425
1425
|
@queues_awaiting_declare_ok = Array.new
|
1426
1426
|
@exchanges_awaiting_declare_ok = Array.new
|
1427
|
+
@exchanges_awaiting_bind_ok = Array.new
|
1428
|
+
@exchanges_awaiting_unbind_ok = Array.new
|
1427
1429
|
|
1428
1430
|
@queues_awaiting_delete_ok = Array.new
|
1429
1431
|
|
data/lib/amqp/exchange.rb
CHANGED
@@ -365,9 +365,9 @@ module AMQP
|
|
365
365
|
end
|
366
366
|
end
|
367
367
|
|
368
|
-
self.exchange_declare(
|
368
|
+
self.exchange_declare(@opts[:passive], @opts[:durable], @opts[:auto_delete], @opts[:internal], @opts[:nowait], @opts[:arguments], &shim)
|
369
369
|
else
|
370
|
-
self.exchange_declare(
|
370
|
+
self.exchange_declare(@opts[:passive], @opts[:durable], @opts[:auto_delete], @opts[:internal], @opts[:nowait], @opts[:arguments])
|
371
371
|
end
|
372
372
|
end
|
373
373
|
end
|
@@ -422,6 +422,10 @@ module AMQP
|
|
422
422
|
@name && ((@name == AMQ::Protocol::EMPTY_STRING) || !!(@name =~ /^amq\.(direct|fanout|topic|headers|match)/i))
|
423
423
|
end # predefined?
|
424
424
|
|
425
|
+
# @return [Boolean] true if this exchange is an internal exchange
|
426
|
+
def internal?
|
427
|
+
@opts[:internal]
|
428
|
+
end
|
425
429
|
|
426
430
|
# Publishes message to the exchange. The message will be routed to queues by the exchange
|
427
431
|
# and distributed to any active consumers. Routing logic is determined by exchange type and
|
@@ -604,14 +608,15 @@ module AMQP
|
|
604
608
|
# @group Declaration
|
605
609
|
|
606
610
|
# @api public
|
607
|
-
def exchange_declare(passive = false, durable = false, auto_delete = false, nowait = false, arguments = nil, &block)
|
611
|
+
def exchange_declare(passive = false, durable = false, auto_delete = false, internal = false, nowait = false, arguments = nil, &block)
|
608
612
|
# for re-declaration
|
609
613
|
@passive = passive
|
610
614
|
@durable = durable
|
611
615
|
@auto_delete = auto_delete
|
612
616
|
@arguments = arguments
|
617
|
+
@internal = internal
|
613
618
|
|
614
|
-
@connection.send_frame(AMQ::Protocol::Exchange::Declare.encode(@channel.id, @name, @type.to_s, passive, durable, auto_delete,
|
619
|
+
@connection.send_frame(AMQ::Protocol::Exchange::Declare.encode(@channel.id, @name, @type.to_s, passive, durable, auto_delete, internal, nowait, arguments))
|
615
620
|
|
616
621
|
unless nowait
|
617
622
|
self.define_callback(:declare, &block)
|
@@ -625,7 +630,7 @@ module AMQP
|
|
625
630
|
# @api public
|
626
631
|
def redeclare(&block)
|
627
632
|
nowait = block.nil?
|
628
|
-
@connection.send_frame(AMQ::Protocol::Exchange::Declare.encode(@channel.id, @name, @type.to_s, @passive, @durable, @auto_delete,
|
633
|
+
@connection.send_frame(AMQ::Protocol::Exchange::Declare.encode(@channel.id, @name, @type.to_s, @passive, @durable, @auto_delete, @internal, nowait, @arguments))
|
629
634
|
|
630
635
|
unless nowait
|
631
636
|
self.define_callback(:declare, &block)
|
@@ -653,6 +658,111 @@ module AMQP
|
|
653
658
|
end # delete(if_unused = false, nowait = false)
|
654
659
|
|
655
660
|
|
661
|
+
# @group Exchange to Exchange Bindings
|
662
|
+
|
663
|
+
# This method binds a source exchange to a destination exchange. Messages
|
664
|
+
# sent to the source exchange are forwarded to the destination exchange, provided
|
665
|
+
# the message routing key matches the routing key specified when binding the
|
666
|
+
# exchanges.
|
667
|
+
#
|
668
|
+
# A valid exchange name (or reference) must be passed as the first
|
669
|
+
# parameter.
|
670
|
+
# @example Binding two source exchanges to a destination exchange
|
671
|
+
#
|
672
|
+
# ch = AMQP::Channel.new(connection)
|
673
|
+
# source1 = ch.fanout('backlog-events-datacenter-1')
|
674
|
+
# source2 = ch.fanout('backlog-events-datacenter-2')
|
675
|
+
# destination = ch.fanout('baklog-events')
|
676
|
+
# destination.bind(source1).bind(source2)
|
677
|
+
#
|
678
|
+
#
|
679
|
+
# @param [Exchange] Exchange to bind to. May also be a string or any object that responds to #name.
|
680
|
+
#
|
681
|
+
# @option opts [String] :routing_key Specifies the routing key for the binding. The routing key is
|
682
|
+
# used for routing messages depending on the exchange configuration.
|
683
|
+
# Not all exchanges use a routing key! Refer to the specific
|
684
|
+
# exchange documentation.
|
685
|
+
#
|
686
|
+
# @option opts [Hash] :arguments (nil) A hash of optional arguments with the declaration. Headers exchange type uses these metadata
|
687
|
+
# attributes for routing matching.
|
688
|
+
# In addition, brokers may implement AMQP extensions using x-prefixed declaration arguments.
|
689
|
+
#
|
690
|
+
# @option opts [Boolean] :nowait (true) If set, the server will not respond to the method. The client should
|
691
|
+
# not wait for a reply method. If the server could not complete the
|
692
|
+
# method it will raise a channel or connection exception.
|
693
|
+
# @return [Exchange] Self
|
694
|
+
#
|
695
|
+
#
|
696
|
+
# @yield [] Since exchange.bind-ok carries no attributes, no parameters are yielded to the block.
|
697
|
+
#
|
698
|
+
|
699
|
+
# @api public
|
700
|
+
def bind(source, opts = {}, &block)
|
701
|
+
source = source.name if source.respond_to?(:name)
|
702
|
+
routing_key = opts[:key] || opts[:routing_key] || AMQ::Protocol::EMPTY_STRING
|
703
|
+
arguments = opts[:arguments] || {}
|
704
|
+
nowait = opts[:nowait] || block.nil?
|
705
|
+
@channel.once_open do
|
706
|
+
@connection.send_frame(AMQ::Protocol::Exchange::Bind.encode(@channel.id, @name, source, routing_key, nowait, arguments))
|
707
|
+
unless nowait
|
708
|
+
self.define_callback(:bind, &block)
|
709
|
+
@channel.exchanges_awaiting_bind_ok.push(self)
|
710
|
+
end
|
711
|
+
end
|
712
|
+
self
|
713
|
+
end
|
714
|
+
|
715
|
+
# This method unbinds a source exchange from a previously bound destination exchange.
|
716
|
+
#
|
717
|
+
# A valid exchange name (or reference) must be passed as the first
|
718
|
+
# parameter.
|
719
|
+
# @example Binding and unbinding two exchanges
|
720
|
+
#
|
721
|
+
# ch = AMQP::Channel.new(connection)
|
722
|
+
# source = ch.fanout('backlog-events')
|
723
|
+
# destination = ch.fanout('backlog-events-copy')
|
724
|
+
# destination.bind(source)
|
725
|
+
# ...
|
726
|
+
# destination.unbind(source)
|
727
|
+
#
|
728
|
+
#
|
729
|
+
# @param [Exchange] Exchange to bind to. May also be a string or any object that responds to #name.
|
730
|
+
#
|
731
|
+
# @option opts [String] :routing_key Specifies the routing key for the binding. The routing key is
|
732
|
+
# used for routing messages depending on the exchange configuration.
|
733
|
+
# Not all exchanges use a routing key! Refer to the specific
|
734
|
+
# exchange documentation.
|
735
|
+
#
|
736
|
+
# @option opts [Hash] :arguments (nil) A hash of optional arguments with the declaration. Headers exchange type uses these metadata
|
737
|
+
# attributes for routing matching.
|
738
|
+
# In addition, brokers may implement AMQP extensions using x-prefixed declaration arguments.
|
739
|
+
#
|
740
|
+
# @option opts [Boolean] :nowait (true) If set, the server will not respond to the method. The client should
|
741
|
+
# not wait for a reply method. If the server could not complete the
|
742
|
+
# method it will raise a channel or connection exception.
|
743
|
+
# @return [Exchange] Self
|
744
|
+
#
|
745
|
+
#
|
746
|
+
# @yield [] Since exchange.unbind-ok carries no attributes, no parameters are yielded to the block.
|
747
|
+
#
|
748
|
+
|
749
|
+
# @api public
|
750
|
+
def unbind(source, opts = {}, &block)
|
751
|
+
source = source.name if source.respond_to?(:name)
|
752
|
+
routing_key = opts[:key] || opts[:routing_key] || AMQ::Protocol::EMPTY_STRING
|
753
|
+
arguments = opts[:arguments] || {}
|
754
|
+
nowait = opts[:nowait] || block.nil?
|
755
|
+
@channel.once_open do
|
756
|
+
@connection.send_frame(AMQ::Protocol::Exchange::Unbind.encode(@channel.id, @name, source, routing_key, nowait, arguments))
|
757
|
+
unless nowait
|
758
|
+
self.define_callback(:unbind, &block)
|
759
|
+
@channel.exchanges_awaiting_unbind_ok.push(self)
|
760
|
+
end
|
761
|
+
end
|
762
|
+
self
|
763
|
+
end
|
764
|
+
|
765
|
+
# @endgroup
|
656
766
|
|
657
767
|
# @group Publishing Messages
|
658
768
|
|
@@ -750,10 +860,17 @@ module AMQP
|
|
750
860
|
self.exec_callback_once_yielding_self(:declare, method)
|
751
861
|
end
|
752
862
|
|
863
|
+
def handle_bind_ok(method)
|
864
|
+
self.exec_callback_once(:bind, method)
|
865
|
+
end
|
866
|
+
|
867
|
+
def handle_unbind_ok(method)
|
868
|
+
self.exec_callback_once(:unbind, method)
|
869
|
+
end
|
870
|
+
|
753
871
|
def handle_delete_ok(method)
|
754
872
|
self.exec_callback_once(:delete, method)
|
755
|
-
end
|
756
|
-
|
873
|
+
end
|
757
874
|
|
758
875
|
|
759
876
|
self.handle(AMQ::Protocol::Exchange::DeclareOk) do |connection, frame|
|
@@ -764,6 +881,21 @@ module AMQP
|
|
764
881
|
exchange.handle_declare_ok(method)
|
765
882
|
end # handle
|
766
883
|
|
884
|
+
self.handle(AMQ::Protocol::Exchange::BindOk) do |connection, frame|
|
885
|
+
method = frame.decode_payload
|
886
|
+
channel = connection.channels[frame.channel]
|
887
|
+
exchange = channel.exchanges_awaiting_bind_ok.shift
|
888
|
+
|
889
|
+
exchange.handle_bind_ok(method)
|
890
|
+
end # handle
|
891
|
+
|
892
|
+
self.handle(AMQ::Protocol::Exchange::UnbindOk) do |connection, frame|
|
893
|
+
method = frame.decode_payload
|
894
|
+
channel = connection.channels[frame.channel]
|
895
|
+
exchange = channel.exchanges_awaiting_unbind_ok.shift
|
896
|
+
|
897
|
+
exchange.handle_unbind_ok(method)
|
898
|
+
end # handle
|
767
899
|
|
768
900
|
self.handle(AMQ::Protocol::Exchange::DeleteOk) do |connection, frame|
|
769
901
|
channel = connection.channels[frame.channel]
|
@@ -789,7 +921,7 @@ module AMQP
|
|
789
921
|
|
790
922
|
# @private
|
791
923
|
def self.add_default_options(type, name, opts, block)
|
792
|
-
{ :exchange => name, :type => type, :nowait => block.nil
|
924
|
+
{ :exchange => name, :type => type, :nowait => block.nil?, :internal => false }.merge(opts)
|
793
925
|
end
|
794
926
|
end # Exchange
|
795
927
|
end # AMQP
|
data/lib/amqp/version.rb
CHANGED
@@ -472,6 +472,28 @@ describe AMQP::Channel do
|
|
472
472
|
end # it
|
473
473
|
end # context
|
474
474
|
|
475
|
+
context "when exchange is declared with or without :internal parameter" do
|
476
|
+
it "should create a public exchange by default" do
|
477
|
+
exchange = @channel.topic("a new public topic exchange")
|
478
|
+
|
479
|
+
exchange.should_not be_internal
|
480
|
+
done
|
481
|
+
end # it
|
482
|
+
|
483
|
+
it "should create a public exchange when :internal is false" do
|
484
|
+
exchange = @channel.topic("a new-public topic exchange", :internal => false)
|
485
|
+
|
486
|
+
exchange.should_not be_internal
|
487
|
+
done
|
488
|
+
end # it
|
489
|
+
|
490
|
+
it "should create an internal exchange when :internal is true" do
|
491
|
+
exchange = @channel.topic("a new internal topic exchange", :internal => true)
|
492
|
+
|
493
|
+
exchange.should be_internal
|
494
|
+
done
|
495
|
+
end # it
|
496
|
+
end # context
|
475
497
|
|
476
498
|
context "when exchange is re-declared with parameters different from the original declaration" do
|
477
499
|
amqp_after do
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe AMQP::Channel do
|
6
|
+
|
7
|
+
#
|
8
|
+
# Environment
|
9
|
+
#
|
10
|
+
|
11
|
+
include EventedSpec::AMQPSpec
|
12
|
+
|
13
|
+
default_options AMQP_OPTS
|
14
|
+
default_timeout 2
|
15
|
+
|
16
|
+
|
17
|
+
amqp_before do
|
18
|
+
@channel = AMQP::Channel.new
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Examples
|
23
|
+
#
|
24
|
+
|
25
|
+
describe "exchange to exchange bindings" do
|
26
|
+
context "basic properties" do
|
27
|
+
it "bind returns self" do
|
28
|
+
source1 = @channel.fanout("fanout-exchange-source-1")
|
29
|
+
source2 = @channel.fanout("fanout-exchange-source-2")
|
30
|
+
destination = @channel.fanout("fanout-exchange-destination-multi")
|
31
|
+
destination.bind(source1).bind(source2).should == destination
|
32
|
+
done
|
33
|
+
end
|
34
|
+
|
35
|
+
it "bind can work with strings for source exchange parameter" do
|
36
|
+
@channel.fanout("fanout-exchange-source-3")
|
37
|
+
destination = @channel.fanout("fanout-exchange-destination-multi-2")
|
38
|
+
destination.bind('fanout-exchange-source-3').should == destination
|
39
|
+
done
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "fanout exchanges" do
|
44
|
+
it "are bindable and forward messages" do
|
45
|
+
source = @channel.fanout("fanout-exchange-source")
|
46
|
+
destination = @channel.fanout("fanout-exchange-destination")
|
47
|
+
messages = []
|
48
|
+
destination.bind(source) do
|
49
|
+
queue = @channel.queue("fanout-forwarding", :auto_delete => true)
|
50
|
+
queue.subscribe do |metadata, payload|
|
51
|
+
messages << payload
|
52
|
+
end
|
53
|
+
queue.bind(destination) do
|
54
|
+
source.publish("x")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
done(0.1) { messages.should == ["x"] }
|
58
|
+
end
|
59
|
+
|
60
|
+
it "can be unbound" do
|
61
|
+
source = @channel.fanout("fanout-exchange-source-2")
|
62
|
+
destination = @channel.fanout("fanout-exchange-destination-2")
|
63
|
+
destination.bind(source) do
|
64
|
+
destination.unbind(source) do
|
65
|
+
done
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
it "can be unbound without callbacks" do
|
71
|
+
source = @channel.fanout("fanout-exchange-source-2")
|
72
|
+
destination = @channel.fanout("fanout-exchange-destination-2")
|
73
|
+
destination.bind(source)
|
74
|
+
destination.unbind(source)
|
75
|
+
done
|
76
|
+
end
|
77
|
+
|
78
|
+
it "using :nowait => true should not call a passed in block" do
|
79
|
+
source = @channel.fanout("fanout-exchange-source-no-wait")
|
80
|
+
destination = @channel.fanout("fanout-exchange-destination-no-wait")
|
81
|
+
callback_called = false
|
82
|
+
destination.bind(source, :nowait => true) do
|
83
|
+
callback_called = true
|
84
|
+
end
|
85
|
+
done(0.1) { callback_called.should be_false}
|
86
|
+
end
|
87
|
+
|
88
|
+
end #context
|
89
|
+
|
90
|
+
context "topic exchanges" do
|
91
|
+
it "using routing key '#'" do
|
92
|
+
source = @channel.topic("topic-exchange-source")
|
93
|
+
destination = @channel.topic("topic-exchange-destination")
|
94
|
+
messages = []
|
95
|
+
destination.bind(source) do
|
96
|
+
queue = @channel.queue("ex-to-ex-default-key", :auto_delete => true)
|
97
|
+
queue.subscribe do |metadata, payload|
|
98
|
+
messages << payload
|
99
|
+
end
|
100
|
+
queue.bind(destination, :routing_key => "#") do
|
101
|
+
source.publish("a", :routing_key => "lalalala")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
done(0.1) { messages.should == ["a"] }
|
105
|
+
end
|
106
|
+
|
107
|
+
it "using routing key 'foo'" do
|
108
|
+
source = @channel.topic("topic-exchange-source-foo")
|
109
|
+
destination = @channel.topic("topic-exchange-destination-foo")
|
110
|
+
messages = []
|
111
|
+
destination.bind(source, :routing_key => 'foo') do
|
112
|
+
queue = @channel.queue("foo-foo", :auto_delete => true)
|
113
|
+
queue.subscribe do |metadata, payload|
|
114
|
+
messages << payload
|
115
|
+
end
|
116
|
+
queue.bind(destination, :routing_key => "foo") do
|
117
|
+
source.publish("b", :routing_key => "foo")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
done(0.1) { messages.should == ["b"]}
|
121
|
+
end
|
122
|
+
end #context
|
123
|
+
end # describe
|
124
|
+
end # describe AMQP
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amqp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aman Gupta
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2014-
|
13
|
+
date: 2014-02-03 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: eventmachine
|
@@ -272,6 +272,7 @@ files:
|
|
272
272
|
- spec/integration/declare_one_hundred_server_named_queues_spec.rb
|
273
273
|
- spec/integration/direct_exchange_routing_spec.rb
|
274
274
|
- spec/integration/exchange_declaration_spec.rb
|
275
|
+
- spec/integration/exchange_to_exchange_binding_spec.rb
|
275
276
|
- spec/integration/extensions/rabbitmq/publisher_confirmations_spec.rb
|
276
277
|
- spec/integration/fanout_exchange_routing_spec.rb
|
277
278
|
- spec/integration/headers_exchange_routing_spec.rb
|