amq-protocol 0.0.1.pre → 0.5.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/.gitignore +3 -1
- data/.travis.yml +7 -0
- data/CONTRIBUTORS +2 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +31 -0
- data/LICENSE +1 -1
- data/PROFILING.md +81 -0
- data/README.textile +34 -17
- data/TODO.todo +24 -0
- data/__init__.py +0 -0
- data/amq-protocol.gemspec +16 -11
- data/amqp_0.9.1_changes.json +1 -1
- data/bin/jenkins.sh +23 -0
- data/codegen.py +50 -16
- data/codegen_helpers.py +81 -26
- data/examples/00_manual_test.rb +117 -38
- data/irb.rb +76 -4
- data/lib/amq/hacks.rb +33 -0
- data/lib/amq/protocol.rb +3 -1472
- data/lib/amq/protocol/client.rb +2230 -0
- data/lib/amq/protocol/frame.rb +111 -38
- data/lib/amq/protocol/table.rb +89 -42
- data/lib/amq/protocol/version.rb +5 -0
- data/post-processing.rb +1 -0
- data/protocol.rb.pytemplate +217 -63
- data/spec/amq/hacks_spec.rb +39 -0
- data/spec/amq/protocol/basic_spec.rb +320 -0
- data/spec/amq/protocol/channel_spec.rb +117 -0
- data/spec/amq/protocol/confirm_spec.rb +44 -0
- data/spec/amq/protocol/connection_spec.rb +149 -0
- data/spec/amq/protocol/exchange_spec.rb +95 -0
- data/spec/amq/protocol/frame_spec.rb +93 -78
- data/spec/amq/protocol/method_spec.rb +40 -0
- data/spec/amq/protocol/queue_spec.rb +129 -0
- data/spec/amq/protocol/table_spec.rb +59 -36
- data/spec/amq/protocol/tx_spec.rb +58 -0
- data/spec/amq/protocol_spec.rb +572 -643
- data/spec/spec_helper.rb +25 -2
- data/tasks.rb +13 -8
- metadata +44 -25
- data/amq-protocol.pre.gemspec +0 -6
- data/examples/01_basics.rb +0 -14
- data/examples/02_eventmachine.rb +0 -4
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: binary
|
2
|
+
|
3
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
4
|
+
|
5
|
+
|
6
|
+
module AMQ
|
7
|
+
module Protocol
|
8
|
+
class Confirm
|
9
|
+
describe Select do
|
10
|
+
describe '.decode' do
|
11
|
+
subject do
|
12
|
+
Select.decode("\x01")
|
13
|
+
end
|
14
|
+
|
15
|
+
its(:nowait) { should be_true }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '.encode' do
|
19
|
+
it 'encodes the parameters into a MethodFrame' do
|
20
|
+
channel = 1
|
21
|
+
nowait = true
|
22
|
+
method_frame = Select.encode(channel, nowait)
|
23
|
+
method_frame.payload.should == "\x00U\x00\n\x01"
|
24
|
+
method_frame.channel.should == 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe SelectOk do
|
30
|
+
# describe '.decode' do
|
31
|
+
# end
|
32
|
+
|
33
|
+
describe '.encode' do
|
34
|
+
it 'encodes the parameters into a MethodFrame' do
|
35
|
+
channel = 1
|
36
|
+
method_frame = SelectOk.encode(channel)
|
37
|
+
method_frame.payload.should == "\000U\000\v"
|
38
|
+
method_frame.channel.should == 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# encoding: binary
|
2
|
+
|
3
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
4
|
+
|
5
|
+
|
6
|
+
module AMQ
|
7
|
+
module Protocol
|
8
|
+
class Connection
|
9
|
+
describe Start do
|
10
|
+
describe '.decode' do
|
11
|
+
subject do
|
12
|
+
Start.decode("\x00\t\x00\x00\x00\xFB\tcopyrightS\x00\x00\x00gCopyright (C) 2007-2010 LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.\vinformationS\x00\x00\x005Licensed under the MPL. See http://www.rabbitmq.com/\bplatformS\x00\x00\x00\nErlang/OTP\aproductS\x00\x00\x00\bRabbitMQ\aversionS\x00\x00\x00\x052.2.0\x00\x00\x00\x0EPLAIN AMQPLAIN\x00\x00\x00\x05en_US")
|
13
|
+
end
|
14
|
+
|
15
|
+
its(:version_major) { should == 0 }
|
16
|
+
its(:version_minor) { should == 9 }
|
17
|
+
its(:server_properties) { should == {'copyright' => 'Copyright (C) 2007-2010 LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.', 'information' => 'Licensed under the MPL. See http://www.rabbitmq.com/', 'platform' => 'Erlang/OTP', 'product' => 'RabbitMQ', 'version' => '2.2.0'} }
|
18
|
+
its(:mechanisms) { should == 'PLAIN AMQPLAIN' }
|
19
|
+
its(:locales) { should == 'en_US' }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe StartOk do
|
24
|
+
describe '.encode' do
|
25
|
+
it 'encodes the parameters into a MethodFrame' do
|
26
|
+
client_properties = {:platform => 'Ruby 1.9.2', :product => 'AMQ Client', :information => 'http://github.com/ruby-amqp/amq-client', :version => '0.2.0'}
|
27
|
+
mechanism = 'PLAIN'
|
28
|
+
response = "\x00guest\x00guest"
|
29
|
+
locale = 'en_GB'
|
30
|
+
method_frame = StartOk.encode(client_properties, mechanism, response, locale)
|
31
|
+
# the order of the table parts isn't deterministic in Ruby 1.8
|
32
|
+
method_frame.payload[0, 8].should == "\x00\n\x00\v\x00\x00\x00x"
|
33
|
+
method_frame.payload.should include("\bplatformS\x00\x00\x00\nRuby 1.9.2")
|
34
|
+
method_frame.payload.should include("\aproductS\x00\x00\x00\nAMQ Client")
|
35
|
+
method_frame.payload.should include("\vinformationS\x00\x00\x00&http://github.com/ruby-amqp/amq-client")
|
36
|
+
method_frame.payload.should include("\aversionS\x00\x00\x00\x050.2.0")
|
37
|
+
method_frame.payload[-28, 28].should == "\x05PLAIN\x00\x00\x00\f\x00guest\x00guest\x05en_GB"
|
38
|
+
method_frame.payload.length.should == 156
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe Secure do
|
44
|
+
describe '.decode' do
|
45
|
+
subject do
|
46
|
+
Secure.decode("\x00\x00\x00\x03foo")
|
47
|
+
end
|
48
|
+
|
49
|
+
its(:challenge) { should == 'foo' }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe SecureOk do
|
54
|
+
describe '.encode' do
|
55
|
+
it 'encodes the parameters as a MethodFrame' do
|
56
|
+
response = 'bar'
|
57
|
+
method_frame = SecureOk.encode(response)
|
58
|
+
method_frame.payload.should == "\x00\x0a\x00\x15\x00\x00\x00\x03bar"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe Tune do
|
64
|
+
describe '.decode' do
|
65
|
+
subject do
|
66
|
+
Tune.decode("\x00\x00\x00\x02\x00\x00\x00\x00")
|
67
|
+
end
|
68
|
+
|
69
|
+
its(:channel_max) { should == 0 }
|
70
|
+
its(:frame_max) { should == 131072 }
|
71
|
+
its(:heartbeat) { should == 0}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe TuneOk do
|
76
|
+
describe '.encode' do
|
77
|
+
it 'encodes the parameters into a MethodFrame' do
|
78
|
+
channel_max = 0
|
79
|
+
frame_max = 65536
|
80
|
+
heartbeat = 1
|
81
|
+
method_frame = TuneOk.encode(channel_max, frame_max, heartbeat)
|
82
|
+
method_frame.payload.should == "\x00\n\x00\x1F\x00\x00\x00\x01\x00\x00\x00\x01"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe Open do
|
88
|
+
describe '.encode' do
|
89
|
+
it 'encodes the parameters into a MethodFrame' do
|
90
|
+
vhost = '/test'
|
91
|
+
method_frame = Open.encode(vhost)
|
92
|
+
method_frame.payload.should == "\x00\n\x00(\x05/test\x00\x00"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe OpenOk do
|
98
|
+
describe '.decode' do
|
99
|
+
subject do
|
100
|
+
OpenOk.decode("\x00")
|
101
|
+
end
|
102
|
+
|
103
|
+
its(:known_hosts) { should == '' }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe Close do
|
108
|
+
describe '.decode' do
|
109
|
+
context 'with code 200' do
|
110
|
+
subject do
|
111
|
+
Close.decode("\x00\xc8\x07KTHXBAI\x00\x05\x00\x06")
|
112
|
+
end
|
113
|
+
|
114
|
+
its(:reply_code) { should == 200 }
|
115
|
+
its(:reply_text) { should == 'KTHXBAI' }
|
116
|
+
its(:class_id) { should == 5 }
|
117
|
+
its(:method_id) { should == 6 }
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'with an error code' do
|
121
|
+
it 'raises the corresponding error' do
|
122
|
+
expect { Close.decode("\x01\x38\x08NO_ROUTE\x00\x00") }.to raise_error(NoRoute, 'NO_ROUTE')
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe '.encode' do
|
128
|
+
it 'encodes the parameters into a MethodFrame' do
|
129
|
+
reply_code = 540
|
130
|
+
reply_text = 'NOT_IMPLEMENTED'
|
131
|
+
class_id = 0
|
132
|
+
method_id = 0
|
133
|
+
method_frame = Close.encode(reply_code, reply_text, class_id, method_id)
|
134
|
+
method_frame.payload.should == "\x00\x0a\x002\x02\x1c\x0fNOT_IMPLEMENTED\x00\x00\x00\x00"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe CloseOk do
|
140
|
+
describe '.encode' do
|
141
|
+
it 'encodes a MethodFrame' do
|
142
|
+
method_frame = CloseOk.encode
|
143
|
+
method_frame.payload.should == "\x00\n\x003"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# encoding: binary
|
2
|
+
|
3
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
4
|
+
|
5
|
+
|
6
|
+
module AMQ
|
7
|
+
module Protocol
|
8
|
+
class Exchange
|
9
|
+
describe Declare do
|
10
|
+
describe '.encode' do
|
11
|
+
it 'encodes the parameters into a MethodFrame' do
|
12
|
+
channel = 1
|
13
|
+
exchange = 'amqclient.adapters.em.exchange1'
|
14
|
+
type = 'fanout'
|
15
|
+
passive = false
|
16
|
+
durable = false
|
17
|
+
auto_delete = false
|
18
|
+
internal = false
|
19
|
+
nowait = false
|
20
|
+
arguments = nil
|
21
|
+
method_frame = Declare.encode(channel, exchange, type, passive, durable, auto_delete, internal, nowait, arguments)
|
22
|
+
method_frame.payload.should == "\x00(\x00\n\x00\x00\x1Famqclient.adapters.em.exchange1\x06fanout\x00\x00\x00\x00\x00"
|
23
|
+
method_frame.channel.should == 1
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# describe DeclareOk do
|
29
|
+
# describe '.decode' do
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
|
33
|
+
describe Delete do
|
34
|
+
describe '.encode' do
|
35
|
+
it 'encodes the parameters into a MethodFrame' do
|
36
|
+
channel = 1
|
37
|
+
exchange = 'amqclient.adapters.em.exchange'
|
38
|
+
if_unused = false
|
39
|
+
nowait = false
|
40
|
+
method_frame = Delete.encode(channel, exchange, if_unused, nowait)
|
41
|
+
method_frame.payload.should == "\x00(\x00\x14\x00\x00\x1Eamqclient.adapters.em.exchange\x00"
|
42
|
+
method_frame.channel.should == 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# describe DeleteOk do
|
48
|
+
# describe '.decode' do
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
|
52
|
+
describe Bind do
|
53
|
+
describe '.encode' do
|
54
|
+
it 'encodes the parameters into a MethodFrame' do
|
55
|
+
channel = 1
|
56
|
+
destination = 'foo'
|
57
|
+
source = 'bar'
|
58
|
+
routing_key = 'xyz'
|
59
|
+
nowait = false
|
60
|
+
arguments = nil
|
61
|
+
method_frame = Bind.encode(channel, destination, source, routing_key, nowait, arguments)
|
62
|
+
method_frame.payload.should == "\x00(\x00\x1E\x00\x00\x03foo\x03bar\x03xyz\x00\x00\x00\x00\x00"
|
63
|
+
method_frame.channel.should == 1
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# describe BindOk do
|
69
|
+
# describe '.decode' do
|
70
|
+
# end
|
71
|
+
# end
|
72
|
+
|
73
|
+
describe Unbind do
|
74
|
+
describe '.encode' do
|
75
|
+
it 'encodes the parameters into a MethodFrame' do
|
76
|
+
channel = 1
|
77
|
+
destination = 'foo'
|
78
|
+
source = 'bar'
|
79
|
+
routing_key = 'xyz'
|
80
|
+
nowait = false
|
81
|
+
arguments = nil
|
82
|
+
method_frame = Unbind.encode(channel, destination, source, routing_key, nowait, arguments)
|
83
|
+
method_frame.payload.should == "\x00(\x00(\x00\x00\x03foo\x03bar\x03xyz\x00\x00\x00\x00\x00"
|
84
|
+
method_frame.channel.should == 1
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# describe UnbindOk do
|
90
|
+
# describe '.decode' do
|
91
|
+
# end
|
92
|
+
# end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -1,82 +1,97 @@
|
|
1
1
|
# encoding: binary
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
3
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
4
|
+
|
5
|
+
|
6
|
+
module AMQ
|
7
|
+
module Protocol
|
8
|
+
describe Frame do
|
9
|
+
describe ".encode" do
|
10
|
+
it "should raise FrameTypeError if type isn't one of: [:method, :header, :body, :heartbeat]" do
|
11
|
+
lambda { Frame.encode(nil, "", 0) }.should raise_error(FrameTypeError)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should raise FrameTypeError if type isn't valid (when type is a symbol)" do
|
15
|
+
expect { Frame.encode(:xyz, "test", 12) }.to raise_error(FrameTypeError)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should raise FrameTypeError if type isn't valid (when type is a number)" do
|
19
|
+
expect { Frame.encode(16, "test", 12) }.to raise_error(FrameTypeError)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should raise RuntimeError if channel isn't 0 or an integer in range 1..65535" do
|
23
|
+
lambda { Frame.encode(:method, "", -1) }.should raise_error(RuntimeError, /^Channel has to be 0 or an integer in range 1\.\.65535/)
|
24
|
+
lambda { Frame.encode(:method, "", 65536) }.should raise_error(RuntimeError, /^Channel has to be 0 or an integer in range 1\.\.65535/)
|
25
|
+
lambda { Frame.encode(:method, "", 65535) }.should_not raise_error(RuntimeError, /^Channel has to be 0 or an integer in range 1\.\.65535/)
|
26
|
+
lambda { Frame.encode(:method, "", 0) }.should_not raise_error(RuntimeError, /^Channel has to be 0 or an integer in range 1\.\.65535/)
|
27
|
+
lambda { Frame.encode(:method, "", 1) }.should_not raise_error(RuntimeError, /^Channel has to be 0 or an integer in range 1\.\.65535/)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should raise RuntimeError if payload is nil" do
|
31
|
+
lambda { Frame.encode(:method, nil, 0) }.should raise_error(RuntimeError, "Payload can't be nil")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should encode type" do
|
35
|
+
Frame.encode(:body, "", 0).unpack("c").first.should eql(3)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should encode channel" do
|
39
|
+
Frame.encode(:body, "", 12).unpack("cn").last.should eql(12)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should encode size" do
|
43
|
+
Frame.encode(:body, "test", 12).unpack("cnN").last.should eql(4)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should include payload" do
|
47
|
+
Frame.encode(:body, "test", 12)[7..-2].should eql("test")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should include final octet" do
|
51
|
+
Frame.encode(:body, "test", 12).should =~ /\xCE$/
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should encode unicode strings" do
|
55
|
+
expect { Frame.encode(:body, "à bientôt!", 12) }.to_not raise_error
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe ".new" do
|
60
|
+
it "should raise FrameTypeError if the type is not one of the accepted" do
|
61
|
+
expect { Frame.new(10) }.to raise_error(FrameTypeError)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#decode_header' do
|
66
|
+
it 'raises FrameTypeError if the decoded type is not one of the accepted' do
|
67
|
+
expect { Frame.decode_header("\n\x00\x01\x00\x00\x00\x05") }.to raise_error(FrameTypeError)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'raises EmptyResponseError if the header is nil' do
|
71
|
+
expect { Frame.decode_header(nil) }.to raise_error(EmptyResponseError)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe HeaderFrame do
|
76
|
+
subject { HeaderFrame.new("\x00<\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\x98\x00\x18application/octet-stream\x02\x00", nil) }
|
77
|
+
|
78
|
+
it "should decode body_size from payload" do
|
79
|
+
subject.body_size.should == 10
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should decode klass_id from payload" do
|
83
|
+
subject.klass_id.should == 60
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should decode weight from payload" do
|
87
|
+
subject.weight.should == 0
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should decode properties from payload" do
|
91
|
+
subject.properties[:delivery_mode].should == 2
|
92
|
+
subject.properties[:priority].should == 0
|
93
|
+
end
|
94
|
+
end
|
80
95
|
end
|
81
96
|
end
|
82
|
-
end
|
97
|
+
end
|