amq-protocol 2.2.0 → 2.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,17 +1,12 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- require File.expand_path('../../../spec_helper', __FILE__)
4
1
  require 'bigdecimal'
5
2
  require 'time'
6
3
 
7
-
8
4
  module AMQ
9
5
  module Protocol
10
- describe Table do
6
+ RSpec.describe Table do
11
7
  timestamp = Time.utc(2010, 12, 31, 23, 58, 59)
12
- bigdecimal_1 = BigDecimal.new("1.0")
13
- bigdecimal_2 = BigDecimal.new("5E-3")
14
-
8
+ bigdecimal_1 = BigDecimal("1.0")
9
+ bigdecimal_2 = BigDecimal("5E-3")
15
10
 
16
11
  DATA = {
17
12
  {} => "\x00\x00\x00\x00",
@@ -51,6 +46,16 @@ module AMQ
51
46
  to eql("\x00\x00\x00$\vcoordinatesF\x00\x00\x00\x13\tlongituded@2\x11\x11\x16\xA8\xB8\xF1".force_encoding(Encoding::ASCII_8BIT))
52
47
  end
53
48
 
49
+ it "should serialize long UTF-8 strings and symbols" do
50
+ long_utf8 = "à" * 192
51
+ long_ascii8 = long_utf8.dup.force_encoding(::Encoding::ASCII_8BIT)
52
+
53
+ input = { "utf8_string" => long_utf8, "utf8_symbol" => long_utf8.to_sym }
54
+ output = { "utf8_string" => long_ascii8, "utf8_symbol" => long_ascii8 }
55
+
56
+ expect(Table.decode(Table.encode(input))).to eq(output)
57
+ end
58
+
54
59
  DATA.each do |data, encoded|
55
60
  it "should return #{encoded.inspect} for #{data.inspect}" do
56
61
  expect(Table.encode(data)).to eql(encoded.force_encoding(Encoding::ASCII_8BIT))
@@ -209,7 +214,7 @@ module AMQ
209
214
  "rev" => 1.0,
210
215
  "spec" => {
211
216
  "url" => "http://bit.ly/hw2ELX",
212
- "utf8" => "à bientôt".force_encoding(::Encoding::ASCII_8BIT)
217
+ "utf8" => "à bientôt"
213
218
  }
214
219
  },
215
220
  "true" => true,
@@ -217,7 +222,7 @@ module AMQ
217
222
  "nil" => nil
218
223
  }
219
224
  }
220
- expect(Table.decode(Table.encode(input))).to eq(input)
225
+ expect(Table.decode(Table.encode(input))).to eq(input.tap { |r| r["hashval"]["protocol"]["spec"]["utf8"].force_encoding(::Encoding::ASCII_8BIT) })
221
226
  end
222
227
 
223
228
 
@@ -1,12 +1,9 @@
1
1
  # encoding: binary
2
2
 
3
- require File.expand_path('../../../spec_helper', __FILE__)
4
-
5
-
6
3
  module AMQ
7
4
  module Protocol
8
5
  class Tx
9
- describe Select do
6
+ RSpec.describe Select do
10
7
  describe '.encode' do
11
8
  it 'encodes the parameters into a MethodFrame' do
12
9
  channel = 1
@@ -17,12 +14,12 @@ module AMQ
17
14
  end
18
15
  end
19
16
 
20
- # describe SelectOk do
17
+ # RSpec.describe SelectOk do
21
18
  # describe '.decode' do
22
19
  # end
23
20
  # end
24
21
 
25
- describe Commit do
22
+ RSpec.describe Commit do
26
23
  describe '.encode' do
27
24
  it 'encodes the parameters into a MethodFrame' do
28
25
  channel = 1
@@ -32,13 +29,13 @@ module AMQ
32
29
  end
33
30
  end
34
31
  end
35
-
36
- # describe CommitOk do
32
+
33
+ # RSpec.describe CommitOk do
37
34
  # describe '.decode' do
38
35
  # end
