amqp 0.7.0.pre → 0.7.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 (71) hide show
  1. data/.gitignore +4 -0
  2. data/.rspec +2 -0
  3. data/CHANGELOG +8 -2
  4. data/CONTRIBUTORS +22 -0
  5. data/Gemfile +3 -3
  6. data/README.md +20 -11
  7. data/Rakefile +30 -6
  8. data/amqp.gemspec +1 -1
  9. data/bin/cleanify.rb +50 -0
  10. data/examples/amqp/simple.rb +6 -4
  11. data/examples/mq/ack.rb +8 -6
  12. data/examples/mq/automatic_binding_for_default_direct_exchange.rb +65 -0
  13. data/examples/mq/callbacks.rb +9 -1
  14. data/examples/mq/clock.rb +17 -17
  15. data/examples/mq/hashtable.rb +19 -10
  16. data/examples/mq/internal.rb +13 -11
  17. data/examples/mq/logger.rb +38 -36
  18. data/examples/mq/multiclock.rb +16 -7
  19. data/examples/mq/pingpong.rb +16 -7
  20. data/examples/mq/pop.rb +8 -6
  21. data/examples/mq/primes-simple.rb +2 -0
  22. data/examples/mq/primes.rb +7 -5
  23. data/examples/mq/stocks.rb +14 -5
  24. data/lib/amqp.rb +12 -8
  25. data/lib/amqp/buffer.rb +35 -158
  26. data/lib/amqp/client.rb +34 -22
  27. data/lib/amqp/frame.rb +8 -64
  28. data/lib/amqp/protocol.rb +21 -70
  29. data/lib/amqp/server.rb +11 -9
  30. data/lib/amqp/spec.rb +8 -6
  31. data/lib/amqp/version.rb +2 -0
  32. data/lib/ext/blankslate.rb +3 -1
  33. data/lib/ext/em.rb +2 -0
  34. data/lib/ext/emfork.rb +13 -11
  35. data/lib/mq.rb +253 -156
  36. data/lib/mq/collection.rb +6 -88
  37. data/lib/mq/exchange.rb +70 -13
  38. data/lib/mq/header.rb +12 -6
  39. data/lib/mq/logger.rb +9 -7
  40. data/lib/mq/queue.rb +42 -30
  41. data/lib/mq/rpc.rb +6 -4
  42. data/protocol/codegen.rb +20 -18
  43. data/research/api.rb +10 -46
  44. data/research/primes-forked.rb +9 -7
  45. data/research/primes-processes.rb +74 -72
  46. data/research/primes-threaded.rb +9 -7
  47. data/spec/integration/automatic_binding_for_default_direct_exchange_spec.rb +61 -0
  48. data/spec/mq_helper.rb +70 -0
  49. data/spec/spec_helper.rb +84 -29
  50. data/spec/unit/amqp/buffer_spec.rb +178 -0
  51. data/spec/unit/amqp/client_spec.rb +472 -0
  52. data/spec/unit/amqp/frame_spec.rb +60 -0
  53. data/spec/unit/amqp/misc_spec.rb +123 -0
  54. data/spec/unit/amqp/protocol_spec.rb +53 -0
  55. data/spec/unit/mq/channel_close_spec.rb +15 -0
  56. data/spec/unit/mq/collection_spec.rb +129 -0
  57. data/spec/unit/mq/exchange_declaration_spec.rb +524 -0
  58. data/spec/unit/mq/misc_spec.rb +228 -0
  59. data/spec/unit/mq/mq_basic_spec.rb +39 -0
  60. data/spec/unit/mq/queue_declaration_spec.rb +97 -0
  61. data/spec/unit/mq/queue_spec.rb +71 -0
  62. metadata +33 -21
  63. data/Gemfile.lock +0 -16
  64. data/old/README +0 -30
  65. data/old/Rakefile +0 -12
  66. data/old/amqp-0.8.json +0 -606
  67. data/old/amqp_spec.rb +0 -796
  68. data/old/amqpc.rb +0 -695
  69. data/old/codegen.rb +0 -148
  70. data/spec/channel_close_spec.rb +0 -13
  71. data/spec/sync_async_spec.rb +0 -52
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+
4
+ require "spec_helper"
5
+ require "amqp/frame"
6
+
7
+ describe AMQP::Frame do
8
+ include AMQP
9
+
10
+ it 'should handle basic frame types' do
11
+ Frame::Method.new.id.should == 1
12
+ Frame::Header.new.id.should == 2
13
+ Frame::Body.new.id.should == 3
14
+ end
15
+
16
+ it 'should convert method frames to binary' do
17
+ meth = Protocol::Connection::Secure.new :challenge => 'secret'
18
+
19
+ frame = Frame::Method.new(meth)
20
+ frame.to_binary.should be_kind_of Buffer
21
+ frame.to_s.should == [1, 0, meth.to_s.length, meth.to_s, 206].pack('CnNa*C')
22
+ end
23
+
24
+ it 'should convert binary to method frames' do
25
+ orig = Frame::Method.new Protocol::Connection::Secure.new(:challenge => 'secret')
26
+
27
+ copy = Frame.parse(orig.to_binary)
28
+ copy.should == orig
29
+ end
30
+
31
+ it 'should ignore partial frames until ready' do
32
+ frame = Frame::Method.new Protocol::Connection::Secure.new(:challenge => 'secret')
33
+ data = frame.to_s
34
+
35
+ buf = Buffer.new
36
+ Frame.parse(buf).should == nil
37
+
38
+ buf << data[0..5]
39
+ Frame.parse(buf).should == nil
40
+
41
+ buf << data[6..-1]
42
+ Frame.parse(buf).should == frame
43
+
44
+ Frame.parse(buf).should == nil
45
+ end
46
+
47
+ it 'should convert header frames to binary' do
48
+ head = Protocol::Header.new(Protocol::Basic, :priority => 1)
49
+
50
+ frame = Frame::Header.new(head)
51
+ frame.to_s.should == [2, 0, head.to_s.length, head.to_s, 206].pack('CnNa*C')
52
+ end
53
+
54
+ it 'should convert binary to header frame' do
55
+ orig = Frame::Header.new Protocol::Header.new(Protocol::Basic, :priority => 1)
56
+
57
+ copy = Frame.parse(orig.to_binary)
58
+ copy.should == orig
59
+ end
60
+ end
@@ -0,0 +1,123 @@
1
+ require 'spec_helper'
2
+
3
+ require 'amqp'
4
+
5
+ module MockClientModule
6
+ def my_mock_method
7
+ end
8
+ end
9
+
10
+ class MockClient
11
+ include AMQP::Client
12
+ end
13
+
14
+ describe AMQP, 'class object' do
15
+ context 'has class accessors, with default values' do
16
+ subject { AMQP }
17
+
18
+ its(:logging) { should be_false }
19
+ its(:connection) { should be_nil }
20
+ its(:conn) { should be_nil } # Alias for #connection
21
+ its(:closing) { should be_false }
22
+ its(:settings) { should == {:host => "127.0.0.1",
23
+ :port => 5672,
24
+ :user => "guest",
25
+ :pass => "guest",
26
+ :vhost => "/",
27
+ :timeout => nil,
28
+ :logging => false,
29
+ :ssl => false} }
30
+
31
+ its(:client) { should == AMQP::BasicClient }
32
+ end
33
+
34
+
35
+
36
+ describe '.client=' do
37
+ after(:all) { AMQP.client = AMQP::BasicClient }
38
+
39
+ it 'is used to change default client module' do
40
+ AMQP.client = MockClientModule
41
+ AMQP.client.should == MockClientModule
42
+ MockClientModule.ancestors.should include AMQP
43
+ end
44
+
45
+ describe 'new default client module' do
46
+ it 'sticks around after being assigned' do
47
+ AMQP.client.should == MockClientModule
48
+ end
49
+
50
+ it 'extends any object that includes AMQP::Client' do
51
+ @client = MockClient.new
52
+ @client.should respond_to :my_mock_method
53
+ end
54
+ end
55
+ end # .client
56
+
57
+
58
+
59
+
60
+ describe 'logging' do
61
+ after(:all) do
62
+ AMQP.logging = false
63
+ end
64
+
65
+ it 'is silent by default' do
66
+ AMQP.logging.should be_false
67
+ end
68
+ end # .logging=
69
+
70
+
71
+
72
+
73
+ describe '.start' do
74
+ context 'inside EM loop' do
75
+ include AMQP::SpecHelper
76
+ em_after { AMQP.cleanup_state }
77
+
78
+ it 'yields to given block AFTER connection is established' do
79
+ em do
80
+ AMQP.start AMQP_OPTS do
81
+ @block_fired = true
82
+ AMQP.connection.should be_connected
83
+ end
84
+ done(0.1) { @block_fired.should be_true }
85
+ end
86
+ end
87
+ end # context 'inside EM loop'
88
+ end # .start
89
+
90
+
91
+
92
+
93
+ describe '.stop' do
94
+ it 'is noop if connection is not established' do
95
+ expect { @res = AMQP.stop }.to_not raise_error
96
+ @res.should be_nil
97
+ end
98
+
99
+ context 'with established AMQP connection' do
100
+ include AMQP::Spec
101
+ after { AMQP.cleanup_state; done }
102
+ default_options AMQP_OPTS
103
+
104
+ it 'unsets AMQP.connection property. Mind the delay!' do
105
+ AMQP.start(AMQP_OPTS)
106
+ AMQP.connection.should be_connected
107
+
108
+ AMQP.stop
109
+ AMQP.connection.should_not be_nil
110
+ done(0.1) { AMQP.connection.should be_nil }
111
+ end
112
+
113
+ it 'yields to given block AFTER disconnect (BUT before AMQP.conn is cleared!)' do
114
+ AMQP.stop do
115
+ @block_fired = true
116
+ AMQP.connection.should_not be_nil
117
+ AMQP.instance_variable_get(:@closing).should be_true
118
+ end
119
+ done(0.1) { @block_fired.should be_true }
120
+ end
121
+ end # context 'with established AMQP connection'
122
+ end # .stop
123
+ end
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+ require "amqp/protocol"
5
+
6
+ describe AMQP::Protocol do
7
+ include AMQP
8
+
9
+ it 'should instantiate methods with arguments' do
10
+ meth = Protocol::Connection::StartOk.new nil, 'PLAIN', nil, 'en_US'
11
+ meth.locale.should == 'en_US'
12
+ end
13
+
14
+ it 'should instantiate methods with named parameters' do
15
+ meth = Protocol::Connection::StartOk.new :locale => 'en_US',
16
+ :mechanism => 'PLAIN'
17
+ meth.locale.should == 'en_US'
18
+ end
19
+
20
+ it 'should convert methods to binary' do
21
+ meth = Protocol::Connection::Secure.new :challenge => 'secret'
22
+ meth.to_binary.should be_kind_of Buffer
23
+
24
+ meth.to_s.should == [10, 20, 6, 'secret'].pack('nnNa*')
25
+ end
26
+
27
+ it 'should convert binary to method' do
28
+ orig = Protocol::Connection::Secure.new :challenge => 'secret'
29
+ copy = Protocol.parse orig.to_binary
30
+ orig.should == copy
31
+ end
32
+
33
+ it 'should convert headers to binary' do
34
+ head = Protocol::Header.new Protocol::Basic,
35
+ size = 5,
36
+ weight = 0,
37
+ :content_type => 'text/json',
38
+ :delivery_mode => 1,
39
+ :priority => 1
40
+ head.to_s.should ==
41
+ [60, weight, 0, size, 0b1001_1000_0000_0000, 9, 'text/json', 1, 1].pack('nnNNnCa*CC')
42
+ end
43
+
44
+ it 'should convert binary to header' do
45
+ orig = Protocol::Header.new Protocol::Basic,
46
+ size = 5,
47
+ weight = 0,
48
+ :content_type => 'text/json',
49
+ :delivery_mode => 1,
50
+ :priority => 1
51
+ Protocol::Header.new(orig.to_binary).should == orig
52
+ end
53
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe MQ, "#close(&callback)" do
6
+ include AMQP::EMSpec
7
+
8
+ default_timeout 5
9
+
10
+ it "takes a callback which will run when we get back Channel.Close-Ok" do
11
+ MQ.new.close do |amq|
12
+ done
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,129 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+ require "mq/collection"
5
+
6
+ Item = Struct.new(:name)
7
+
8
+ describe MQ::Collection do
9
+ before do
10
+ @items = 3.times.map { |int| Item.new("name-#{int}") }
11
+ @collection = MQ::Collection.new(@items)
12
+ end
13
+
14
+ it "provides access to items by name" do
15
+ @collection["name-1"].should_not be_nil
16
+ @collection["name-1"].should eql(@items[1])
17
+ end
18
+
19
+ it "DOES NOT allow modification of existing items" do
20
+ lambda { @collection["name-1"] = Item.new("test") }.should raise_error(NoMethodError)
21
+ end
22
+
23
+
24
+ describe "#<<" do
25
+ it "should raise IncompatibleItemError if the argument doesn't have method :name" do
26
+ lambda { @collection << nil }.should raise_error(MQ::Collection::IncompatibleItemError)
27
+ end
28
+
29
+ it "should add an item into the collection" do
30
+ length = @collection.length
31
+ @collection << Item.new("test")
32
+ @collection.length.should eql(length + 1)
33
+ end
34
+
35
+ context "when another item with given name already exists and the name IS NOT nil" do
36
+ it "should not add an item to the collection" do
37
+ @collection << Item.new("test")
38
+ length = @collection.length
39
+ @collection << Item.new("test")
40
+ @collection.length.should eql(length)
41
+ end # it
42
+ end # context
43
+
44
+
45
+ context "when another item with given name already exists and the name IS nil" do
46
+ it "should add an item to the collection" do
47
+ @collection << Item.new(nil)
48
+ length = @collection.length
49
+ @collection << Item.new(nil)
50
+ @collection.length.should eql(length + 1)
51
+ end # it
52
+ end # context
53
+
54
+ it "should return the item" do
55
+ item = Item.new("test")
56
+ (@collection << item).should eql item
57
+ end
58
+
59
+ context "when adding new item with duplicate name" do
60
+ before do
61
+ @original_item = Item.new("test")
62
+ @new_item = Item.new("test")
63
+ @collection << @original_item
64
+ end
65
+
66
+ it "keeps item already in collection" do
67
+ @collection << @new_item
68
+ @collection['test'].should eql @original_item
69
+ end
70
+
71
+ it "returns item already in collection" do
72
+ (@collection << @new_item).should eql @original_item
73
+ end
74
+ end
75
+
76
+ context "when item we add already exists in the collection" do
77
+ it "should return the item" do
78
+ item = Item.new("test")
79
+ @collection << item
80
+ (@collection << item).should eql item
81
+ end # it
82
+ end # context
83
+ end # describe
84
+
85
+
86
+
87
+
88
+ describe "#add!" do
89
+ context "when the argument doesn't respond to :name" do
90
+ it "should raise IncompatibleItemError " do
91
+ lambda { @collection.add!(nil) }.should raise_error(MQ::Collection::IncompatibleItemError)
92
+ end # it
93
+ end
94
+
95
+ context "when another item with given name already exists" do
96
+ it "should add an item to the collection" do
97
+ @collection.add! Item.new("test")
98
+ lambda do
99
+ @collection.add!(Item.new("test"))
100
+ end.should change(@collection, :length).by(1)
101
+ end # it
102
+ end # context
103
+
104
+ it "should return the item" do
105
+ item = Item.new("test")
106
+ (@collection.add! item).should eql(item)
107
+ end # it
108
+ end # describe
109
+
110
+
111
+
112
+
113
+
114
+ describe "#<<" do
115
+ context "when the argument doesn't respond to :name" do
116
+ it "should raise IncompatibleItemError " do
117
+ lambda { @collection << nil }.should raise_error(MQ::Collection::IncompatibleItemError)
118
+ end # it
119
+ end # context
120
+
121
+ context "when the argument DOES respond to :name" do
122
+ it "should add an item into the collection" do
123
+ lambda do
124
+ @collection << Item.new("test")
125
+ end.should change(@collection, :length).by(1)
126
+ end
127
+ end # context
128
+ end # describe
129
+ end # describe MQ::Collection
@@ -0,0 +1,524 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe MQ do
6
+
7
+ #
8
+ # Environment
9
+ #
10
+
11
+ include AMQP::Spec
12
+
13
+ default_timeout 10
14
+
15
+ amqp_before do
16
+ @channel = MQ.new
17
+ end
18
+
19
+
20
+ #
21
+ # Examples
22
+ #
23
+
24
+ describe "#direct" do
25
+ context "when exchange name is specified" do
26
+ it 'declares a new direct exchange with that name' do
27
+ @channel.direct('name').name.should == 'name'
28
+
29
+ done
30
+ end
31
+
32
+ it "declares direct exchange as transient (non-durable)" do
33
+ exchange = @channel.direct('name')
34
+
35
+ exchange.should_not be_durable
36
+ exchange.should be_transient
37
+
38
+ done
39
+ end
40
+
41
+ it "declares direct exchange as non-auto-deleted" do
42
+ exchange = @channel.direct('name')
43
+
44
+ exchange.should_not be_auto_deleted
45
+
46
+ done
47
+ end
48
+ end
49
+
50
+
51
+ context "when exchange name is omitted" do
52
+ it 'uses amq.direct' do
53
+ @channel.direct.name.should == 'amq.direct'
54
+ done
55
+ end # it
56
+ end # context
57
+
58
+
59
+ context "when exchange name was specified as a blank string" do
60
+ it 'returns direct exchange with server-generated name' do
61
+ pending <<-EOF
62
+ This has to be fixed in RabbitMQ first
63
+ https://bugzilla.rabbitmq.com/show_bug.cgi?id=23509
64
+ EOF
65
+ @channel.direct("") do |exchange|
66
+ exchange.name.should_not be_empty
67
+ done
68
+ end
69
+ end
70
+ end # context
71
+
72
+
73
+ context "when passive option is used" do
74
+ context "and exchange with given name already exists" do
75
+ it "silently returns" do
76
+ name = "a_new_direct_exchange declared at #{Time.now.to_i}"
77
+
78
+ original_exchange = @channel.direct(name)
79
+ exchange = @channel.direct(name, :passive => true)
80
+
81
+ exchange.should == original_exchange
82
+
83
+ done
84
+ end # it
85
+ end
86
+
87
+ context "and exchange with given name DOES NOT exist" do
88
+ it "raises an exception" do
89
+ pending "Not yet supported"
90
+
91
+ expect {
92
+ exchange = @channel.direct("direct exchange declared at #{Time.now.to_i}", :passive => true)
93
+ }.to raise_error
94
+
95
+ done
96
+ end # it
97
+ end # context
98
+ end # context
99
+
100
+
101
+ context "when exchange is declared as durable" do
102
+ it "returns a new durable direct exchange" do
103
+ exchange = @channel.direct("a_new_durable_direct_exchange", :durable => true)
104
+ exchange.should be_durable
105
+ exchange.should_not be_transient
106
+
107
+ done
108
+ end # it
109
+ end # context
110
+
111
+
112
+ context "when exchange is declared as non-durable" do
113
+ it "returns a new NON-durable direct exchange" do
114
+ exchange = @channel.direct("a_new_non_durable_direct_exchange", :durable => false)
115
+ exchange.should_not be_durable
116
+ exchange.should be_transient
117
+
118
+ done
119
+ end # it
120
+ end # context
121
+
122
+
123
+ context "when exchange is declared as auto-deleted" do
124
+ it "returns a new auto-deleted direct exchange" do
125
+ exchange = @channel.direct("a new auto-deleted direct exchange", :auto_delete => true)
126
+
127
+ exchange.should be_auto_deleted
128
+ done
129
+ end # it
130
+ end # context
131
+
132
+
133
+ context "when exchange is declared as auto-deleted" do
134
+ it "returns a new auto-deleted direct exchange" do
135
+ exchange = @channel.direct("a new non-auto-deleted direct exchange", :auto_delete => false)
136
+
137
+ exchange.should_not be_auto_deleted
138
+ done
139
+ end # it
140
+ end # context
141
+
142
+
143
+ context "when exchange is declared without explicit :nowait parameter" do
144
+ it "is declared with :nowait by default" do
145
+ exchange = @channel.direct("a new non-auto-deleted direct exchange", :auto_delete => false)
146
+
147
+ exchange.should_not be_auto_deleted
148
+ done
149
+ end # it
150
+ end # context
151
+
152
+
153
+ context "when exchange is re-declared with parameters different from original declaration" do
154
+ it "raises an exception" do
155
+ @channel.direct("previously.declared.durable.direct.exchange", :durable => true)
156
+
157
+ expect {
158
+ @channel.direct("previously.declared.durable.direct.exchange", :durable => false)
159
+ }.to raise_error(MQ::IncompatibleOptionsError)
160
+
161
+ done
162
+ end # it
163
+ end # context
164
+ end # describe
165
+
166
+
167
+
168
+
169
+ describe "#fanout" do
170
+ context "when exchange name is specified" do
171
+ let(:name) { "new.fanout.exchange" }
172
+
173
+ it "declares a new fanout exchange with that name" do
174
+ exchange = @channel.fanout(name)
175
+
176
+ exchange.name.should == name
177
+
178
+ done
179
+ end
180
+ end # context
181
+
182
+ context "when exchange name is omitted" do
183
+ it "uses amq.fanout" do
184
+ exchange = @channel.fanout
185
+ exchange.name.should == "amq.fanout"
186
+ exchange.name.should_not == "amq.fanout2"
187
+
188
+ done
189
+ end
190
+ end # context
191
+
192
+ context "when passive option is used" do
193
+ context "and exchange with given name already exists" do
194
+ it "silently returns" do
195
+ name = "a_new_fanout_exchange declared at #{Time.now.to_i}"
196
+
197
+ original_exchange = @channel.fanout(name)
198
+ exchange = @channel.fanout(name, :passive => true)
199
+
200
+ exchange.should == original_exchange
201
+
202
+ done
203
+ end # it
204
+ end
205
+
206
+ context "and exchange with given name DOES NOT exist" do
207
+ it "raises an exception" do
208
+ pending "Not yet supported"
209
+
210
+ expect {
211
+ exchange = @channel.fanout("fanout exchange declared at #{Time.now.to_i}", :passive => true)
212
+ }.to raise_error
213
+
214
+ done
215
+ end # it
216
+ end # context
217
+ end # context
218
+
219
+
220
+ context "when exchange is declared as durable" do
221
+ it "returns a new durable fanout exchange" do
222
+ exchange = @channel.fanout("a_new_durable_fanout_exchange", :durable => true)
223
+ exchange.should be_durable
224
+ exchange.should_not be_transient
225
+
226
+ done
227
+ end # it
228
+ end # context
229
+
230
+
231
+ context "when exchange is declared as non-durable" do
232
+ it "returns a new NON-durable fanout exchange" do
233
+ exchange = @channel.fanout("a_new_non_durable_fanout_exchange", :durable => false)
234
+ exchange.should_not be_durable
235
+ exchange.should be_transient
236
+
237
+ done
238
+ end # it
239
+ end # context
240
+
241
+
242
+ context "when exchange is declared as auto-deleted" do
243
+ it "returns a new auto-deleted fanout exchange" do
244
+ exchange = @channel.fanout("a new auto-deleted fanout exchange", :auto_delete => true)
245
+
246
+ exchange.should be_auto_deleted
247
+ done
248
+ end # it
249
+ end # context
250
+
251
+
252
+ context "when exchange is declared as auto-deleted" do
253
+ it "returns a new auto-deleted fanout exchange" do
254
+ exchange = @channel.fanout("a new non-auto-deleted fanout exchange", :auto_delete => false)
255
+
256
+ exchange.should_not be_auto_deleted
257
+ done
258
+ end # it
259
+ end # context
260
+
261
+
262
+ context "when exchange is declared without explicit :nowait parameter" do
263
+ it "is declared with :nowait by default" do
264
+ exchange = @channel.fanout("a new non-auto-deleted fanout exchange", :auto_delete => false)
265
+
266
+ exchange.should_not be_auto_deleted
267
+ done
268
+ end # it
269
+ end # context
270
+
271
+
272
+ context "when exchange is re-declared with parameters different from original declaration" do
273
+ it "raises an exception" do
274
+ @channel.fanout("previously.declared.durable.topic.exchange", :durable => true)
275
+
276
+ expect {
277
+ @channel.fanout("previously.declared.durable.topic.exchange", :durable => false)
278
+ }.to raise_error(MQ::IncompatibleOptionsError)
279
+
280
+ done
281
+ end # it
282
+ end # context
283
+ end # describe
284
+
285
+
286
+
287
+
288
+ describe "#topic" do
289
+ context "when exchange name is specified" do
290
+ let(:name) { "a.topic.exchange" }
291
+
292
+ it "declares a new topic exchange with that name" do
293
+ exchange = @channel.topic(name)
294
+ exchange.name.should == name
295
+
296
+ done
297
+ end
298
+ end # context
299
+
300
+ context "when exchange name is omitted" do
301
+ it "uses amq.topic" do
302
+ exchange = @channel.topic
303
+ exchange.name.should == "amq.topic"
304
+ exchange.name.should_not == "amq.topic2"
305
+
306
+ done
307
+ end
308
+ end # context
309
+
310
+ context "when passive option is used" do
311
+ context "and exchange with given name already exists" do
312
+ it "silently returns" do
313
+ name = "a_new_topic_exchange declared at #{Time.now.to_i}"
314
+
315
+ original_exchange = @channel.topic(name)
316
+ exchange = @channel.topic(name, :passive => true)
317
+
318
+ exchange.should == original_exchange
319
+
320
+ done
321
+ end # it
322
+ end
323
+
324
+ context "and exchange with given name DOES NOT exist" do
325
+ it "raises an exception" do
326
+ pending "Not yet supported"
327
+
328
+ expect {
329
+ exchange = @channel.topic("topic exchange declared at #{Time.now.to_i}", :passive => true)
330
+ }.to raise_error
331
+
332
+ done
333
+ end # it
334
+ end # context
335
+ end # context
336
+
337
+
338
+ context "when exchange is declared as durable" do
339
+ it "returns a new durable topic exchange" do
340
+ exchange = @channel.topic("a_new_durable_topic_exchange", :durable => true)
341
+ exchange.should be_durable
342
+ exchange.should_not be_transient
343
+
344
+ done
345
+ end # it
346
+ end # context
347
+
348
+
349
+ context "when exchange is declared as non-durable" do
350
+ it "returns a new NON-durable topic exchange" do
351
+ exchange = @channel.topic("a_new_non_durable_topic_exchange", :durable => false)
352
+ exchange.should_not be_durable
353
+ exchange.should be_transient
354
+
355
+ done
356
+ end # it
357
+ end # context
358
+
359
+
360
+ context "when exchange is declared as auto-deleted" do
361
+ it "returns a new auto-deleted topic exchange" do
362
+ exchange = @channel.topic("a new auto-deleted topic exchange", :auto_delete => true)
363
+
364
+ exchange.should be_auto_deleted
365
+ done
366
+ end # it
367
+ end # context
368
+
369
+
370
+ context "when exchange is declared as auto-deleted" do
371
+ it "returns a new auto-deleted topic exchange" do
372
+ exchange = @channel.topic("a new non-auto-deleted topic exchange", :auto_delete => false)
373
+
374
+ exchange.should_not be_auto_deleted
375
+ done
376
+ end # it
377
+ end # context
378
+
379
+
380
+ context "when exchange is declared without explicit :nowait parameter" do
381
+ it "is declared with :nowait by default" do
382
+ exchange = @channel.topic("a new non-auto-deleted topic exchange", :auto_delete => false)
383
+
384
+ exchange.should_not be_auto_deleted
385
+ done
386
+ end # it
387
+ end # context
388
+
389
+
390
+ context "when exchange is re-declared with parameters different from original declaration" do
391
+ xit "raises an exception" do
392
+ @channel.topic("previously.declared.durable.topic.exchange", :durable => true)
393
+
394
+ expect {
395
+ @channel.topic("previously.declared.durable.topic.exchange", :durable => false)
396
+ }.to raise_error(MQ::IncompatibleOptionsError)
397
+
398
+ done
399
+ end # it
400
+ end # context
401
+ end # describe
402
+
403
+
404
+
405
+
406
+ describe "#headers" do
407
+ context "when exchange name is specified" do
408
+ let(:name) { "new.headers.exchange" }
409
+
410
+ it "declares a new headers exchange with that name" do
411
+ exchange = @channel.headers(name)
412
+
413
+ exchange.name.should == name
414
+
415
+ done
416
+ end
417
+ end # context
418
+
419
+ context "when exchange name is omitted" do
420
+ xit "uses amq.match" do
421
+ pending "Times out. MK."
422
+
423
+ exchange = @channel.headers
424
+ exchange.name.should == "amq.match"
425
+ exchange.name.should_not == "amq.headers"
426
+
427
+ done
428
+ end
429
+ end # context
430
+
431
+ context "when passive option is used" do
432
+ context "and exchange with given name already exists" do
433
+ it "silently returns" do
434
+ name = "a_new_headers_exchange declared at #{Time.now.to_i}"
435
+
436
+ original_exchange = @channel.headers(name)
437
+ exchange = @channel.headers(name, :passive => true)
438
+
439
+ exchange.should == original_exchange
440
+
441
+ done
442
+ end # it
443
+ end
444
+
445
+ context "and exchange with given name DOES NOT exist" do
446
+ it "raises an exception" do
447
+ pending "Not yet supported"
448
+
449
+ expect {
450
+ exchange = @channel.headers("headers exchange declared at #{Time.now.to_i}", :passive => true)
451
+ }.to raise_error
452
+
453
+ done
454
+ end # it
455
+ end # context
456
+ end # context
457
+
458
+
459
+ context "when exchange is declared as durable" do
460
+ it "returns a new durable headers exchange" do
461
+ exchange = @channel.headers("a_new_durable_headers_exchange", :durable => true)
462
+ exchange.should be_durable
463
+ exchange.should_not be_transient
464
+
465
+ done
466
+ end # it
467
+ end # context
468
+
469
+
470
+ context "when exchange is declared as non-durable" do
471
+ it "returns a new NON-durable headers exchange" do
472
+ exchange = @channel.headers("a_new_non_durable_headers_exchange", :durable => false)
473
+ exchange.should_not be_durable
474
+ exchange.should be_transient
475
+
476
+ done
477
+ end # it
478
+ end # context
479
+
480
+
481
+ context "when exchange is declared as auto-deleted" do
482
+ it "returns a new auto-deleted headers exchange" do
483
+ exchange = @channel.headers("a new auto-deleted headers exchange", :auto_delete => true)
484
+
485
+ exchange.should be_auto_deleted
486
+ done
487
+ end # it
488
+ end # context
489
+
490
+
491
+ context "when exchange is declared as auto-deleted" do
492
+ it "returns a new auto-deleted headers exchange" do
493
+ exchange = @channel.headers("a new non-auto-deleted headers exchange", :auto_delete => false)
494
+
495
+ exchange.should_not be_auto_deleted
496
+ done
497
+ end # it
498
+ end # context
499
+
500
+
501
+ context "when exchange is declared without explicit :nowait parameter" do
502
+ it "is declared with :nowait by default" do
503
+ exchange = @channel.headers("a new non-auto-deleted headers exchange", :auto_delete => false)
504
+
505
+ exchange.should_not be_auto_deleted
506
+ done
507
+ end # it
508
+ end # context
509
+
510
+
511
+ context "when exchange is re-declared with parameters different from original declaration" do
512
+ xit "raises an exception" do
513
+ pending "Times out. MK."
514
+ @channel.headers("previously.declared.durable.topic.exchange", :durable => true)
515
+
516
+ expect {
517
+ @channel.headers("previously.declared.durable.topic.exchange", :durable => false)
518
+ }.to raise_error(MQ::IncompatibleOptionsError)
519
+
520
+ done
521
+ end # it
522
+ end # context
523
+ end # describe
524
+ end # describe MQ