carrot 0.8.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +2 -2
- data/Rakefile +0 -8
- data/VERSION.yml +5 -5
- data/carrot.gemspec +28 -34
- data/lib/carrot.rb +8 -8
- data/lib/{amqp → carrot/amqp}/buffer.rb +0 -125
- data/lib/{amqp → carrot/amqp}/exchange.rb +0 -0
- data/lib/carrot/amqp/frame.rb +62 -0
- data/lib/{amqp → carrot/amqp}/header.rb +0 -0
- data/lib/{amqp → carrot/amqp}/protocol.rb +0 -51
- data/lib/{amqp → carrot/amqp}/queue.rb +6 -4
- data/lib/{amqp → carrot/amqp}/server.rb +29 -0
- data/lib/{amqp → carrot/amqp}/spec.rb +0 -0
- data/test/buffer_test.rb +122 -0
- data/test/carrot_test.rb +11 -13
- data/test/frame_test.rb +56 -0
- data/test/protocol_test.rb +52 -0
- data/test/test_helper.rb +23 -14
- metadata +52 -76
- data/.gitignore +0 -3
- data/lib/amqp/frame.rb +0 -121
data/README.markdown
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
A synchronous amqp client. Based on Aman's amqp client:
|
4
4
|
|
5
|
-
[http://github.com/tmm1/amqp/tree/master]
|
5
|
+
[http://github.com/tmm1/amqp/tree/master](http://github.com/tmm1/amqp/tree/master)
|
6
6
|
|
7
7
|
## Motivation
|
8
8
|
|
9
|
-
This client does not use eventmachine so no background thread necessary. As a result, it is much easier to use from script/console and Passenger. It also solves the problem of buffering messages and ack responses. For more details see [this thread]
|
9
|
+
This client does not use eventmachine so no background thread necessary. As a result, it is much easier to use from script/console and Passenger. It also solves the problem of buffering messages and ack responses. For more details see [this thread](http://groups.google.com/group/ruby-amqp/browse_thread/thread/fdae324a0ebb1961/fa185fdce1841b68).
|
10
10
|
|
11
11
|
There is currently no way to prevent buffering using eventmachine. Support for prefetch is still unreliable.
|
12
12
|
|
data/Rakefile
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/testtask'
|
3
3
|
require 'rake/rdoctask'
|
4
|
-
require 'rcov/rcovtask'
|
5
4
|
|
6
5
|
begin
|
7
6
|
require 'jeweler'
|
@@ -12,7 +11,6 @@ begin
|
|
12
11
|
s.description = "A synchronous version of the ruby amqp client"
|
13
12
|
s.summary = "A synchronous version of the ruby amqp client"
|
14
13
|
s.authors = ["Amos Elliston"]
|
15
|
-
s.add_development_dependency "rcov"
|
16
14
|
s.add_development_dependency "mocha"
|
17
15
|
end
|
18
16
|
Jeweler::GemcutterTasks.new
|
@@ -34,10 +32,4 @@ Rake::RDocTask.new do |rdoc|
|
|
34
32
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
35
33
|
end
|
36
34
|
|
37
|
-
Rcov::RcovTask.new do |t|
|
38
|
-
t.libs << ['lib', 'test']
|
39
|
-
t.test_files = FileList['test/**/*_test.rb']
|
40
|
-
t.verbose = true
|
41
|
-
end
|
42
|
-
|
43
35
|
task :default => :test
|
data/VERSION.yml
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
---
|
2
|
-
:major:
|
3
|
-
:minor:
|
4
|
-
:
|
5
|
-
:
|
1
|
+
---
|
2
|
+
:major: 1
|
3
|
+
:minor: 0
|
4
|
+
:patch: 0
|
5
|
+
:build: !!null
|
data/carrot.gemspec
CHANGED
@@ -1,68 +1,62 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{carrot}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "1.0.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Amos Elliston"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-08-03}
|
13
13
|
s.description = %q{A synchronous version of the ruby amqp client}
|
14
14
|
s.email = %q{amos@geni.com}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
17
|
-
|
17
|
+
"README.markdown"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
|
-
"
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
20
|
+
"LICENSE",
|
21
|
+
"README.markdown",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION.yml",
|
24
|
+
"carrot.gemspec",
|
25
|
+
"lib/carrot.rb",
|
26
|
+
"lib/carrot/amqp/buffer.rb",
|
27
|
+
"lib/carrot/amqp/exchange.rb",
|
28
|
+
"lib/carrot/amqp/frame.rb",
|
29
|
+
"lib/carrot/amqp/header.rb",
|
30
|
+
"lib/carrot/amqp/protocol.rb",
|
31
|
+
"lib/carrot/amqp/queue.rb",
|
32
|
+
"lib/carrot/amqp/server.rb",
|
33
|
+
"lib/carrot/amqp/spec.rb",
|
34
|
+
"lib/examples/simple_pop.rb",
|
35
|
+
"protocol/amqp-0.8.json",
|
36
|
+
"protocol/amqp-0.8.xml",
|
37
|
+
"protocol/codegen.rb",
|
38
|
+
"protocol/doc.txt",
|
39
|
+
"test/buffer_test.rb",
|
40
|
+
"test/carrot_test.rb",
|
41
|
+
"test/frame_test.rb",
|
42
|
+
"test/protocol_test.rb",
|
43
|
+
"test/test_helper.rb"
|
42
44
|
]
|
43
45
|
s.homepage = %q{http://github.com/famoseagle/carrot}
|
44
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
45
46
|
s.require_paths = ["lib"]
|
46
47
|
s.rubygems_version = %q{1.3.7}
|
47
48
|
s.summary = %q{A synchronous version of the ruby amqp client}
|
48
|
-
s.test_files = [
|
49
|
-
"test/carrot_test.rb",
|
50
|
-
"test/test_helper.rb"
|
51
|
-
]
|
52
49
|
|
53
50
|
if s.respond_to? :specification_version then
|
54
51
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
55
52
|
s.specification_version = 3
|
56
53
|
|
57
54
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
58
|
-
s.add_development_dependency(%q<rcov>, [">= 0"])
|
59
55
|
s.add_development_dependency(%q<mocha>, [">= 0"])
|
60
56
|
else
|
61
|
-
s.add_dependency(%q<rcov>, [">= 0"])
|
62
57
|
s.add_dependency(%q<mocha>, [">= 0"])
|
63
58
|
end
|
64
59
|
else
|
65
|
-
s.add_dependency(%q<rcov>, [">= 0"])
|
66
60
|
s.add_dependency(%q<mocha>, [">= 0"])
|
67
61
|
end
|
68
62
|
end
|
data/lib/carrot.rb
CHANGED
@@ -8,14 +8,14 @@ class Carrot
|
|
8
8
|
end
|
9
9
|
|
10
10
|
$:.unshift File.expand_path(File.dirname(File.expand_path(__FILE__)))
|
11
|
-
require 'amqp/spec'
|
12
|
-
require 'amqp/buffer'
|
13
|
-
require 'amqp/exchange'
|
14
|
-
require 'amqp/frame'
|
15
|
-
require 'amqp/header'
|
16
|
-
require 'amqp/queue'
|
17
|
-
require 'amqp/server'
|
18
|
-
require 'amqp/protocol'
|
11
|
+
require 'carrot/amqp/spec'
|
12
|
+
require 'carrot/amqp/buffer'
|
13
|
+
require 'carrot/amqp/exchange'
|
14
|
+
require 'carrot/amqp/frame'
|
15
|
+
require 'carrot/amqp/header'
|
16
|
+
require 'carrot/amqp/queue'
|
17
|
+
require 'carrot/amqp/server'
|
18
|
+
require 'carrot/amqp/protocol'
|
19
19
|
|
20
20
|
class Carrot
|
21
21
|
@logging = false
|
@@ -274,128 +274,3 @@ module Carrot::AMQP
|
|
274
274
|
end
|
275
275
|
end
|
276
276
|
end
|
277
|
-
|
278
|
-
if $0 =~ /bacon/ or $0 == __FILE__
|
279
|
-
require 'bacon'
|
280
|
-
include AMQP
|
281
|
-
|
282
|
-
describe Buffer do
|
283
|
-
before do
|
284
|
-
@buf = Buffer.new
|
285
|
-
end
|
286
|
-
|
287
|
-
should 'have contents' do
|
288
|
-
@buf.contents.should == ''
|
289
|
-
end
|
290
|
-
|
291
|
-
should 'initialize with data' do
|
292
|
-
@buf = Buffer.new('abc')
|
293
|
-
@buf.contents.should == 'abc'
|
294
|
-
end
|
295
|
-
|
296
|
-
should 'append raw data' do
|
297
|
-
@buf << 'abc'
|
298
|
-
@buf << 'def'
|
299
|
-
@buf.contents.should == 'abcdef'
|
300
|
-
end
|
301
|
-
|
302
|
-
should 'append other buffers' do
|
303
|
-
@buf << Buffer.new('abc')
|
304
|
-
@buf.data.should == 'abc'
|
305
|
-
end
|
306
|
-
|
307
|
-
should 'have a position' do
|
308
|
-
@buf.pos.should == 0
|
309
|
-
end
|
310
|
-
|
311
|
-
should 'have a length' do
|
312
|
-
@buf.length.should == 0
|
313
|
-
@buf << 'abc'
|
314
|
-
@buf.length.should == 3
|
315
|
-
end
|
316
|
-
|
317
|
-
should 'know the end' do
|
318
|
-
@buf.empty?.should == true
|
319
|
-
end
|
320
|
-
|
321
|
-
should 'read and write data' do
|
322
|
-
@buf._write('abc')
|
323
|
-
@buf.rewind
|
324
|
-
@buf._read(2).should == 'ab'
|
325
|
-
@buf._read(1).should == 'c'
|
326
|
-
end
|
327
|
-
|
328
|
-
should 'raise on overflow' do
|
329
|
-
lambda{ @buf._read(1) }.should.raise Buffer::Overflow
|
330
|
-
end
|
331
|
-
|
332
|
-
should 'raise on invalid types' do
|
333
|
-
lambda{ @buf.read(:junk) }.should.raise Buffer::InvalidType
|
334
|
-
lambda{ @buf.write(:junk, 1) }.should.raise Buffer::InvalidType
|
335
|
-
end
|
336
|
-
|
337
|
-
{ :octet => 0b10101010,
|
338
|
-
:short => 100,
|
339
|
-
:long => 100_000_000,
|
340
|
-
:longlong => 666_555_444_333_222_111,
|
341
|
-
:shortstr => 'hello',
|
342
|
-
:longstr => 'bye'*500,
|
343
|
-
:timestamp => time = Time.at(Time.now.to_i),
|
344
|
-
:table => { :this => 'is', :a => 'hash', :with => {:nested => 123, :and => time, :also => 123.456} },
|
345
|
-
:bit => true
|
346
|
-
}.each do |type, value|
|
347
|
-
|
348
|
-
should "read and write a #{type}" do
|
349
|
-
@buf.write(type, value)
|
350
|
-
@buf.rewind
|
351
|
-
@buf.read(type).should == value
|
352
|
-
@buf.should.be.empty
|
353
|
-
end
|
354
|
-
|
355
|
-
end
|
356
|
-
|
357
|
-
should 'read and write multiple bits' do
|
358
|
-
bits = [true, false, false, true, true, false, false, true, true, false]
|
359
|
-
@buf.write(:bit, bits)
|
360
|
-
@buf.write(:octet, 100)
|
361
|
-
|
362
|
-
@buf.rewind
|
363
|
-
|
364
|
-
bits.map do
|
365
|
-
@buf.read(:bit)
|
366
|
-
end.should == bits
|
367
|
-
@buf.read(:octet).should == 100
|
368
|
-
end
|
369
|
-
|
370
|
-
should 'read and write properties' do
|
371
|
-
properties = ([
|
372
|
-
[:octet, 1],
|
373
|
-
[:shortstr, 'abc'],
|
374
|
-
[:bit, true],
|
375
|
-
[:bit, false],
|
376
|
-
[:shortstr, nil],
|
377
|
-
[:timestamp, nil],
|
378
|
-
[:table, { :a => 'hash' }],
|
379
|
-
]*5).sort_by{rand}
|
380
|
-
|
381
|
-
@buf.write(:properties, properties)
|
382
|
-
@buf.rewind
|
383
|
-
@buf.read(:properties, *properties.map{|type,_| type }).should == properties.map{|_,value| value }
|
384
|
-
@buf.should.be.empty
|
385
|
-
end
|
386
|
-
|
387
|
-
should 'do transactional reads with #extract' do
|
388
|
-
@buf.write :octet, 8
|
389
|
-
orig = @buf.to_s
|
390
|
-
|
391
|
-
@buf.rewind
|
392
|
-
@buf.extract do |b|
|
393
|
-
b.read :octet
|
394
|
-
b.read :short
|
395
|
-
end
|
396
|
-
|
397
|
-
@buf.pos.should == 0
|
398
|
-
@buf.data.should == orig
|
399
|
-
end
|
400
|
-
end
|
401
|
-
end
|
File without changes
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Carrot::AMQP
|
2
|
+
class Frame #:nodoc: all
|
3
|
+
def initialize payload = nil, channel = 0
|
4
|
+
@channel, @payload = channel, payload
|
5
|
+
end
|
6
|
+
attr_accessor :channel, :payload
|
7
|
+
|
8
|
+
def id
|
9
|
+
self.class::ID
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_binary
|
13
|
+
buf = Buffer.new
|
14
|
+
buf.write :octet, id
|
15
|
+
buf.write :short, channel
|
16
|
+
buf.write :longstr, payload
|
17
|
+
buf.write :octet, FOOTER
|
18
|
+
buf.rewind
|
19
|
+
buf
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
to_binary.to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
def == frame
|
27
|
+
[ :id, :channel, :payload ].inject(true) do |eql, field|
|
28
|
+
eql and __send__(field) == frame.__send__(field)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Invalid < StandardError; end
|
33
|
+
|
34
|
+
class Method
|
35
|
+
def initialize payload = nil, channel = 0
|
36
|
+
super
|
37
|
+
unless @payload.is_a? Protocol::Class::Method or @payload.nil?
|
38
|
+
@payload = Protocol.parse(@payload)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Header
|
44
|
+
def initialize payload = nil, channel = 0
|
45
|
+
super
|
46
|
+
unless @payload.is_a? Protocol::Header or @payload.nil?
|
47
|
+
@payload = Protocol::Header.new(@payload)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class Body; end
|
53
|
+
|
54
|
+
def self.parse(buf)
|
55
|
+
buf = Buffer.new(buf) unless buf.is_a? Buffer
|
56
|
+
buf.extract do
|
57
|
+
id, channel, payload, footer = buf.read(:octet, :short, :longstr, :octet)
|
58
|
+
Frame.types[id].new(payload, channel) if footer == FOOTER
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
File without changes
|
@@ -156,54 +156,3 @@ module Carrot::AMQP
|
|
156
156
|
#:stopdoc:
|
157
157
|
end
|
158
158
|
end
|
159
|
-
|
160
|
-
if $0 =~ /bacon/ or $0 == __FILE__
|
161
|
-
require 'bacon'
|
162
|
-
include AMQP
|
163
|
-
|
164
|
-
describe Protocol do
|
165
|
-
should 'instantiate methods with arguments' do
|
166
|
-
meth = Protocol::Connection::StartOk.new nil, 'PLAIN', nil, 'en_US'
|
167
|
-
meth.locale.should == 'en_US'
|
168
|
-
end
|
169
|
-
|
170
|
-
should 'instantiate methods with named parameters' do
|
171
|
-
meth = Protocol::Connection::StartOk.new :locale => 'en_US',
|
172
|
-
:mechanism => 'PLAIN'
|
173
|
-
meth.locale.should == 'en_US'
|
174
|
-
end
|
175
|
-
|
176
|
-
should 'convert methods to binary' do
|
177
|
-
meth = Protocol::Connection::Secure.new :challenge => 'secret'
|
178
|
-
meth.to_binary.should.be.kind_of? Buffer
|
179
|
-
|
180
|
-
meth.to_s.should == [ 10, 20, 6, 'secret' ].pack('nnNa*')
|
181
|
-
end
|
182
|
-
|
183
|
-
should 'convert binary to method' do
|
184
|
-
orig = Protocol::Connection::Secure.new :challenge => 'secret'
|
185
|
-
copy = Protocol.parse orig.to_binary
|
186
|
-
orig.should == copy
|
187
|
-
end
|
188
|
-
|
189
|
-
should 'convert headers to binary' do
|
190
|
-
head = Protocol::Header.new Protocol::Basic,
|
191
|
-
size = 5,
|
192
|
-
weight = 0,
|
193
|
-
:content_type => 'text/json',
|
194
|
-
:delivery_mode => 1,
|
195
|
-
:priority => 1
|
196
|
-
head.to_s.should == [ 60, weight, 0, size, 0b1001_1000_0000_0000, 9, 'text/json', 1, 1 ].pack('nnNNnCa*CC')
|
197
|
-
end
|
198
|
-
|
199
|
-
should 'convert binary to header' do
|
200
|
-
orig = Protocol::Header.new Protocol::Basic,
|
201
|
-
size = 5,
|
202
|
-
weight = 0,
|
203
|
-
:content_type => 'text/json',
|
204
|
-
:delivery_mode => 1,
|
205
|
-
:priority => 1
|
206
|
-
Protocol::Header.new(orig.to_binary).should == orig
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
@@ -1,14 +1,16 @@
|
|
1
1
|
module Carrot::AMQP
|
2
2
|
class Queue
|
3
3
|
attr_reader :name, :carrot
|
4
|
-
attr_accessor :delivery_tag
|
4
|
+
attr_accessor :delivery_tag, :opts
|
5
5
|
|
6
6
|
def initialize(carrot, name, opts = {})
|
7
7
|
@opts = opts
|
8
8
|
@name = name
|
9
9
|
@carrot = carrot
|
10
|
+
|
11
|
+
@opts[:queue] = name
|
10
12
|
server.send_frame(
|
11
|
-
Protocol::Queue::Declare.new(
|
13
|
+
Protocol::Queue::Declare.new(@opts.merge(:nowait => true))
|
12
14
|
)
|
13
15
|
end
|
14
16
|
|
@@ -50,9 +52,9 @@ module Carrot::AMQP
|
|
50
52
|
status.last
|
51
53
|
end
|
52
54
|
|
53
|
-
def status
|
55
|
+
def status
|
54
56
|
server.send_frame(
|
55
|
-
Protocol::Queue::Declare.new(
|
57
|
+
Protocol::Queue::Declare.new(opts)
|
56
58
|
)
|
57
59
|
method = server.next_method
|
58
60
|
return [nil, nil] if method.kind_of?(Protocol::Connection::Close)
|
@@ -2,6 +2,12 @@ require 'socket'
|
|
2
2
|
require 'thread'
|
3
3
|
require 'timeout'
|
4
4
|
|
5
|
+
begin
|
6
|
+
require 'openssl'
|
7
|
+
rescue LoadError
|
8
|
+
warn "Unable to load SSL extension - you will be unable to make ssl connections."
|
9
|
+
end
|
10
|
+
|
5
11
|
module Carrot::AMQP
|
6
12
|
class Server
|
7
13
|
CONNECT_TIMEOUT = 1.0
|
@@ -23,6 +29,9 @@ module Carrot::AMQP
|
|
23
29
|
@insist = opts[:insist]
|
24
30
|
@status = 'NOT CONNECTED'
|
25
31
|
|
32
|
+
@use_ssl = !!opts[:ssl]
|
33
|
+
@ssl_verify = opts[:ssl_verify] || OpenSSL::SSL::VERIFY_PEER
|
34
|
+
|
26
35
|
@multithread = opts[:multithread]
|
27
36
|
start_session
|
28
37
|
end
|
@@ -93,6 +102,23 @@ module Carrot::AMQP
|
|
93
102
|
end
|
94
103
|
end
|
95
104
|
|
105
|
+
def start_ssl
|
106
|
+
unless defined?(OpenSSL)
|
107
|
+
raise "SSL Extension not installed"
|
108
|
+
end
|
109
|
+
|
110
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
111
|
+
ctx.verify_mode = @ssl_verify
|
112
|
+
|
113
|
+
@socket = OpenSSL::SSL::SSLSocket.new(@socket, ctx)
|
114
|
+
@socket.sync_close = true
|
115
|
+
@socket.connect
|
116
|
+
|
117
|
+
if ctx.verify_mode != OpenSSL::SSL::VERIFY_NONE
|
118
|
+
@socket.post_connection_check(@host)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
96
122
|
def socket
|
97
123
|
return @socket if @socket and not @socket.closed?
|
98
124
|
|
@@ -106,6 +132,9 @@ module Carrot::AMQP
|
|
106
132
|
if Socket.constants.include? 'TCP_NODELAY'
|
107
133
|
@socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
|
108
134
|
end
|
135
|
+
|
136
|
+
start_ssl if @use_ssl
|
137
|
+
|
109
138
|
@status = 'CONNECTED'
|
110
139
|
rescue SocketError, SystemCallError, IOError, Timeout::Error => e
|
111
140
|
msg = e.message << " - #{@host}:#{@port}"
|
File without changes
|
data/test/buffer_test.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'carrot/amqp/buffer'
|
3
|
+
|
4
|
+
module Carrot::AMQP
|
5
|
+
context 'Buffer' do
|
6
|
+
setup do
|
7
|
+
@buf = Buffer.new
|
8
|
+
end
|
9
|
+
|
10
|
+
test 'have contents' do
|
11
|
+
assert_equal '', @buf.contents
|
12
|
+
end
|
13
|
+
|
14
|
+
test 'initialize with data' do
|
15
|
+
@buf = Buffer.new('abc')
|
16
|
+
assert_equal 'abc', @buf.contents
|
17
|
+
end
|
18
|
+
|
19
|
+
test 'append raw data' do
|
20
|
+
@buf << 'abc'
|
21
|
+
@buf << 'def'
|
22
|
+
assert_equal 'abcdef', @buf.contents
|
23
|
+
end
|
24
|
+
|
25
|
+
test 'append other buffers' do
|
26
|
+
@buf << Buffer.new('abc')
|
27
|
+
assert_equal 'abc', @buf.contents
|
28
|
+
end
|
29
|
+
|
30
|
+
test 'have a position' do
|
31
|
+
assert_equal 0, @buf.pos
|
32
|
+
end
|
33
|
+
|
34
|
+
test 'have a length' do
|
35
|
+
assert_equal 0, @buf.length
|
36
|
+
@buf << 'abc'
|
37
|
+
assert_equal 3, @buf.length
|
38
|
+
end
|
39
|
+
|
40
|
+
test 'know the end' do
|
41
|
+
assert_equal true, @buf.empty?
|
42
|
+
end
|
43
|
+
|
44
|
+
test 'read and write data' do
|
45
|
+
@buf._write('abc')
|
46
|
+
@buf.rewind
|
47
|
+
assert_equal 'ab', @buf._read(2)
|
48
|
+
assert_equal 'c', @buf._read(1)
|
49
|
+
end
|
50
|
+
|
51
|
+
test 'raise on overflow' do
|
52
|
+
assert_raise(Buffer::Overflow) { @buf._read(1) }
|
53
|
+
end
|
54
|
+
|
55
|
+
test 'raise on invalid types' do
|
56
|
+
assert_raise(Buffer::InvalidType) { @buf.read(:junk) }
|
57
|
+
assert_raise(Buffer::InvalidType) { @buf.write(:junk, 1) }
|
58
|
+
end
|
59
|
+
|
60
|
+
{ :octet => 0b10101010,
|
61
|
+
:short => 100,
|
62
|
+
:long => 100_000_000,
|
63
|
+
:longlong => 666_555_444_333_222_111,
|
64
|
+
:shortstr => 'hello',
|
65
|
+
:longstr => 'bye'*500,
|
66
|
+
:timestamp => time = Time.at(Time.now.to_i),
|
67
|
+
:table => { :this => 'is', :a => 'hash', :with => {:nested => 123, :and => time, :also => 123.456} },
|
68
|
+
:bit => true
|
69
|
+
}.each do |type, value|
|
70
|
+
|
71
|
+
test "read and write a #{type}" do
|
72
|
+
@buf.write(type, value)
|
73
|
+
@buf.rewind
|
74
|
+
assert_equal value, @buf.read(type)
|
75
|
+
assert_equal true, @buf.empty?
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
test 'read and write multiple bits' do
|
81
|
+
bits = [true, false, false, true, true, false, false, true, true, false]
|
82
|
+
@buf.write(:bit, bits)
|
83
|
+
@buf.write(:octet, 100)
|
84
|
+
|
85
|
+
@buf.rewind
|
86
|
+
|
87
|
+
assert_equal bits, bits.collect{ @buf.read(:bit) }
|
88
|
+
assert_equal 100, @buf.read(:octet)
|
89
|
+
end
|
90
|
+
|
91
|
+
test 'read and write properties' do
|
92
|
+
properties = ([
|
93
|
+
[:octet, 1],
|
94
|
+
[:shortstr, 'abc'],
|
95
|
+
[:bit, true],
|
96
|
+
[:bit, false],
|
97
|
+
[:shortstr, nil],
|
98
|
+
[:timestamp, nil],
|
99
|
+
[:table, { :a => 'hash' }],
|
100
|
+
]*5).sort_by{rand}
|
101
|
+
|
102
|
+
@buf.write(:properties, properties)
|
103
|
+
@buf.rewind
|
104
|
+
assert_equal properties.map{|_,value| value }, @buf.read(:properties, *properties.map{|type,_| type })
|
105
|
+
assert_equal true, @buf.empty?
|
106
|
+
end
|
107
|
+
|
108
|
+
test 'do transactional reads with #extract' do
|
109
|
+
@buf.write :octet, 8
|
110
|
+
orig = @buf.to_s
|
111
|
+
|
112
|
+
@buf.rewind
|
113
|
+
@buf.extract do |b|
|
114
|
+
b.read :octet
|
115
|
+
b.read :short
|
116
|
+
end
|
117
|
+
|
118
|
+
assert_equal 0, @buf.pos
|
119
|
+
assert_equal orig, @buf.data
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/test/carrot_test.rb
CHANGED
@@ -1,25 +1,23 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
|
3
|
+
context 'test queue' do
|
4
4
|
TEST_QUEUE = '_carrot_test'
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
setup do
|
6
|
+
@carrot = Carrot.new
|
7
|
+
@q = @carrot.queue(TEST_QUEUE)
|
8
|
+
@q.purge
|
8
9
|
end
|
9
10
|
|
10
11
|
test "large messages" do
|
11
12
|
msg = 'a' * 1024 * 1024
|
12
|
-
q
|
13
|
-
q.
|
14
|
-
assert_equal msg, q.pop
|
13
|
+
@q.publish(msg)
|
14
|
+
assert_equal msg, @q.pop
|
15
15
|
end
|
16
16
|
|
17
17
|
test "reset" do
|
18
|
-
|
19
|
-
q
|
20
|
-
|
21
|
-
q.
|
22
|
-
c.reset
|
23
|
-
assert_equal count + 1, q.message_count
|
18
|
+
count = @q.message_count
|
19
|
+
@q.publish('test')
|
20
|
+
@carrot.reset
|
21
|
+
assert_equal count + 1, @q.message_count
|
24
22
|
end
|
25
23
|
end
|
data/test/frame_test.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Carrot::AMQP
|
4
|
+
context 'Frame' do
|
5
|
+
test 'handle basic frame types' do
|
6
|
+
assert_equal 1, Frame::Method.new.id
|
7
|
+
assert_equal 2, Frame::Header.new.id
|
8
|
+
assert_equal 3, Frame::Body.new.id
|
9
|
+
end
|
10
|
+
|
11
|
+
test 'convert method frames to binary' do
|
12
|
+
meth = Protocol::Connection::Secure.new :challenge => 'secret'
|
13
|
+
|
14
|
+
frame = Frame::Method.new(meth)
|
15
|
+
assert frame.to_binary.kind_of?(Buffer)
|
16
|
+
assert_equal [ 1, 0, meth.to_s.length, meth.to_s, 206 ].pack('CnNa*C'), frame.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
test 'convert binary to method frames' do
|
20
|
+
orig = Frame::Method.new Protocol::Connection::Secure.new(:challenge => 'secret')
|
21
|
+
|
22
|
+
copy = Frame.parse(orig.to_binary)
|
23
|
+
assert_equal orig, copy
|
24
|
+
end
|
25
|
+
|
26
|
+
test 'ignore partial frames until ready' do
|
27
|
+
frame = Frame::Method.new Protocol::Connection::Secure.new(:challenge => 'secret')
|
28
|
+
data = frame.to_s
|
29
|
+
|
30
|
+
buf = Buffer.new
|
31
|
+
assert_equal nil, Frame.parse(buf)
|
32
|
+
|
33
|
+
buf << data[0..5]
|
34
|
+
assert_equal nil, Frame.parse(buf)
|
35
|
+
|
36
|
+
buf << data[6..-1]
|
37
|
+
assert_equal frame, Frame.parse(buf)
|
38
|
+
|
39
|
+
assert_equal nil, Frame.parse(buf)
|
40
|
+
end
|
41
|
+
|
42
|
+
test 'convert header frames to binary' do
|
43
|
+
head = Protocol::Header.new(Protocol::Basic, :priority => 1)
|
44
|
+
|
45
|
+
frame = Frame::Header.new(head)
|
46
|
+
assert_equal [ 2, 0, head.to_s.length, head.to_s, 206 ].pack('CnNa*C'), frame.to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
test 'convert binary to header frame' do
|
50
|
+
orig = Frame::Header.new Protocol::Header.new(Protocol::Basic, :priority => 1)
|
51
|
+
|
52
|
+
copy = Frame.parse(orig.to_binary)
|
53
|
+
assert_equal orig, copy
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Carrot::AMQP
|
4
|
+
context 'Protocol' do
|
5
|
+
test 'instantiate methods with arguments' do
|
6
|
+
meth = Protocol::Connection::StartOk.new(nil, 'PLAIN', nil, 'en_US')
|
7
|
+
assert_equal 'en_US', meth.locale
|
8
|
+
end
|
9
|
+
|
10
|
+
test 'instantiate methods with named parameters' do
|
11
|
+
meth = Protocol::Connection::StartOk.new(:locale => 'en_US', :mechanism => 'PLAIN')
|
12
|
+
assert_equal 'en_US', meth.locale
|
13
|
+
end
|
14
|
+
|
15
|
+
test 'convert methods to binary' do
|
16
|
+
meth = Protocol::Connection::Secure.new(:challenge => 'secret')
|
17
|
+
assert meth.to_binary.kind_of?(Buffer)
|
18
|
+
|
19
|
+
assert_equal [ 10, 20, 6, 'secret' ].pack('nnNa*'), meth.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
test 'convert binary to method' do
|
23
|
+
orig = Protocol::Connection::Secure.new(:challenge => 'secret')
|
24
|
+
copy = Protocol.parse orig.to_binary
|
25
|
+
assert_equal copy, orig
|
26
|
+
end
|
27
|
+
|
28
|
+
test 'convert headers to binary' do
|
29
|
+
head = Protocol::Header.new(
|
30
|
+
Protocol::Basic,
|
31
|
+
size = 5,
|
32
|
+
weight = 0,
|
33
|
+
:content_type => 'text/json',
|
34
|
+
:delivery_mode => 1,
|
35
|
+
:priority => 1
|
36
|
+
)
|
37
|
+
assert_equal [ 60, weight, 0, size, 0b1001_1000_0000_0000, 9, 'text/json', 1, 1 ].pack('nnNNnCa*CC'), head.to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
test 'convert binary to header' do
|
41
|
+
orig = Protocol::Header.new(
|
42
|
+
Protocol::Basic,
|
43
|
+
size = 5,
|
44
|
+
weight = 0,
|
45
|
+
:content_type => 'text/json',
|
46
|
+
:delivery_mode => 1,
|
47
|
+
:priority => 1
|
48
|
+
)
|
49
|
+
assert_equal orig, Protocol::Header.new(orig.to_binary)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -1,18 +1,27 @@
|
|
1
|
-
|
1
|
+
dir = File.dirname(File.expand_path(__FILE__))
|
2
|
+
$LOAD_PATH.unshift dir + '/../lib'
|
3
|
+
require 'carrot'
|
2
4
|
require 'test/unit'
|
3
|
-
|
4
|
-
require '
|
5
|
-
require File.dirname(__FILE__) + '/../lib/carrot'
|
6
|
-
|
7
|
-
class << Test::Unit::TestCase
|
8
|
-
def test(name, &block)
|
9
|
-
test_name = "test_#{name.gsub(/[\s\W]/,'_')}"
|
10
|
-
raise ArgumentError, "#{test_name} is already defined" if self.instance_methods.include? test_name
|
11
|
-
define_method test_name, &block
|
12
|
-
end
|
5
|
+
require 'rubygems'
|
6
|
+
require 'pp'
|
13
7
|
|
14
|
-
|
15
|
-
|
16
|
-
|
8
|
+
##
|
9
|
+
# test/spec/mini 3
|
10
|
+
# http://gist.github.com/25455
|
11
|
+
# chris@ozmm.org
|
12
|
+
# file:lib/test/spec/mini.rb
|
13
|
+
#
|
14
|
+
def context(*args, &block)
|
15
|
+
return super unless (name = args.first) && block
|
16
|
+
require 'test/unit'
|
17
|
+
klass = Class.new(defined?(ActiveSupport::TestCase) ? ActiveSupport::TestCase : Test::Unit::TestCase) do
|
18
|
+
def self.test(name, &block)
|
19
|
+
define_method("test_#{name.gsub(/\W/,'_')}", &block) if block
|
20
|
+
end
|
21
|
+
def self.xtest(*args) end
|
22
|
+
def self.setup(&block) define_method(:setup, &block) end
|
23
|
+
def self.teardown(&block) define_method(:teardown, &block) end
|
17
24
|
end
|
25
|
+
(class << klass; self end).send(:define_method, :name) { name.gsub(/\W/,'_') }
|
26
|
+
klass.class_eval &block
|
18
27
|
end
|
metadata
CHANGED
@@ -1,117 +1,93 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: carrot
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 8
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
segments:
|
9
6
|
- 1
|
10
|
-
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
prerelease: false
|
11
10
|
platform: ruby
|
12
|
-
authors:
|
11
|
+
authors:
|
13
12
|
- Amos Elliston
|
14
|
-
autorequire:
|
13
|
+
autorequire: !!null
|
15
14
|
bindir: bin
|
16
15
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
- !ruby/object:Gem::Dependency
|
22
|
-
name: rcov
|
23
|
-
prerelease: false
|
24
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ">="
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
hash: 3
|
30
|
-
segments:
|
31
|
-
- 0
|
32
|
-
version: "0"
|
33
|
-
type: :development
|
34
|
-
version_requirements: *id001
|
35
|
-
- !ruby/object:Gem::Dependency
|
16
|
+
date: 2011-08-03 00:00:00.000000000 -07:00
|
17
|
+
default_executable: !!null
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
36
20
|
name: mocha
|
37
|
-
|
38
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
21
|
+
requirement: &2152420380 !ruby/object:Gem::Requirement
|
39
22
|
none: false
|
40
|
-
requirements:
|
41
|
-
- -
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
|
44
|
-
segments:
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
segments:
|
45
28
|
- 0
|
46
|
-
version: "0"
|
47
29
|
type: :development
|
48
|
-
|
30
|
+
prerelease: false
|
31
|
+
version_requirements: *2152420380
|
49
32
|
description: A synchronous version of the ruby amqp client
|
50
33
|
email: amos@geni.com
|
51
34
|
executables: []
|
52
|
-
|
53
35
|
extensions: []
|
54
|
-
|
55
|
-
extra_rdoc_files:
|
36
|
+
extra_rdoc_files:
|
56
37
|
- LICENSE
|
57
38
|
- README.markdown
|
58
|
-
files:
|
59
|
-
- .gitignore
|
39
|
+
files:
|
60
40
|
- LICENSE
|
61
41
|
- README.markdown
|
62
42
|
- Rakefile
|
63
43
|
- VERSION.yml
|
64
44
|
- carrot.gemspec
|
65
|
-
- lib/amqp/buffer.rb
|
66
|
-
- lib/amqp/exchange.rb
|
67
|
-
- lib/amqp/frame.rb
|
68
|
-
- lib/amqp/header.rb
|
69
|
-
- lib/amqp/protocol.rb
|
70
|
-
- lib/amqp/queue.rb
|
71
|
-
- lib/amqp/server.rb
|
72
|
-
- lib/amqp/spec.rb
|
73
45
|
- lib/carrot.rb
|
46
|
+
- lib/carrot/amqp/buffer.rb
|
47
|
+
- lib/carrot/amqp/exchange.rb
|
48
|
+
- lib/carrot/amqp/frame.rb
|
49
|
+
- lib/carrot/amqp/header.rb
|
50
|
+
- lib/carrot/amqp/protocol.rb
|
51
|
+
- lib/carrot/amqp/queue.rb
|
52
|
+
- lib/carrot/amqp/server.rb
|
53
|
+
- lib/carrot/amqp/spec.rb
|
74
54
|
- lib/examples/simple_pop.rb
|
75
55
|
- protocol/amqp-0.8.json
|
76
56
|
- protocol/amqp-0.8.xml
|
77
57
|
- protocol/codegen.rb
|
78
58
|
- protocol/doc.txt
|
59
|
+
- test/buffer_test.rb
|
79
60
|
- test/carrot_test.rb
|
61
|
+
- test/frame_test.rb
|
62
|
+
- test/protocol_test.rb
|
80
63
|
- test/test_helper.rb
|
81
64
|
has_rdoc: true
|
82
65
|
homepage: http://github.com/famoseagle/carrot
|
83
66
|
licenses: []
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
- --charset=UTF-8
|
88
|
-
require_paths:
|
67
|
+
post_install_message: !!null
|
68
|
+
rdoc_options: []
|
69
|
+
require_paths:
|
89
70
|
- lib
|
90
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
72
|
none: false
|
92
|
-
requirements:
|
93
|
-
- -
|
94
|
-
- !ruby/object:Gem::Version
|
95
|
-
|
96
|
-
segments:
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
segments:
|
97
78
|
- 0
|
98
|
-
|
99
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
80
|
none: false
|
101
|
-
requirements:
|
102
|
-
- -
|
103
|
-
- !ruby/object:Gem::Version
|
104
|
-
|
105
|
-
segments:
|
81
|
+
requirements:
|
82
|
+
- - ! '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
segments:
|
106
86
|
- 0
|
107
|
-
version: "0"
|
108
87
|
requirements: []
|
109
|
-
|
110
|
-
rubyforge_project:
|
88
|
+
rubyforge_project: !!null
|
111
89
|
rubygems_version: 1.3.7
|
112
|
-
signing_key:
|
90
|
+
signing_key: !!null
|
113
91
|
specification_version: 3
|
114
92
|
summary: A synchronous version of the ruby amqp client
|
115
|
-
test_files:
|
116
|
-
- test/carrot_test.rb
|
117
|
-
- test/test_helper.rb
|
93
|
+
test_files: []
|
data/.gitignore
DELETED
data/lib/amqp/frame.rb
DELETED
@@ -1,121 +0,0 @@
|
|
1
|
-
module Carrot::AMQP
|
2
|
-
class Frame #:nodoc: all
|
3
|
-
def initialize payload = nil, channel = 0
|
4
|
-
@channel, @payload = channel, payload
|
5
|
-
end
|
6
|
-
attr_accessor :channel, :payload
|
7
|
-
|
8
|
-
def id
|
9
|
-
self.class::ID
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_binary
|
13
|
-
buf = Buffer.new
|
14
|
-
buf.write :octet, id
|
15
|
-
buf.write :short, channel
|
16
|
-
buf.write :longstr, payload
|
17
|
-
buf.write :octet, FOOTER
|
18
|
-
buf.rewind
|
19
|
-
buf
|
20
|
-
end
|
21
|
-
|
22
|
-
def to_s
|
23
|
-
to_binary.to_s
|
24
|
-
end
|
25
|
-
|
26
|
-
def == frame
|
27
|
-
[ :id, :channel, :payload ].inject(true) do |eql, field|
|
28
|
-
eql and __send__(field) == frame.__send__(field)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
class Invalid < StandardError; end
|
33
|
-
|
34
|
-
class Method
|
35
|
-
def initialize payload = nil, channel = 0
|
36
|
-
super
|
37
|
-
unless @payload.is_a? Protocol::Class::Method or @payload.nil?
|
38
|
-
@payload = Protocol.parse(@payload)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
class Header
|
44
|
-
def initialize payload = nil, channel = 0
|
45
|
-
super
|
46
|
-
unless @payload.is_a? Protocol::Header or @payload.nil?
|
47
|
-
@payload = Protocol::Header.new(@payload)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
class Body; end
|
53
|
-
|
54
|
-
def self.parse(buf)
|
55
|
-
buf = Buffer.new(buf) unless buf.is_a? Buffer
|
56
|
-
buf.extract do
|
57
|
-
id, channel, payload, footer = buf.read(:octet, :short, :longstr, :octet)
|
58
|
-
Frame.types[id].new(payload, channel) if footer == FOOTER
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
if $0 =~ /bacon/ or $0 == __FILE__
|
65
|
-
require 'rubygems'
|
66
|
-
require 'bacon'
|
67
|
-
include AMQP
|
68
|
-
|
69
|
-
describe Frame do
|
70
|
-
should 'handle basic frame types' do
|
71
|
-
Frame::Method.new.id.should == 1
|
72
|
-
Frame::Header.new.id.should == 2
|
73
|
-
Frame::Body.new.id.should == 3
|
74
|
-
end
|
75
|
-
|
76
|
-
should 'convert method frames to binary' do
|
77
|
-
meth = Protocol::Connection::Secure.new :challenge => 'secret'
|
78
|
-
|
79
|
-
frame = Frame::Method.new(meth)
|
80
|
-
frame.to_binary.should.be.kind_of? Buffer
|
81
|
-
frame.to_s.should == [ 1, 0, meth.to_s.length, meth.to_s, 206 ].pack('CnNa*C')
|
82
|
-
end
|
83
|
-
|
84
|
-
should 'convert binary to method frames' do
|
85
|
-
orig = Frame::Method.new Protocol::Connection::Secure.new(:challenge => 'secret')
|
86
|
-
|
87
|
-
copy = Frame.parse(orig.to_binary)
|
88
|
-
copy.should == orig
|
89
|
-
end
|
90
|
-
|
91
|
-
should 'ignore partial frames until ready' do
|
92
|
-
frame = Frame::Method.new Protocol::Connection::Secure.new(:challenge => 'secret')
|
93
|
-
data = frame.to_s
|
94
|
-
|
95
|
-
buf = Buffer.new
|
96
|
-
Frame.parse(buf).should == nil
|
97
|
-
|
98
|
-
buf << data[0..5]
|
99
|
-
Frame.parse(buf).should == nil
|
100
|
-
|
101
|
-
buf << data[6..-1]
|
102
|
-
Frame.parse(buf).should == frame
|
103
|
-
|
104
|
-
Frame.parse(buf).should == nil
|
105
|
-
end
|
106
|
-
|
107
|
-
should 'convert header frames to binary' do
|
108
|
-
head = Protocol::Header.new(Protocol::Basic, :priority => 1)
|
109
|
-
|
110
|
-
frame = Frame::Header.new(head)
|
111
|
-
frame.to_s.should == [ 2, 0, head.to_s.length, head.to_s, 206 ].pack('CnNa*C')
|
112
|
-
end
|
113
|
-
|
114
|
-
should 'convert binary to header frame' do
|
115
|
-
orig = Frame::Header.new Protocol::Header.new(Protocol::Basic, :priority => 1)
|
116
|
-
|
117
|
-
copy = Frame.parse(orig.to_binary)
|
118
|
-
copy.should == orig
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|