39
36
  # end
40
37
 
41
- describe Rollback do
38
+ RSpec.describe Rollback do
42
39
  describe '.encode' do
43
40
  it 'encodes the parameters into a MethodFrame' do
44
41
  channel = 1
@@ -49,7 +46,7 @@ module AMQ
49
46
  end
50
47
  end
51
48
 
52
- # describe RollbackOk do
49
+ # RSpec.describe RollbackOk do
53
50
  # describe '.decode' do
54
51
  # end
55
52
  # end
@@ -1,17 +1,14 @@
1
- # -*- coding: utf-8 -*-
2
- require File.expand_path('../../../spec_helper', __FILE__)
3
-
4
1
  require 'time'
5
2
  require "amq/protocol/table_value_decoder"
6
3
 
7
4
  module AMQ
8
5
  module Protocol
9
- describe TableValueDecoder do
6
+ RSpec.describe TableValueDecoder do
10
7
 
11
8
  it "is capable of decoding basic arrays TableValueEncoder encodes" do
12
9
  input1 = [1, 2, 3]
13
10
 
14
- value, offset = described_class.decode_array(TableValueEncoder.encode(input1), 1)
11
+ value, _offset = described_class.decode_array(TableValueEncoder.encode(input1), 1)
15
12
  expect(value.size).to eq(3)
16
13
  expect(value.first).to eq(1)
17
14
  expect(value).to eq(input1)
@@ -20,7 +17,7 @@ module AMQ
20
17
 
21
18
  input2 = ["one", 2, "three"]
22
19
 
23
- value, offset = described_class.decode_array(TableValueEncoder.encode(input2), 1)
20
+ value, _offset = described_class.decode_array(TableValueEncoder.encode(input2), 1)
24
21
  expect(value.size).to eq(3)
25
22
  expect(value.first).to eq("one")
26
23
  expect(value).to eq(input2)
@@ -29,7 +26,7 @@ module AMQ
29
26
 
30
27
  input3 = ["one", 2, "three", 4.0, 5000000.0]
31
28
 
32
- value, offset = described_class.decode_array(TableValueEncoder.encode(input3), 1)
29
+ value, _offset = described_class.decode_array(TableValueEncoder.encode(input3), 1)
33
30
  expect(value.size).to eq(5)
34
31
  expect(value.last).to eq(5000000.0)
35
32
  expect(value).to eq(input3)
@@ -45,7 +42,7 @@ module AMQ
45
42
  # puts(TableValueEncoder.encode(input1).inspect)
46
43
 
47
44
 
48
- value, offset = described_class.decode_array(data1, 1)
45
+ value, _offset = described_class.decode_array(data1, 1)
49
46
  expect(value.size).to eq(2)
50
47
  expect(value.first).to eq(Hash["one" => 2])
51
48
  expect(value).to eq(input1)
@@ -54,7 +51,7 @@ module AMQ
54
51
 
55
52
  input2 = ["one", 2, { "three" => { "four" => 5.0 } }]
56
53
 
57
- value, offset = described_class.decode_array(TableValueEncoder.encode(input2), 1)
54
+ value, _offset = described_class.decode_array(TableValueEncoder.encode(input2), 1)
58
55
  expect(value.size).to eq(3)
59
56
  expect(value.last["three"]["four"]).to eq(5.0)
60
57
  expect(value).to eq(input2)
@@ -1,14 +1,10 @@
1
- # -*- coding: utf-8 -*-
2
- require File.expand_path('../../../spec_helper', __FILE__)
3
-
4
1
  require 'time'
5
2
  require "amq/protocol/table_value_encoder"
6
3
  require "amq/protocol/float_32bit"
7
4
 
8
5
  module AMQ
9
6
  module Protocol
10
- describe TableValueEncoder do
11
-
7
+ RSpec.describe TableValueEncoder do
12
8
 
13
9
  it "calculates size of string field values" do
14
10
  expect(described_class.field_value_size("amqp")).to eq(9)
