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.
- data/.gitignore +3 -2
- data/CHANGELOG +25 -0
- data/Gemfile +4 -2
- data/README.md +2 -0
- data/{amqp.todo → TODO} +1 -3
- data/amqp.gemspec +3 -3
- data/bin/irb +2 -2
- data/bin/jenkins.sh +25 -0
- data/bin/set_test_suite_realms_up.sh +21 -0
- data/doc/EXAMPLE_01_PINGPONG +1 -1
- data/doc/EXAMPLE_02_CLOCK +1 -1
- data/doc/EXAMPLE_03_STOCKS +1 -1
- data/doc/EXAMPLE_04_MULTICLOCK +1 -1
- data/doc/EXAMPLE_05_ACK +1 -1
- data/doc/EXAMPLE_05_POP +1 -1
- data/doc/EXAMPLE_06_HASHTABLE +1 -1
- data/examples/{mq/ack.rb → ack.rb} +6 -6
- data/examples/{mq/automatic_binding_for_default_direct_exchange.rb → automatic_binding_for_default_direct_exchange.rb} +4 -4
- data/examples/{mq/callbacks.rb → callbacks.rb} +2 -2
- data/examples/{mq/clock.rb → clock.rb} +5 -5
- data/examples/{mq/hashtable.rb → hashtable.rb} +4 -4
- data/examples/{mq/internal.rb → internal.rb} +5 -5
- data/examples/{mq/logger.rb → logger.rb} +5 -5
- data/examples/{mq/multiclock.rb → multiclock.rb} +4 -4
- data/examples/{mq/pingpong.rb → pingpong.rb} +5 -5
- data/examples/{mq/pop.rb → pop.rb} +3 -3
- data/examples/{mq/primes-simple.rb → primes-simple.rb} +0 -0
- data/examples/{mq/primes.rb → primes.rb} +6 -6
- data/examples/{amqp/simple.rb → simple.rb} +1 -1
- data/examples/{mq/stocks.rb → stocks.rb} +5 -5
- data/lib/amqp.rb +8 -112
- data/lib/amqp/basic_client.rb +58 -0
- data/lib/amqp/channel.rb +937 -0
- data/lib/amqp/client.rb +72 -79
- data/lib/{mq → amqp}/collection.rb +12 -2
- data/lib/amqp/connection.rb +115 -0
- data/lib/amqp/exceptions.rb +18 -0
- data/lib/{mq → amqp}/exchange.rb +32 -34
- data/lib/{ext → amqp/ext}/em.rb +1 -1
- data/lib/{ext → amqp/ext}/emfork.rb +0 -0
- data/lib/amqp/frame.rb +3 -3
- data/lib/{mq → amqp}/header.rb +5 -11
- data/lib/{mq → amqp}/logger.rb +2 -2
- data/lib/amqp/protocol.rb +2 -2
- data/lib/{mq → amqp}/queue.rb +20 -17
- data/lib/{mq → amqp}/rpc.rb +20 -8
- data/lib/amqp/server.rb +1 -1
- data/lib/amqp/version.rb +1 -1
- data/lib/mq.rb +20 -964
- data/protocol/codegen.rb +1 -1
- data/research/api.rb +3 -3
- data/research/primes-forked.rb +5 -5
- data/research/primes-processes.rb +5 -5
- data/research/primes-threaded.rb +5 -5
- data/spec/integration/authentication_spec.rb +114 -0
- data/spec/integration/automatic_binding_for_default_direct_exchange_spec.rb +13 -12
- data/spec/{unit/mq → integration}/channel_close_spec.rb +2 -2
- data/spec/{unit/mq → integration}/exchange_declaration_spec.rb +26 -14
- data/spec/{unit/mq → integration}/queue_declaration_spec.rb +4 -4
- data/spec/integration/queue_exclusivity_spec.rb +95 -0
- data/spec/integration/reply_queue_communication_spec.rb +63 -0
- data/spec/integration/store_and_forward_spec.rb +121 -0
- data/spec/integration/topic_subscription_spec.rb +193 -0
- data/spec/integration/workload_distribution_spec.rb +245 -0
- data/spec/spec_helper.rb +16 -32
- data/spec/unit/{mq/mq_basic_spec.rb → amqp/basic_spec.rb} +4 -4
- data/spec/unit/{mq → amqp}/collection_spec.rb +22 -7
- data/spec/unit/amqp/connection_spec.rb +116 -0
- data/spec/unit/amqp/frame_spec.rb +18 -18
- data/spec/unit/amqp/protocol_spec.rb +9 -11
- metadata +54 -49
- data/lib/ext/blankslate.rb +0 -9
- data/spec/mq_helper.rb +0 -70
- data/spec/unit/amqp/client_spec.rb +0 -472
- data/spec/unit/amqp/misc_spec.rb +0 -123
- data/spec/unit/mq/misc_spec.rb +0 -228
- data/spec/unit/mq/queue_spec.rb +0 -71
data/spec/unit/amqp/misc_spec.rb
DELETED
@@ -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
|
data/spec/unit/mq/misc_spec.rb
DELETED
@@ -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"
|
data/spec/unit/mq/queue_spec.rb
DELETED
@@ -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
|