fotonauts-bunny 0.4.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.
- data/LICENSE +20 -0
- data/README +52 -0
- data/Rakefile +6 -0
- data/bunny.gemspec +38 -0
- data/examples/simple.rb +30 -0
- data/examples/simple_ack.rb +33 -0
- data/examples/simple_consumer.rb +55 -0
- data/examples/simple_fanout.rb +39 -0
- data/examples/simple_publisher.rb +27 -0
- data/examples/simple_topic.rb +59 -0
- data/lib/bunny/client.rb +324 -0
- data/lib/bunny/exchange.rb +158 -0
- data/lib/bunny/queue.rb +410 -0
- data/lib/bunny.rb +37 -0
- data/lib/qrack/client.rb +5 -0
- data/lib/qrack/protocol/protocol.rb +135 -0
- data/lib/qrack/protocol/spec.rb +822 -0
- data/lib/qrack/qrack.rb +28 -0
- data/lib/qrack/transport/buffer.rb +267 -0
- data/lib/qrack/transport/frame.rb +100 -0
- data/spec/bunny_spec.rb +36 -0
- data/spec/exchange_spec.rb +117 -0
- data/spec/queue_spec.rb +90 -0
- metadata +76 -0
data/lib/qrack/qrack.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
$: << File.expand_path(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
require 'protocol/spec'
|
4
|
+
require 'protocol/protocol'
|
5
|
+
|
6
|
+
require 'transport/buffer'
|
7
|
+
require 'transport/frame'
|
8
|
+
|
9
|
+
require 'client'
|
10
|
+
|
11
|
+
module Qrack
|
12
|
+
|
13
|
+
include Protocol
|
14
|
+
include Transport
|
15
|
+
|
16
|
+
# Errors
|
17
|
+
class BufferOverflowError < StandardError; end
|
18
|
+
class InvalidTypeError < StandardError; end
|
19
|
+
|
20
|
+
# Qrack version number
|
21
|
+
VERSION = '0.0.1'
|
22
|
+
|
23
|
+
# Return the Qrack version
|
24
|
+
def self.version
|
25
|
+
VERSION
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,267 @@
|
|
1
|
+
module Qrack
|
2
|
+
module Transport #:nodoc: all
|
3
|
+
class Buffer
|
4
|
+
require 'enumerator' if RUBY_VERSION < '1.8.7'
|
5
|
+
|
6
|
+
def initialize data = ''
|
7
|
+
@data = data
|
8
|
+
@pos = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :pos
|
12
|
+
|
13
|
+
def data
|
14
|
+
@data.clone
|
15
|
+
end
|
16
|
+
alias :contents :data
|
17
|
+
alias :to_s :data
|
18
|
+
|
19
|
+
def << data
|
20
|
+
@data << data.to_s
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def length
|
25
|
+
@data.length
|
26
|
+
end
|
27
|
+
|
28
|
+
def empty?
|
29
|
+
pos == length
|
30
|
+
end
|
31
|
+
|
32
|
+
def rewind
|
33
|
+
@pos = 0
|
34
|
+
end
|
35
|
+
|
36
|
+
def read_properties *types
|
37
|
+
types.shift if types.first == :properties
|
38
|
+
|
39
|
+
i = 0
|
40
|
+
values = []
|
41
|
+
|
42
|
+
while props = read(:short)
|
43
|
+
(0..14).each do |n|
|
44
|
+
# no more property types
|
45
|
+
break unless types[i]
|
46
|
+
|
47
|
+
# if flag is set
|
48
|
+
if props & (1<<(15-n)) != 0
|
49
|
+
if types[i] == :bit
|
50
|
+
# bit values exist in flags only
|
51
|
+
values << true
|
52
|
+
else
|
53
|
+
# save type name for later reading
|
54
|
+
values << types[i]
|
55
|
+
end
|
56
|
+
else
|
57
|
+
# property not set or is false bit
|
58
|
+
values << (types[i] == :bit ? false : nil)
|
59
|
+
end
|
60
|
+
|
61
|
+
i+=1
|
62
|
+
end
|
63
|
+
|
64
|
+
# bit(0) == 0 means no more property flags
|
65
|
+
break unless props & 1 == 1
|
66
|
+
end
|
67
|
+
|
68
|
+
values.map do |value|
|
69
|
+
value.is_a?(Symbol) ? read(value) : value
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def read *types
|
74
|
+
if types.first == :properties
|
75
|
+
return read_properties(*types)
|
76
|
+
end
|
77
|
+
|
78
|
+
values = types.map do |type|
|
79
|
+
case type
|
80
|
+
when :octet
|
81
|
+
_read(1, 'C')
|
82
|
+
when :short
|
83
|
+
_read(2, 'n')
|
84
|
+
when :long
|
85
|
+
_read(4, 'N')
|
86
|
+
when :longlong
|
87
|
+
upper, lower = _read(8, 'NN')
|
88
|
+
upper << 32 | lower
|
89
|
+
when :shortstr
|
90
|
+
_read read(:octet)
|
91
|
+
when :longstr
|
92
|
+
_read read(:long)
|
93
|
+
when :timestamp
|
94
|
+
Time.at read(:longlong)
|
95
|
+
when :table
|
96
|
+
t = Hash.new
|
97
|
+
|
98
|
+
table = Buffer.new(read(:longstr))
|
99
|
+
until table.empty?
|
100
|
+
key, type = table.read(:shortstr, :octet)
|
101
|
+
key = key.intern
|
102
|
+
t[key] ||= case type
|
103
|
+
when 83 # 'S'
|
104
|
+
table.read(:longstr)
|
105
|
+
when 73 # 'I'
|
106
|
+
table.read(:long)
|
107
|
+
when 68 # 'D'
|
108
|
+
exp = table.read(:octet)
|
109
|
+
num = table.read(:long)
|
110
|
+
num / 10.0**exp
|
111
|
+
when 84 # 'T'
|
112
|
+
table.read(:timestamp)
|
113
|
+
when 70 # 'F'
|
114
|
+
table.read(:table)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
t
|
119
|
+
when :bit
|
120
|
+
if (@bits ||= []).empty?
|
121
|
+
val = read(:octet)
|
122
|
+
@bits = (0..7).map{|i| (val & 1<<i) != 0 }
|
123
|
+
end
|
124
|
+
|
125
|
+
@bits.shift
|
126
|
+
else
|
127
|
+
raise Qrack::InvalidTypeError, "Cannot read data of type #{type}"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
types.size == 1 ? values.first : values
|
132
|
+
end
|
133
|
+
|
134
|
+
def write type, data
|
135
|
+
case type
|
136
|
+
when :octet
|
137
|
+
_write(data, 'C')
|
138
|
+
when :short
|
139
|
+
_write(data, 'n')
|
140
|
+
when :long
|
141
|
+
_write(data, 'N')
|
142
|
+
when :longlong
|
143
|
+
lower = data & 0xffffffff
|
144
|
+
upper = (data & ~0xffffffff) >> 32
|
145
|
+
_write([upper, lower], 'NN')
|
146
|
+
when :shortstr
|
147
|
+
data = (data || '').to_s
|
148
|
+
_write([data.length, data], 'Ca*')
|
149
|
+
when :longstr
|
150
|
+
if data.is_a? Hash
|
151
|
+
write(:table, data)
|
152
|
+
else
|
153
|
+
data = (data || '').to_s
|
154
|
+
_write([data.length, data], 'Na*')
|
155
|
+
end
|
156
|
+
when :timestamp
|
157
|
+
write(:longlong, data.to_i)
|
158
|
+
when :table
|
159
|
+
data ||= {}
|
160
|
+
write :longstr, (data.inject(Buffer.new) do |table, (key, value)|
|
161
|
+
table.write(:shortstr, key.to_s)
|
162
|
+
|
163
|
+
case value
|
164
|
+
when String
|
165
|
+
table.write(:octet, 83) # 'S'
|
166
|
+
table.write(:longstr, value.to_s)
|
167
|
+
when Fixnum
|
168
|
+
table.write(:octet, 73) # 'I'
|
169
|
+
table.write(:long, value)
|
170
|
+
when Float
|
171
|
+
table.write(:octet, 68) # 'D'
|
172
|
+
# XXX there's gotta be a better way to do this..
|
173
|
+
exp = value.to_s.split('.').last.length
|
174
|
+
num = value * 10**exp
|
175
|
+
table.write(:octet, exp)
|
176
|
+
table.write(:long, num)
|
177
|
+
when Time
|
178
|
+
table.write(:octet, 84) # 'T'
|
179
|
+
table.write(:timestamp, value)
|
180
|
+
when Hash
|
181
|
+
table.write(:octet, 70) # 'F'
|
182
|
+
table.write(:table, value)
|
183
|
+
end
|
184
|
+
|
185
|
+
table
|
186
|
+
end)
|
187
|
+
when :bit
|
188
|
+
[*data].to_enum(:each_slice, 8).each{|bits|
|
189
|
+
write(:octet, bits.enum_with_index.inject(0){ |byte, (bit, i)|
|
190
|
+
byte |= 1<<i if bit
|
191
|
+
byte
|
192
|
+
})
|
193
|
+
}
|
194
|
+
when :properties
|
195
|
+
values = []
|
196
|
+
data.enum_with_index.inject(0) do |short, ((type, value), i)|
|
197
|
+
n = i % 15
|
198
|
+
last = i+1 == data.size
|
199
|
+
|
200
|
+
if (n == 0 and i != 0) or last
|
201
|
+
if data.size > i+1
|
202
|
+
short |= 1<<0
|
203
|
+
elsif last and value
|
204
|
+
values << [type,value]
|
205
|
+
short |= 1<<(15-n)
|
206
|
+
end
|
207
|
+
|
208
|
+
write(:short, short)
|
209
|
+
short = 0
|
210
|
+
end
|
211
|
+
|
212
|
+
if value and !last
|
213
|
+
values << [type,value]
|
214
|
+
short |= 1<<(15-n)
|
215
|
+
end
|
216
|
+
|
217
|
+
short
|
218
|
+
end
|
219
|
+
|
220
|
+
values.each do |type, value|
|
221
|
+
write(type, value) unless type == :bit
|
222
|
+
end
|
223
|
+
else
|
224
|
+
raise Qrack::InvalidTypeError, "Cannot write data of type #{type}"
|
225
|
+
end
|
226
|
+
|
227
|
+
self
|
228
|
+
end
|
229
|
+
|
230
|
+
def extract
|
231
|
+
begin
|
232
|
+
cur_data, cur_pos = @data.clone, @pos
|
233
|
+
yield self
|
234
|
+
rescue Qrack::BufferOverflowError
|
235
|
+
@data, @pos = cur_data, cur_pos
|
236
|
+
nil
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def _read(size, pack = nil)
|
241
|
+
if @data.is_a?(Qrack::Client)
|
242
|
+
raw = @data.read(size)
|
243
|
+
return raw if raw.nil? or pack.nil?
|
244
|
+
return raw.unpack(pack).first
|
245
|
+
end
|
246
|
+
|
247
|
+
if @pos + size > length
|
248
|
+
raise Qrack::BufferOverflowError
|
249
|
+
else
|
250
|
+
data = @data[@pos,size]
|
251
|
+
@data[@pos,size] = ''
|
252
|
+
if pack
|
253
|
+
data = data.unpack(pack)
|
254
|
+
data = data.pop if data.size == 1
|
255
|
+
end
|
256
|
+
data
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def _write data, pack = nil
|
261
|
+
data = [*data].pack(pack) if pack
|
262
|
+
@data[@pos,0] = data
|
263
|
+
@pos += data.length
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
|
2
|
+
#:stopdoc:
|
3
|
+
# this file was autogenerated on Fri May 15 10:11:23 +0100 2009
|
4
|
+
#
|
5
|
+
# DO NOT EDIT! (edit ext/qparser.rb and config.yml instead, and run 'ruby qparser.rb')
|
6
|
+
|
7
|
+
module Qrack
|
8
|
+
module Transport
|
9
|
+
class Frame
|
10
|
+
def self.types
|
11
|
+
@types ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.Frame id
|
15
|
+
(@_base_frames ||= {})[id] ||= Class.new(Frame) do
|
16
|
+
class_eval %[
|
17
|
+
def self.inherited klass
|
18
|
+
klass.const_set(:ID, #{id})
|
19
|
+
Frame.types[#{id}] = klass
|
20
|
+
end
|
21
|
+
]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Method < Frame( 1 ); end
|
26
|
+
class Header < Frame( 2 ); end
|
27
|
+
class Body < Frame( 3 ); end
|
28
|
+
class OobMethod < Frame( 4 ); end
|
29
|
+
class OobHeader < Frame( 5 ); end
|
30
|
+
class OobBody < Frame( 6 ); end
|
31
|
+
class Trace < Frame( 7 ); end
|
32
|
+
class Heartbeat < Frame( 8 ); end
|
33
|
+
|
34
|
+
FOOTER = 206
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module Qrack
|
40
|
+
module Transport
|
41
|
+
class Frame
|
42
|
+
def initialize payload = nil, channel = 0
|
43
|
+
@channel, @payload = channel, payload
|
44
|
+
end
|
45
|
+
attr_accessor :channel, :payload
|
46
|
+
|
47
|
+
def id
|
48
|
+
self.class::ID
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_binary
|
52
|
+
buf = Transport::Buffer.new
|
53
|
+
buf.write :octet, id
|
54
|
+
buf.write :short, channel
|
55
|
+
buf.write :longstr, payload
|
56
|
+
buf.write :octet, Transport::Frame::FOOTER
|
57
|
+
buf.rewind
|
58
|
+
buf
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s
|
62
|
+
to_binary.to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
def == frame
|
66
|
+
[ :id, :channel, :payload ].inject(true) do |eql, field|
|
67
|
+
eql and __send__(field) == frame.__send__(field)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class Method
|
72
|
+
def initialize payload = nil, channel = 0
|
73
|
+
super
|
74
|
+
unless @payload.is_a? Protocol::Class::Method or @payload.nil?
|
75
|
+
@payload = Protocol.parse(@payload)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class Header
|
81
|
+
def initialize payload = nil, channel = 0
|
82
|
+
super
|
83
|
+
unless @payload.is_a? Protocol::Header or @payload.nil?
|
84
|
+
@payload = Protocol::Header.new(@payload)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class Body; end
|
90
|
+
|
91
|
+
def self.parse buf
|
92
|
+
buf = Transport::Buffer.new(buf) unless buf.is_a? Transport::Buffer
|
93
|
+
buf.extract do
|
94
|
+
id, channel, payload, footer = buf.read(:octet, :short, :longstr, :octet)
|
95
|
+
Transport::Frame.types[id].new(payload, channel) if footer == Transport::Frame::FOOTER
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/spec/bunny_spec.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# bunny_spec.rb
|
2
|
+
|
3
|
+
# Assumes that target message broker/server has a user called 'guest' with a password 'guest'
|
4
|
+
# and that it is running on 'localhost'.
|
5
|
+
|
6
|
+
# If this is not the case, please change the 'Bunny.new' call below to include
|
7
|
+
# the relevant arguments e.g. @b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar')
|
8
|
+
|
9
|
+
require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib bunny]))
|
10
|
+
|
11
|
+
describe Bunny do
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
@b = Bunny.new
|
15
|
+
@b.start
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should connect to an AMQP server" do
|
19
|
+
@b.status.should == :connected
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should be able to create an exchange" do
|
23
|
+
exch = @b.exchange('test_exchange')
|
24
|
+
exch.should be_an_instance_of Bunny::Exchange
|
25
|
+
exch.name.should == 'test_exchange'
|
26
|
+
@b.exchanges.has_key?('test_exchange').should be true
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should be able to create a queue" do
|
30
|
+
q = @b.queue('test1')
|
31
|
+
q.should be_an_instance_of Bunny::Queue
|
32
|
+
q.name.should == 'test1'
|
33
|
+
@b.queues.has_key?('test1').should be true
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# exchange_spec.rb
|
2
|
+
|
3
|
+
# Assumes that target message broker/server has a user called 'guest' with a password 'guest'
|
4
|
+
# and that it is running on 'localhost'.
|
5
|
+
|
6
|
+
# If this is not the case, please change the 'Bunny.new' call below to include
|
7
|
+
# the relevant arguments e.g. @b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar')
|
8
|
+
|
9
|
+
require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib bunny]))
|
10
|
+
|
11
|
+
describe Bunny::Exchange do
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
@b = Bunny.new
|
15
|
+
@b.start
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should raise an error if instantiated as non-existent type" do
|
19
|
+
lambda { @b.exchange('bogus_ex', :type => :bogus) }.should raise_error(Bunny::ProtocolError)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should allow a default direct exchange to be instantiated by specifying :type" do
|
23
|
+
exch = @b.exchange('amq.direct', :type => :direct)
|
24
|
+
exch.should be_an_instance_of Bunny::Exchange
|
25
|
+
exch.name.should == 'amq.direct'
|
26
|
+
exch.type.should == :direct
|
27
|
+
@b.exchanges.has_key?('amq.direct').should be true
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should allow a default direct exchange to be instantiated without specifying :type" do
|
31
|
+
exch = @b.exchange('amq.direct')
|
32
|
+
exch.should be_an_instance_of Bunny::Exchange
|
33
|
+
exch.name.should == 'amq.direct'
|
34
|
+
exch.type.should == :direct
|
35
|
+
@b.exchanges.has_key?('amq.direct').should be true
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should allow a default fanout exchange to be instantiated without specifying :type" do
|
39
|
+
exch = @b.exchange('amq.fanout')
|
40
|
+
exch.should be_an_instance_of Bunny::Exchange
|
41
|
+
exch.name.should == 'amq.fanout'
|
42
|
+
exch.type.should == :fanout
|
43
|
+
@b.exchanges.has_key?('amq.fanout').should be true
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should allow a default topic exchange to be instantiated without specifying :type" do
|
47
|
+
exch = @b.exchange('amq.topic')
|
48
|
+
exch.should be_an_instance_of Bunny::Exchange
|
49
|
+
exch.name.should == 'amq.topic'
|
50
|
+
exch.type.should == :topic
|
51
|
+
@b.exchanges.has_key?('amq.topic').should be true
|
52
|
+
end
|
53
|
+
|
54
|
+
# headers exchange not implemented in RabbitMQ yet. Uncomment if target broker/server supports it
|
55
|
+
#
|
56
|
+
#it "should allow a default headers exchange to be instantiated without specifying :type" do
|
57
|
+
# exch = @b.exchange('amq.match')
|
58
|
+
# exch.should be_an_instance_of Bunny::Exchange
|
59
|
+
# exch.name.should == 'amq.match'
|
60
|
+
# exch.type.should == :headers
|
61
|
+
# @b.exchanges.has_key?('amq.match').should be true
|
62
|
+
#end
|
63
|
+
|
64
|
+
it "should create an exchange as direct by default" do
|
65
|
+
exch = @b.exchange('direct_defaultex')
|
66
|
+
exch.should be_an_instance_of Bunny::Exchange
|
67
|
+
exch.name.should == 'direct_defaultex'
|
68
|
+
exch.type.should == :direct
|
69
|
+
@b.exchanges.has_key?('direct_defaultex').should be true
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should be able to be instantiated as a direct exchange" do
|
73
|
+
exch = @b.exchange('direct_exchange', :type => :direct)
|
74
|
+
exch.should be_an_instance_of Bunny::Exchange
|
75
|
+
exch.name.should == 'direct_exchange'
|
76
|
+
exch.type.should == :direct
|
77
|
+
@b.exchanges.has_key?('direct_exchange').should be true
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should be able to be instantiated as a topic exchange" do
|
81
|
+
exch = @b.exchange('topic_exchange', :type => :topic)
|
82
|
+
exch.should be_an_instance_of Bunny::Exchange
|
83
|
+
exch.name.should == 'topic_exchange'
|
84
|
+
exch.type.should == :topic
|
85
|
+
@b.exchanges.has_key?('topic_exchange').should be true
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should be able to be instantiated as a fanout exchange" do
|
89
|
+
exch = @b.exchange('fanout_exchange', :type => :fanout)
|
90
|
+
exch.should be_an_instance_of Bunny::Exchange
|
91
|
+
exch.name.should == 'fanout_exchange'
|
92
|
+
exch.type.should == :fanout
|
93
|
+
@b.exchanges.has_key?('fanout_exchange').should be true
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should ignore the :nowait option when instantiated" do
|
97
|
+
exch = @b.exchange('direct2_exchange', :nowait => true)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should be able to publish a message" do
|
101
|
+
exch = @b.exchange('direct_exchange')
|
102
|
+
exch.publish('This is a published message')
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should be able to be deleted" do
|
106
|
+
exch = @b.exchange('direct_exchange')
|
107
|
+
res = exch.delete
|
108
|
+
res.should == :delete_ok
|
109
|
+
@b.exchanges.has_key?('direct_exchange').should be false
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should ignore the :nowait option when deleted" do
|
113
|
+
exch = @b.exchange('direct2_exchange')
|
114
|
+
exch.delete(:nowait => true)
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
data/spec/queue_spec.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# queue_spec.rb
|
2
|
+
|
3
|
+
# Assumes that target message broker/server has a user called 'guest' with a password 'guest'
|
4
|
+
# and that it is running on 'localhost'.
|
5
|
+
|
6
|
+
# If this is not the case, please change the 'Bunny.new' call below to include
|
7
|
+
# the relevant arguments e.g. @b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar')
|
8
|
+
|
9
|
+
require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib bunny]))
|
10
|
+
|
11
|
+
describe Bunny::Queue do
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
@b = Bunny.new
|
15
|
+
@b.start
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should ignore the :nowait option when instantiated" do
|
19
|
+
q = @b.queue('test0', :nowait => true)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should ignore the :nowait option when binding to an exchange" do
|
23
|
+
exch = @b.exchange('direct_exch')
|
24
|
+
q = @b.queue('test0')
|
25
|
+
q.bind(exch, :nowait => true).should == :bind_ok
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should be able to bind to an exchange" do
|
29
|
+
exch = @b.exchange('direct_exch')
|
30
|
+
q = @b.queue('test1')
|
31
|
+
q.bind(exch).should == :bind_ok
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should ignore the :nowait option when unbinding from an exchange" do
|
35
|
+
exch = @b.exchange('direct_exch')
|
36
|
+
q = @b.queue('test0')
|
37
|
+
q.unbind(exch, :nowait => true).should == :unbind_ok
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should be able to unbind from an exchange" do
|
41
|
+
exch = @b.exchange('direct_exch')
|
42
|
+
q = @b.queue('test1')
|
43
|
+
q.unbind(exch).should == :unbind_ok
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should be able to publish a message" do
|
47
|
+
q = @b.queue('test1')
|
48
|
+
q.publish('This is a test message')
|
49
|
+
q.message_count.should == 1
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should be able to pop a message complete with header and delivery details" do
|
53
|
+
q = @b.queue('test1')
|
54
|
+
msg = q.pop(:header => true)
|
55
|
+
msg.should be_an_instance_of Hash
|
56
|
+
msg[:header].should be_an_instance_of Bunny::Protocol::Header
|
57
|
+
msg[:payload].should == 'This is a test message'
|
58
|
+
msg[:delivery_details].should be_an_instance_of Hash
|
59
|
+
q.message_count.should == 0
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should be able to pop a message and just get the payload" do
|
63
|
+
q = @b.queue('test1')
|
64
|
+
q.publish('This is another test message')
|
65
|
+
msg = q.pop
|
66
|
+
msg.should == 'This is another test message'
|
67
|
+
q.message_count.should == 0
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should return an empty message when popping an empty queue" do
|
71
|
+
q = @b.queue('test1')
|
72
|
+
q.publish('This is another test message')
|
73
|
+
q.pop
|
74
|
+
msg = q.pop
|
75
|
+
msg.should == :queue_empty
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should be able to be deleted" do
|
79
|
+
q = @b.queue('test1')
|
80
|
+
res = q.delete
|
81
|
+
res.should == :delete_ok
|
82
|
+
@b.queues.has_key?('test1').should be false
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should ignore the :nowait option when deleted" do
|
86
|
+
q = @b.queue('test0')
|
87
|
+
q.delete(:nowait => true)
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|