@@ -1,10 +1,5 @@
1
- # encoding: binary
2
-
3
- require File.expand_path('../../spec_helper', __FILE__)
4
-
5
-
6
1
  module AMQ
7
- describe Protocol do
2
+ RSpec.describe Protocol do
8
3
  it "should have PROTOCOL_VERSION constant" do
9
4
  expect(Protocol::PROTOCOL_VERSION).to match(/^\d+\.\d+\.\d$/)
10
5
  end
@@ -1,9 +1,6 @@
1
- # encoding: utf-8
2
-
3
- require "spec_helper"
4
1
  require "amq/settings"
5
2
 
6
- describe AMQ::Settings do
3
+ RSpec.describe AMQ::Settings do
7
4
  describe ".default" do
8
5
  it "should provide some default values" do
9
6
  expect(AMQ::Settings.default).to_not be_nil
@@ -1,95 +1,280 @@
1
- # encoding: utf-8
2
-
3
- require "spec_helper"
4
1
  require "amq/uri"
5
2
 
6
- describe AMQ::URI, ".parse" do
7
- context "when schema is not one of [amqp, amqps]" do
8
- it "raises ArgumentError" do
9
- expect {
10
- described_class.parse_amqp_url("http://dev.rabbitmq.com")
11
- }.to raise_error(ArgumentError, /amqp or amqps schema/)
12
- end
13
- end
3
+ # https://www.rabbitmq.com/uri-spec.html
4
+ # http://www.ietf.org/rfc/rfc3986.txt
5
+ # https://tools.ietf.org/rfc/rfc5246.txt
14
6
 
7
+ RSpec.describe AMQ::URI do
8
+ describe ".parse" do
9
+ subject { described_class.parse(uri) }
15
10
 
16
- it "handles amqp:// URIs w/o path part" do
17
- val = described_class.parse_amqp_url("amqp://dev.rabbitmq.com")
11
+ context "schema is not amqp or amqps" do
12
+ let(:uri) { "http://rabbitmq" }
18
13
 
19
- expect(val[:vhost]).to be_nil # in this case, default / will be used
20
- expect(val[:host]).to eq("dev.rabbitmq.com")
21
- expect(val[:port]).to eq(5672)
22
- expect(val[:scheme]).to eq("amqp")
23
- expect(val[:ssl]).to be_falsey
24
- end
14
+ it "raises ArgumentError" do
15
+ expect { subject }.to raise_error(ArgumentError, /amqp or amqps schema/)
16
+ end
17
+ end
25
18
 
26
- it "handles amqps:// URIs w/o path part" do
27
- val = described_class.parse_amqp_url("amqps://dev.rabbitmq.com")
19
+ describe "host" do
20
+ context "present" do
21
+ let(:uri) { "amqp://rabbitmq" }
28
22
 
29
- expect(val[:vhost]).to be_nil
30
- expect(val[:host]).to eq("dev.rabbitmq.com")
31
- expect(val[:port]).to eq(5671)
32
- expect(val[:scheme]).to eq("amqps")
33
- expect(val[:ssl]).to be_truthy
34
- end
23
+ it "parses host" do
24
+ expect(subject[:host]).to eq("rabbitmq")
25
+ end
26
+ end
35
27
 
28
+ if RUBY_VERSION >= "2.2"
29
+ context "absent" do
30
+ let(:uri) { "amqp://" }
36
31
 
37
- context "when URI ends in a slash" do
38
- it "parses vhost as an empty string" do
39
- val = described_class.parse_amqp_url("amqp://dev.rabbitmq.com/")
32
+ # Note that according to the ABNF, the host component may not be absent, but it may be zero-length.
33
+ it "falls back to default nil host" do
34
+ expect(subject[:host]).to be_nil
35
+ end
36
+ end
37
+ end
40
38
 
