amq-protocol 2.2.0 → 2.3.2

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.
@@ -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