amqp 0.7.0 → 0.7.1

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 (77) hide show
  1. data/.gitignore +3 -2
  2. data/CHANGELOG +25 -0
  3. data/Gemfile +4 -2
  4. data/README.md +2 -0
  5. data/{amqp.todo → TODO} +1 -3
  6. data/amqp.gemspec +3 -3
  7. data/bin/irb +2 -2
  8. data/bin/jenkins.sh +25 -0
  9. data/bin/set_test_suite_realms_up.sh +21 -0
  10. data/doc/EXAMPLE_01_PINGPONG +1 -1
  11. data/doc/EXAMPLE_02_CLOCK +1 -1
  12. data/doc/EXAMPLE_03_STOCKS +1 -1
  13. data/doc/EXAMPLE_04_MULTICLOCK +1 -1
  14. data/doc/EXAMPLE_05_ACK +1 -1
  15. data/doc/EXAMPLE_05_POP +1 -1
  16. data/doc/EXAMPLE_06_HASHTABLE +1 -1
  17. data/examples/{mq/ack.rb → ack.rb} +6 -6
  18. data/examples/{mq/automatic_binding_for_default_direct_exchange.rb → automatic_binding_for_default_direct_exchange.rb} +4 -4
  19. data/examples/{mq/callbacks.rb → callbacks.rb} +2 -2
  20. data/examples/{mq/clock.rb → clock.rb} +5 -5
  21. data/examples/{mq/hashtable.rb → hashtable.rb} +4 -4
  22. data/examples/{mq/internal.rb → internal.rb} +5 -5
  23. data/examples/{mq/logger.rb → logger.rb} +5 -5
  24. data/examples/{mq/multiclock.rb → multiclock.rb} +4 -4
  25. data/examples/{mq/pingpong.rb → pingpong.rb} +5 -5
  26. data/examples/{mq/pop.rb → pop.rb} +3 -3
  27. data/examples/{mq/primes-simple.rb → primes-simple.rb} +0 -0
  28. data/examples/{mq/primes.rb → primes.rb} +6 -6
  29. data/examples/{amqp/simple.rb → simple.rb} +1 -1
  30. data/examples/{mq/stocks.rb → stocks.rb} +5 -5
  31. data/lib/amqp.rb +8 -112
  32. data/lib/amqp/basic_client.rb +58 -0
  33. data/lib/amqp/channel.rb +937 -0
  34. data/lib/amqp/client.rb +72 -79
  35. data/lib/{mq → amqp}/collection.rb +12 -2
  36. data/lib/amqp/connection.rb +115 -0
  37. data/lib/amqp/exceptions.rb +18 -0
  38. data/lib/{mq → amqp}/exchange.rb +32 -34
  39. data/lib/{ext → amqp/ext}/em.rb +1 -1
  40. data/lib/{ext → amqp/ext}/emfork.rb +0 -0
  41. data/lib/amqp/frame.rb +3 -3
  42. data/lib/{mq → amqp}/header.rb +5 -11
  43. data/lib/{mq → amqp}/logger.rb +2 -2
  44. data/lib/amqp/protocol.rb +2 -2
  45. data/lib/{mq → amqp}/queue.rb +20 -17
  46. data/lib/{mq → amqp}/rpc.rb +20 -8
  47. data/lib/amqp/server.rb +1 -1
  48. data/lib/amqp/version.rb +1 -1
  49. data/lib/mq.rb +20 -964
  50. data/protocol/codegen.rb +1 -1
  51. data/research/api.rb +3 -3
  52. data/research/primes-forked.rb +5 -5
  53. data/research/primes-processes.rb +5 -5
  54. data/research/primes-threaded.rb +5 -5
  55. data/spec/integration/authentication_spec.rb +114 -0
  56. data/spec/integration/automatic_binding_for_default_direct_exchange_spec.rb +13 -12
  57. data/spec/{unit/mq → integration}/channel_close_spec.rb +2 -2
  58. data/spec/{unit/mq → integration}/exchange_declaration_spec.rb +26 -14
  59. data/spec/{unit/mq → integration}/queue_declaration_spec.rb +4 -4
  60. data/spec/integration/queue_exclusivity_spec.rb +95 -0
  61. data/spec/integration/reply_queue_communication_spec.rb +63 -0
  62. data/spec/integration/store_and_forward_spec.rb +121 -0
  63. data/spec/integration/topic_subscription_spec.rb +193 -0
  64. data/spec/integration/workload_distribution_spec.rb +245 -0
  65. data/spec/spec_helper.rb +16 -32
  66. data/spec/unit/{mq/mq_basic_spec.rb → amqp/basic_spec.rb} +4 -4
  67. data/spec/unit/{mq → amqp}/collection_spec.rb +22 -7
  68. data/spec/unit/amqp/connection_spec.rb +116 -0
  69. data/spec/unit/amqp/frame_spec.rb +18 -18
  70. data/spec/unit/amqp/protocol_spec.rb +9 -11
  71. metadata +54 -49
  72. data/lib/ext/blankslate.rb +0 -9
  73. data/spec/mq_helper.rb +0 -70
  74. data/spec/unit/amqp/client_spec.rb +0 -472
  75. data/spec/unit/amqp/misc_spec.rb +0 -123
  76. data/spec/unit/mq/misc_spec.rb +0 -228
  77. data/spec/unit/mq/queue_spec.rb +0 -71