41
- expect(val[:host]).to eq("dev.rabbitmq.com")
42
- expect(val[:port]).to eq(5672)
43
- expect(val[:scheme]).to eq("amqp")
44
- expect(val[:ssl]).to be_falsey
45
- expect(val[:vhost]).to eq("")
39
+ if RUBY_VERSION < "2.2"
40
+ context "absent" do
41
+ let(:uri) { "amqp://" }
42
+
43
+ # Note that according to the ABNF, the host component may not be absent, but it may be zero-length.
44
+ it "raises InvalidURIError" do
45
+ expect { subject[:host] }.to raise_error(URI::InvalidURIError, /bad URI\(absolute but no path\)/)
46
+ end
47
+ end
48
+ end
46
49
  end
47
- end
48
50
 
51
+ describe "port" do
52
+ context "present" do
53
+ let(:uri) { "amqp://rabbitmq:5672" }
54
+
55
+ it "parses port" do
56
+ expect(subject[:port]).to eq(5672)
57
+ end
58
+ end
49
59
 
50
- context "when URI ends in /%2Fvault" do
51
- it "parses vhost as /vault" do
52
- val = described_class.parse_amqp_url("amqp://dev.rabbitmq.com/%2Fvault")
60
+ context "absent" do
61
+ context "schema amqp" do
62
+ let(:uri) { "amqp://rabbitmq" }
53
63
 
54
- expect(val[:host]).to eq("dev.rabbitmq.com")
55
- expect(val[:port]).to eq(5672)
56
- expect(val[:scheme]).to eq("amqp")
57
- expect(val[:ssl]).to be_falsey
58
- expect(val[:vhost]).to eq("/vault")
64
+ it "falls back to 5672 port" do
65
+ expect(subject[:port]).to eq(5672)
66
+ end
67
+ end
68
+
69
+ context "schema amqps" do
70
+ let(:uri) { "amqps://rabbitmq" }
71
+
72
+ it "falls back to 5671 port" do
73
+ expect(subject[:port]).to eq(5671)
74
+ end
75
+ end
76
+ end
59
77
  end
60
- end
61
78
 
79
+ describe "username and passowrd" do
80
+ context "both present" do
81
+ let(:uri) { "amqp://alpha:beta@rabbitmq" }
62
82
 
63
- context "when URI is amqp://dev.rabbitmq.com/a.path.without.slashes" do
64
- it "parses vhost as a.path.without.slashes" do
65
- val = described_class.parse_amqp_url("amqp://dev.rabbitmq.com/a.path.without.slashes")
83
+ it "parses user and pass" do
84
+ expect(subject[:user]).to eq("alpha")
85
+ expect(subject[:pass]).to eq("beta")
86
+ end
87
+ end
66
88
 
67
- expect(val[:host]).to eq("dev.rabbitmq.com")
68
- expect(val[:port]).to eq(5672)
69
- expect(val[:scheme]).to eq("amqp")
70
- expect(val[:ssl]).to be_falsey
71
- expect(val[:vhost]).to eq("a.path.without.slashes")
89
+ context "only username present" do
90
+ let(:uri) { "amqp://alpha@rabbitmq" }
91
+
92
+ it "parses user and falls back to nil pass" do
93
+ expect(subject[:user]).to eq("alpha")
94
+ expect(subject[:pass]).to be_nil
95
+ end
96
+
97
+ context "with ':'" do
98
+ let(:uri) { "amqp://alpha:@rabbitmq" }
99
+
100
+ it "parses user and falls back to "" (empty) pass" do
101
+ expect(subject[:user]).to eq("alpha")
102
+ expect(subject[:pass]).to eq("")
103
+ end
104
+ end
105
+ end
106
+
107
+ context "only password present" do
108
+ let(:uri) { "amqp://:beta@rabbitmq" }
109
+
110
+ it "parses pass and falls back to "" (empty) user" do
111
+ expect(subject[:user]).to eq("")
112
+ expect(subject[:pass]).to eq("beta")
113
+ end
114
+ end
115
+
116
+ context "both absent" do
117
+ let(:uri) { "amqp://rabbitmq" }
118
+
119
+ it "falls back to nil user and pass" do
120
+ expect(subject[:user]).to be_nil
121
+ expect(subject[:pass]).to be_nil
122
+ end
123
+
124
+ context "with ':'" do
125
+ let(:uri) { "amqp://:@rabbitmq" }
126
+
127
+ it "falls back to "" (empty) user and "" (empty) pass" do
128
+ expect(subject[:user]).to eq("")
129
+ expect(subject[:pass]).to eq("")
130
+ end
131
+ end
132
+ end
133
+
134
+ context "%-encoded" do
135
+ let(:uri) { "amqp://%61lpha:bet%61@rabbitmq" }
136
+
137
+ it "parses user and pass" do
138
+ expect(subject[:user]).to eq("alpha")
139
+ expect(subject[:pass]).to eq("beta")
140
+ end
141
+ end
72
142
  end
