amqp 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
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