@@ -1,123 +0,0 @@
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
@@ -1,228 +0,0 @@
1
- require 'spec_helper'
2
- require 'mq_helper'
3
-
4
- describe 'MQ', 'class object' do
5
- # after{AMQP.cleanup_state} # Tips off Thread.current[:mq] call
6
- subject { MQ }
7
-
8
- its(:logging) { should be_false }
9
-
10
-
11
- describe '.logging=' do
12
- it 'is independent from AMQP.logging' do
13
- #
14
- AMQP.logging = true
15
- MQ.logging.should be_false
16
- MQ.logging = false
17
- AMQP.logging.should == true
18
-
19
- #
20
- AMQP.logging = false
21
- MQ.logging = true
22
- AMQP.logging.should be_false
23
- MQ.logging = false
24
- end
25
- end # .logging=
26
-
27
-
28
- describe '.default' do
29
- it 'creates MQ object and stashes it in a Thread-local Hash' do
30
- MQ.should_receive(:new).with(no_args).and_return('MQ mock')
31
- Thread.current.should_receive(:[]).with(:mq)
32
- Thread.current.should_receive(:[]=).with(:mq, 'MQ mock')
33
- MQ.default.should == 'MQ mock'
34
- end
35
- end # .default
36
-
37
-
38
-
39
- describe '.id' do
40
- it 'returns Thread-local uuid for mq' do
41
- uuid_pattern = /.*-[0-9]*-[0-9]*/
42
- Thread.current.should_receive(:[]).with(:mq_id)
43
- Thread.current.should_receive(:[]=).with(:mq_id, uuid_pattern)
44
- MQ.id.should =~ uuid_pattern
45
- end
46
- end # .id
47
-
48
-
49
-
50
- describe '.error' do
51
- after(:all) { MQ.instance_variable_set(:@error_callback, nil) } # clear error callback
52
-
53
- it 'is noop unless @error_callback was previously set' do
54
- MQ.instance_variable_get(:@error_callback).should be_nil
55
- MQ.error("Msg").should be_nil
56
- end
57
-
58
- context 'when @error_callback is set' do
59
- before { MQ.error { |message| message.should == "Msg"; @callback_fired = true } }
60
-
61
- it 'is setting @error_callback to given block' do
62
- MQ.instance_variable_get(:@error_callback).should_not be_nil
63
- @callback_fired.should be_false
64
- end
65
-
66
- it 'does not fire @error_callback immediately' do
67
- @callback_fired.should be_false
68
- end
69
-
70
- it 'fires @error_callback on subsequent .error calls' do
71
- MQ.error("Msg")
72
- @callback_fired.should be_true
73
- end
74
- end
75
- end # .error
76
-
77
-
78
-
79
- describe '.method_missing' do
80
- it 'routes all unrecognized methods to MQ.default' do
81
- MQ.should_receive(:new).with(no_args).and_return(mock('channel'))
82
- MQ.default.should_receive(:foo).with("Msg")
83
- MQ.foo("Msg")
84
- end
85
- end # .method_missing
86
- end # describe 'MQ as a class'
87
-
88
-
89
-
90
-
91
- describe 'Channel object' do
92
- context 'when initialized with a mock connection' do
93
- before { @client = MockConnection.new }
94
- after { AMQP.cleanup_state }
95
- subject { MQ.new(@client).tap { |mq| mq.succeed } } # Indicates that channel is connected
96
-
97
- it 'should have a channel' do
98
- subject.channel.should be_kind_of Fixnum
99
- subject.channel.should == 1 # Essentially, this channel (mq) number
100
- end
101
-
102
- it 'has publicly accessible collections' do
103
- subject.exchanges.should be_empty
104
- subject.queues.should be_empty
105
- subject.consumers.should be_empty
106
- subject.rpcs.should be_empty
107
- end
108
-
109
- describe '#send' do
110
- it 'sends given data through its connection' do
111
- args = [ 'data1', 'data2', 'data3']
112
- subject.send *args
113
- @client.messages[-3..-1].map { |message| message[:data] }.should == args
114
- end #send
115
-
116
- it 'sets data`s ticket property if @ticket is set for MQ object' do
117
- ticket = subject_mock(:@ticket)
118
- data = mock('data')
119
- data.should_receive(:ticket=).with(ticket)
120
- subject.send data
121
- end
122
- end
123
-
124
-
125
-
126
- describe '#reset' do
127
- it 'resets and reinitializes the channel, clears and resets its queues/exchanges' do
128
- subject.queue('test').should_receive(:reset)
129
- subject.fanout('fanout').should_receive(:reset)
130
- subject.should_receive(:initialize).with(@client)
131
-
132
- subject.reset
133
- subject.queues.should be_empty
134
- subject.exchanges.should be_empty
135
- subject.consumers.should be_empty
136
- end
137
- end #reset
138
-
139
-
140
-
141
- describe '#prefetch', 'setting :prefetch_count for broker' do
142
- it 'sends Protocol::Basic::Qos' do
143
- subject.prefetch 13
144
- @client.messages.last[:data].should be_an AMQP::Protocol::Basic::Qos
145
- @client.messages.last[:data].instance_variable_get(:@prefetch_count).should == 13
146
- end
147
-
148
- it 'returns MQ object itself, allowing for method chains' do
149
- subject.prefetch(1).should == subject
150
- end
151
- end #prefetch
152
-
153
-
154
-
155
- describe '#recover', "asks broker to redeliver unack'ed messages on this channel" do
156
- it "sends Basic::Recover through @connection" do
157
- subject.recover
158
- @client.messages.last[:data].should be_an AMQP::Protocol::Basic::Recover
159
- end
160
-
161
- it 'defaults to :requeue=nil, redeliver messages to the original recipient' do
162
- subject.recover
163
- @client.messages.last[:data].instance_variable_get(:@requeue).should == nil
164
- end #prefetch
165
-
166
- it 'prompts broker to requeue messages (to other subs) if :requeue set to true' do
167
- subject.recover true
168
- @client.messages.last[:data].instance_variable_get(:@requeue).should == true
169
- end
170
-
171
- it 'returns MQ object itself, allowing for method chains' do
172
- subject.recover.should == subject
173
- end
174
- end #recover
175
-
176
-
177
-
178
- describe '#close', 'closes channel' do
179
- it 'can be simplified, getting rid of @closing ivar?'
180
- # TODO: Just set a callback sending Protocol::Channel::Close...'
181
-
182
- it 'sends Channel::Close through @connection' do
183
- subject.close
184
- @client.messages.last[:data].should be_an AMQP::Protocol::Channel::Close
185
- end
186
-
187
- it 'does not actually delete the channel or close connection' do
188
- @client.channels.should_not_receive(:delete)
189
- @client.should_not_receive(:close)
190
- subject.close
191
- end
192
-
193
- it 'actual channel closing happens ONLY when Channel::CloseOk is received' do
194
- @client.channels.should_receive(:delete) do |key|
195
- key.should == 1
196
- @client.channels.clear
197
- end
198
- @client.should_receive(:close)
199
- subject.process_frame AMQP::Frame::Method.new(AMQP::Protocol::Channel::CloseOk.new)
200
- end
201
- end #close
202
-
203
-
204
-
205
-
206
- describe '#get_queue', 'supports #pop (Basic::Get) operation on queues' do
207
- it 'yields a FIFO queue to a given block' do
208
- subject.get_queue do |fifo|
209
- @block_called = true
210
- fifo.should == []
211
- end
212
- @block_called.should be_true
213
- end
214
-
215
- it 'FIFO queue contains consumers that called Queue#pop' do
216
- queue1 = subject.queue('test1')
217
- queue2 = subject.queue('test2')
218
- queue1.pop
219
- queue2.pop
220
- subject.get_queue do |fifo|
221
- fifo.should have(2).consumers
222
- fifo.first.should == queue1
223
- fifo.last.should == queue2
224
- end
225
- end
226
- end #get_queue
227
- end # context 'when initialized with a mock connection'
228
- end # describe MQ object, also vaguely known as "channel"
@@ -1,71 +0,0 @@
1
- require 'spec_helper'
2
- require 'mq_helper'
3
-
4
- describe MQ::Queue, :broker => true do
5
-
6
- #
7
- # Environment
8
- #
9
-
10
- include AMQP::Spec
11
-
12
- default_options AMQP_OPTS
13
- default_timeout 3
14
-
15
- amqp_before do
16
- @channel = MQ.new
17
- @queue = MQ::Queue.new(@channel, 'test_queue', :option => 'useless')
18
- end
19
-
20
- amqp_after { @queue.purge; AMQP.cleanup_state }
21
-
22
-
23
- #
24
- # Examples
25
- #
26
-
27
- context 'declared with name of "test_queue"' do
28
- amqp_after {@queue.unsubscribe; @queue.delete}
29
- # TODO: Fix amqp_after: it is NOT run in case of raised exceptions, it seems
30
-
31
- it 'supports asynchronous subscription to broker-predefined amq.direct exchange' do
32
- data = "data sent via amq.direct exchange"
33
-
34
- @queue.subscribe do |header, message|
35
- header.should be_an MQ::Header
36
- message.should == data
37
- done
38
- end
39
- @queue.publish(data)
40
- end # it
41
-
42
- it 'supports synchronous message fetching via #pop (Basic.Get)' do
43
- @queue.publish('send some data down the pipe')
44
-
45
- @queue.pop do |header, message|
46
- header.should be_an MQ::Header
47
- message.should == 'send some data down the pipe'
48
- done
49
- end
50
- end # it
51
-
52
- xit 'asynchronously receives own status from the broker' do
53
- pending "TODO: this example currently fails; do investigate why. MK."
54
- total_number_of_messages = 123
55
-
56
- total_number_of_messages.times do |n|
57
- @queue.publish('message # #{n}')
58
- end
59
-
60
- @on_status_fired = false
61
- @queue.status do |messages, consumers|
62
- @on_status_fired = true
63
- messages.should == total_number_of_messages
64
- consumers.should == 0
65
- end # it
66
-
67
- @on_status_fired.should be_true
68
- done(1)
69
- end # it
70
- end # context
71
- end # MQ::Queue, 'with real connection