73
- end
74
143
 
75
- context "when URI is amqp://dev.rabbitmq.com/a/path/with/slashes" do
76
- it "raises an ArgumentError" do
77
- expect { described_class.parse_amqp_url("amqp://dev.rabbitmq.com/a/path/with/slashes") }.to raise_error(ArgumentError)
144
+ describe "path" do
145
+ context "present" do
146
+ let(:uri) { "amqp://rabbitmq/staging" }
147
+
148
+ it "parses vhost" do
149
+ expect(subject[:vhost]).to eq("staging")
150
+ end
151
+
152
+ context "with dots" do
153
+ let(:uri) { "amqp://rabbitmq/staging.critical.subsystem-a" }
154
+
155
+ it "parses vhost" do
156
+ expect(subject[:vhost]).to eq("staging.critical.subsystem-a")
157
+ end
158
+ end
159
+
160
+ context "with slashes" do
161
+ let(:uri) { "amqp://rabbitmq/staging/critical/subsystem-a" }
162
+
163
+ it "raises ArgumentError" do
164
+ expect { subject[:vhost] }.to raise_error(ArgumentError)
165
+ end
166
+ end
167
+
168
+ context "with trailing slash" do
169
+ let(:uri) { "amqp://rabbitmq/" }
170
+
171
+ it "parses vhost as an empty string" do
172
+ expect(subject[:vhost]).to eq("")
173
+ end
174
+ end
175
+
176
+ context "with trailing %-encoded slashes" do
177
+ let(:uri) { "amqp://rabbitmq/%2Fstaging" }
178
+
179
+ it "parses vhost as string with leading slash" do
180
+ expect(subject[:vhost]).to eq("/staging")
181
+ end
182
+ end
183
+
184
+ context "%-encoded" do
185
+ let(:uri) { "amqp://rabbitmq/%2Fstaging%2Fcritical%2Fsubsystem-a" }
186
+
187
+ it "parses vhost as string with leading slash" do
188
+ expect(subject[:vhost]).to eq("/staging/critical/subsystem-a")
189
+ end
190
+ end
191
+ end
192
+
193
+ context "absent" do
194
+ let(:uri) { "amqp://rabbitmq" }
195
+
196
+ it "falls back to default nil vhost" do
197
+ expect(subject[:vhost]).to be_nil
198
+ end
199
+ end
78
200
  end
79
- end
80
201
 
202
+ describe "query parameters" do
203
+ context "present" do
204
+ let(:uri) { "amqp://rabbitmq?heartbeat=10&connection_timeout=100&channel_max=1000&auth_mechanism=plain&auth_mechanism=amqplain" }
205
+
206
+ it "parses client connection parameters" do
207
+ expect(subject[:heartbeat]).to eq(10)
208
+ expect(subject[:connection_timeout]).to eq(100)
209
+ expect(subject[:channel_max]).to eq(1000)
210
+ expect(subject[:auth_mechanism]).to eq(["plain", "amqplain"])
211
+ end
212
+ end
213
+
214
+ context "absent" do
215
+ let(:uri) { "amqp://rabbitmq" }
216
+
217
+ it "falls back to default client connection parameters" do
218
+ expect(subject[:heartbeat]).to be_nil
219
+ expect(subject[:connection_timeout]).to be_nil
220
+ expect(subject[:channel_max]).to be_nil
221
+ expect(subject[:auth_mechanism]).to be_empty
222
+ end
223
+ end
224
+
225
+ context "schema amqp" do
226
+ context "tls parameters" do
227
+ %w(verify fail_if_no_peer_cert cacertfile certfile keyfile).each do |tls_param|
228
+ describe "#{tls_param}" do
229
+ let(:uri) { "amqp://rabbitmq?#{tls_param}=value" }
230
+
231
+ it "raises ArgumentError" do
232
+ expect { subject }.to raise_error(ArgumentError, /The option '#{tls_param}' can only be used in URIs that use amqps schema/)
233
+ end
234
+ end
235
+ end
236
+ end
237
+ end
238
+
239
+ context "amqpa schema" do
240
+ context "TLS parameters in query string" do
241
+ context "case 1" do
242
+ let(:uri) { "amqps://rabbitmq?verify=true&fail_if_no_peer_cert=true&cacertfile=/examples/tls/cacert.pem&certfile=/examples/tls/client_cert.pem&keyfile=/examples/tls/client_key.pem" }
243
+
244
+ it "parses tls options" do
245
+ expect(subject[:verify]).to be_truthy
246
+ expect(subject[:fail_if_no_peer_cert]).to be_truthy
247
+ expect(subject[:cacertfile]).to eq("/examples/tls/cacert.pem")
248
+ expect(subject[:certfile]).to eq("/examples/tls/client_cert.pem")
249
+ expect(subject[:keyfile]).to eq("/examples/tls/client_key.pem")
250
+ end
251
+ end
252
+
253
+ context "case 2" do
254
+ let(:uri) { "amqps://bunny_gem:bunny_password@/bunny_testbed?heartbeat=10&connection_timeout=100&channel_max=1000&verify=false&cacertfile=spec/tls/ca_certificate.pem&certfile=spec/tls/client_certificate.pem&keyfile=spec/tls/client_key.pem" }
255
+
256
+ it "parses tls options" do
257
+ expect(subject[:verify]).to be_falsey
258
+ expect(subject[:fail_if_no_peer_cert]).to be_falsey
259
+ expect(subject[:cacertfile]).to eq("spec/tls/ca_certificate.pem")
260
+ expect(subject[:certfile]).to eq("spec/tls/client_certificate.pem")
261
+ expect(subject[:keyfile]).to eq("spec/tls/client_key.pem")
262
+ end
263
+ end
81
264
 
82
- context "when URI has username:password, for instance, amqp://hedgehog:t0ps3kr3t@hub.megacorp.internal" do
83
- it "parses them out" do
84
- val = described_class.parse_amqp_url("amqp://hedgehog:t0ps3kr3t@hub.megacorp.internal")
265
+ context "absent" do
266
+ let(:uri) { "amqps://rabbitmq" }
85
267
 
86
- expect(val[:host]).to eq("hub.megacorp.internal")
87
- expect(val[:port]).to eq(5672)
88
- expect(val[:scheme]).to eq("amqp")
89
- expect(val[:ssl]).to be_falsey
90
- expect(val[:user]).to eq("hedgehog")
91
- expect(val[:pass]).to eq("t0ps3kr3t")
92
- expect(val[:vhost]).to be_nil # in this case, default / will be used
268
+ it "falls back to default tls options" do
269
+ expect(subject[:verify]).to be_falsey
270
+ expect(subject[:fail_if_no_peer_cert]).to be_falsey
271
+ expect(subject[:cacertfile]).to be_nil
272
+ expect(subject[:certfile]).to be_nil
273
+ expect(subject[:keyfile]).to be_nil
274
+ end
275
+ end
276
+ end
277
+ end
93
278
  end
94
279
  end
95
280
  end