bunny 2.7.0 → 2.7.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f37583fb4c93085f91f358da46737f7e7e75db6a
4
- data.tar.gz: 0e76e67996978dffa4c80a3b91225c494e2d2b55
3
+ metadata.gz: 3f58b34695f1799decb5818ead7efbf21448656d
4
+ data.tar.gz: 4c8db08cd4581da8eab1bdd0afd81693d4042a55
5
5
  SHA512:
6
- metadata.gz: 01caa52176c8bec67e35c26964bc4e2c8aa5eaddea0503bc6c6b6b8b2b289894343baa260f68367fb00e80985accd0e48c17587916968cc75af78611e760c752
7
- data.tar.gz: ad6bf5194d91d866f340cc7688ac863d4062fed845a47c67794961f746dac8cd243fd634d5c552b3add73c1845f4f66a981cc51bbb88a62c22406f1a01a9666c
6
+ metadata.gz: 941c64ca6a10063df82456aec1f5dd4a44d5df67c6d9e74a73cfc41821b1b3d29f2ddfe260ea31434adb0697d5136d6cbc28e5a84e8adaca2b83d8897fb8d164
7
+ data.tar.gz: a3056eae41a6600aeed337094851c1f5f16e0f80e7b8170e2a7a18d22ac2caabdb0cf0ce69637c1f9f0ecdee7e693d1e9cf84dbc66ebfdd866bd6602a6b84a67
@@ -30,8 +30,10 @@ these. TLS (x509 PEM) certificates include a hostname-specific fields,
30
30
  the tests allow for expecting hostname overriding using the `BUNNY_RABBITMQ_HOSTNAME`
31
31
  environment variables (default value is `127.0.0.1`).
32
32
 
33
- Server, CA and client certificates can be found under `spec/tls`. They are supposed to be
34
- generated with [tls-gen](github.com/michaelklishin/tls-gen) or similar in the target environment.
33
+ Server, CA and client certificates can be found under `spec/tls`.
34
+ The location can be overridden via the `BUNNY_CERTIFICATE_DIR` environment variable.
35
+ It is supposed to target [tls-gen](https://github.com/michaelklishin/tls-gen)'s basic profile
36
+ output (result) directory on the host where specs are to be executed.
35
37
 
36
38
  Next up you'll need to prepare your node for the specs (just once):
37
39
 
@@ -1,8 +1,52 @@
1
- ## Changes between Bunny 2.7.0 and 2.8.0 (unreleased)
1
+ ## Changes between Bunny 2.7.1 and 2.7.2 (unreleased)
2
2
 
3
3
  No changes yet.
4
4
 
5
5
 
6
+ ## Changes between Bunny 2.7.0 and 2.7.1 (Sep 25th, 2017)
7
+
8
+ ### Sensible Socket Read Timeouts When RabbitMQ is Configured to Disabled Heartbeats
9
+
10
+ Bunny now correctly handles scenarios where server is configured
11
+ to disable heartbeats (which is a terrible idea, don't do it!)
12
+
13
+ GitHub issue: [#519](https://github.com/ruby-amqp/bunny/issues/519).
14
+
15
+ ### Bunny::Channel#basic_get Usability
16
+
17
+ `Bunny::Channel#basic_get` invoked with a non-existent queue now
18
+ throws a channel exception instead of a generic operation timeout.
19
+
20
+ GitHub issue: [#518](https://github.com/ruby-amqp/bunny/issues/518).
21
+
22
+ ### Spec Suite Improvements
23
+
24
+ `BUNNY_CERTIFICATE_DIR` environment variable now can be used
25
+ to override local CA and client certificate/key pair directory.
26
+ The directory is expected to be the result directory generated
27
+ by the basic [tls-gen](http://github.com/michaelklishin/tls-gen) profile.
28
+
29
+ TLSv1.0 is no longer used in tests because it's being disabled by default
30
+ by more and more installations as it has known vulnerabilities
31
+ and is no longer considered to be acceptable by several compliance
32
+ standards (e.g. PCI DSS).
33
+
34
+ ### Improved Synchronisation for channel.close Handlers
35
+
36
+ `channel.close` handler will now acquire a lock . This avoids concurrency
37
+ hazards in some rare scenarios when a channel is closed due a protocol
38
+ exception by the server and concurrently opened by user code
39
+ at the same time.
40
+
41
+ ### More Meaningful Error Messages in Bunny::Session#create_channel
42
+
43
+ Sometimes users attempt to open a channel on a connection that
44
+ isn't connected yet because `Bunny::Session#start` was never invoked.
45
+
46
+ `Bunny::Session#create_channel` will now provide a more sensible exception message
47
+ in those cases.
48
+
49
+
6
50
  ## Changes between Bunny 2.6.0 and 2.7.0 (May 11th, 2017)
7
51
 
8
52
  ### amq-protocol Update
data/README.md CHANGED
@@ -88,7 +88,7 @@ gem install bunny
88
88
  To use Bunny in a project managed with Bundler:
89
89
 
90
90
  ``` ruby
91
- gem "bunny", ">= 2.6.5"
91
+ gem "bunny", ">= 2.7.0"
92
92
  ```
93
93
 
94
94
 
@@ -602,7 +602,12 @@ module Bunny
602
602
  # we implement them). So we return a triple of nils immediately which apps should be
603
603
  # able to handle anyway as "got no message, no need to act". MK.
604
604
  last_basic_get_response = if @connection.open?
605
- wait_on_basic_get_continuations
605
+ begin
606
+ wait_on_basic_get_continuations
607
+ rescue Timeout::Error => e
608
+ raise_if_continuation_resulted_in_a_channel_error!
609
+ raise e
610
+ end
606
611
  else
607
612
  [nil, nil, nil]
608
613
  end
@@ -101,16 +101,18 @@ module Bunny
101
101
  # @option connection_string_or_opts [String] :username ("guest") Username
102
102
  # @option connection_string_or_opts [String] :password ("guest") Password
103
103
  # @option connection_string_or_opts [String] :vhost ("/") Virtual host to use
104
- # @option connection_string_or_opts [Integer] :heartbeat (600) Heartbeat interval. 0 means no heartbeat.
104
+ # @option connection_string_or_opts [Integer, Symbol] :heartbeat (:server) Heartbeat interval. :server means use the default suggested by RabbitMQ. 0 means no heartbeat (not recommended).
105
105
  # @option connection_string_or_opts [Integer] :network_recovery_interval (4) Recovery interval periodic network recovery will use. This includes initial pause after network failure.
106
106
  # @option connection_string_or_opts [Boolean] :tls (false) Should TLS/SSL be used?
107
107
  # @option connection_string_or_opts [String] :tls_cert (nil) Path to client TLS/SSL certificate file (.pem)
108
108
  # @option connection_string_or_opts [String] :tls_key (nil) Path to client TLS/SSL private key file (.pem)
109
109
  # @option connection_string_or_opts [Array<String>] :tls_ca_certificates Array of paths to TLS/SSL CA files (.pem), by default detected from OpenSSL configuration
110
110
  # @option connection_string_or_opts [String] :verify_peer (true) Whether TLS peer verification should be performed
111
- # @option connection_string_or_opts [Keyword] :tls_version (negotiated) What TLS version should be used (:TLSv1, :TLSv1_1, or :TLSv1_2)
111
+ # @option connection_string_or_opts [Symbol] :tls_version (negotiated) What TLS version should be used (:TLSv1, :TLSv1_1, or :TLSv1_2)
112
112
  # @option connection_string_or_opts [Integer] :continuation_timeout (15000) Timeout for client operations that expect a response (e.g. {Bunny::Queue#get}), in milliseconds.
113
- # @option connection_string_or_opts [Integer] :connection_timeout (5) Timeout in seconds for connecting to the server.
113
+ # @option connection_string_or_opts [Integer] :connection_timeout (30) Timeout in seconds for connecting to the server.
114
+ # @option connection_string_or_opts [Integer] :read_timeout (30) TCP socket read timeout in seconds.
115
+ # @option connection_string_or_opts [Integer] :write_timeout (30) TCP socket write timeout in seconds.
114
116
  # @option connection_string_or_opts [Proc] :hosts_shuffle_strategy A Proc that reorders a list of host strings, defaults to Array#shuffle
115
117
  # @option connection_string_or_opts [Logger] :logger The logger. If missing, one is created using :log_file and :log_level.
116
118
  # @option connection_string_or_opts [IO, String] :log_file The file or path to use when creating a logger. Defaults to STDOUT.
@@ -346,6 +348,7 @@ module Bunny
346
348
  def create_channel(n = nil, consumer_pool_size = 1, consumer_pool_abort_on_exception = false, consumer_pool_shutdown_timeout = 60)
347
349
  raise ArgumentError, "channel number 0 is reserved in the protocol and cannot be used" if 0 == n
348
350
  raise ConnectionAlreadyClosed if manually_closed?
351
+ raise RuntimeError, "this connection is not open. Was Bunny::Session#start invoked? Is automatic recovery enabled?" if !connected?
349
352
 
350
353
  @channel_mutex.synchronize do
351
354
  if n && (ch = @channels[n])
@@ -540,6 +543,16 @@ module Bunny
540
543
  end
541
544
  end
542
545
 
546
+ # @private
547
+ def find_channel(number)
548
+ @channels[number]
549
+ end
550
+
551
+ # @private
552
+ def synchronised_find_channel(number)
553
+ @channel_mutex.synchronize { @channels[number] }
554
+ end
555
+
543
556
  # @private
544
557
  def close_all_channels
545
558
  @channel_mutex.synchronize do
@@ -606,15 +619,20 @@ module Bunny
606
619
  @unblock_callback.call(method) if @unblock_callback
607
620
  when AMQ::Protocol::Channel::Close then
608
621
  begin
609
- ch = @channels[ch_number]
622
+ ch = synchronised_find_channel(ch_number)
623
+ # this includes sending a channel.close-ok and
624
+ # potentially invoking a user-provided callback,
625
+ # avoid doing that while holding a mutex lock. MK.
610
626
  ch.handle_method(method)
611
627
  ensure
628
+ # synchronises on @channel_mutex under the hood
612
629
  self.unregister_channel(ch)
613
630
  end
614
631
  when AMQ::Protocol::Basic::GetEmpty then
615
- @channels[ch_number].handle_basic_get_empty(method)
632
+ ch = find_channel(ch_number)
633
+ ch.handle_basic_get_empty(method)
616
634
  else
617
- if ch = @channels[ch_number]
635
+ if ch = find_channel(ch_number)
618
636
  ch.handle_method(method)
619
637
  else
620
638
  @logger.warn "Channel #{ch_number} is not open on this connection!"
@@ -1161,11 +1179,18 @@ module Bunny
1161
1179
 
1162
1180
  # We set the read_write_timeout to twice the heartbeat value
1163
1181
  # This allows us to miss a single heartbeat before we time out the socket.
1164
- @transport.read_timeout = if heartbeat_disabled?(@client_heartbeat)
1182
+ #
1183
+ # Since RabbitMQ can be configured to disable heartbeats (bad idea but technically
1184
+ # possible nonetheless), we need to take both client and server values into
1185
+ # consideration when deciding about using the heartbeat value for read timeouts.
1186
+ @transport.read_timeout = if heartbeat_disabled?(@client_heartbeat) || heartbeat_disabled?(@heartbeat)
1187
+ @logger.debug { "Will use default socket read timeout of #{Transport::DEFAULT_READ_TIMEOUT}" }
1165
1188
  Transport::DEFAULT_READ_TIMEOUT
1166
1189
  else
1167
1190
  # pad to account for edge cases. MK.
1168
- @heartbeat * 2.2
1191
+ n = @heartbeat * 2.2
1192
+ @logger.debug { "Will use socket read timeout of #{n}" }
1193
+ n
1169
1194
  end
1170
1195
 
1171
1196
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Bunny
4
4
  # @return [String] Version of the library
5
- VERSION = "2.7.0"
5
+ VERSION = "2.7.1"
6
6
  end
@@ -54,3 +54,27 @@ describe Bunny::Queue, "#pop" do
54
54
  end
55
55
  end
56
56
  end
57
+
58
+
59
+ describe Bunny::Channel, "#basic_get" do
60
+ let(:connection) do
61
+ c = Bunny.new(username: "bunny_gem", password: "bunny_password", vhost: "bunny_testbed",
62
+ automatically_recover: false, continuation_timeout: 3000)
63
+ c.start
64
+ c
65
+ end
66
+
67
+ after :each do
68
+ connection.close if connection.open?
69
+ end
70
+
71
+ context "with a non-existent queue" do
72
+ it "throws a NOT_FOUND" do
73
+ ch = connection.create_channel
74
+
75
+ expect do
76
+ ch.basic_get "non_existent_#{rand.to_s}"
77
+ end.to raise_error(Bunny::NotFound)
78
+ end
79
+ end
80
+ end
@@ -2,10 +2,14 @@
2
2
  require "spec_helper"
3
3
 
4
4
  unless ENV["CI"]
5
+ CERTIFICATE_DIR=ENV.fetch("BUNNY_CERTIFICATE_DIR", "./spec/tls")
6
+ puts "Will use certificates from #{CERTIFICATE_DIR}"
7
+
5
8
  shared_examples_for "successful TLS connection" do
6
9
  it "succeeds" do
7
- expect(connection).to be_tls
8
- ch = connection.create_channel
10
+ expect(subject).to be_tls
11
+ ch = subject.create_channel
12
+ ch.confirm_select
9
13
 
10
14
  q = ch.queue("", exclusive: true)
11
15
  x = ch.default_exchange
@@ -15,7 +19,7 @@ unless ENV["CI"]
15
19
  publish("xyzzy", routing_key: q.name).
16
20
  publish("xyzzy", routing_key: q.name)
17
21
 
18
- sleep 0.5
22
+ x.wait_for_confirms
19
23
  expect(q.message_count).to eq 4
20
24
 
21
25
  i = 0
@@ -41,9 +45,9 @@ unless ENV["CI"]
41
45
  :vhost => "bunny_testbed",
42
46
  :tls => true,
43
47
  :verify_peer => verify_peer,
44
- :tls_cert => "spec/tls/client_certificate.pem",
45
- :tls_key => "spec/tls/client_key.pem",
46
- :tls_ca_certificates => ["./spec/tls/ca_certificate.pem"])
48
+ :tls_cert => "#{CERTIFICATE_DIR}/client_certificate.pem",
49
+ :tls_key => "#{CERTIFICATE_DIR}/client_key.pem",
50
+ :tls_ca_certificates => ["#{CERTIFICATE_DIR}/ca_certificate.pem"])
47
51
  end
48
52
 
49
53
  context "peer verification is off" do
@@ -58,6 +62,10 @@ unless ENV["CI"]
58
62
  subject.start
59
63
  expect(subject.transport.socket.hostname).to_not be_empty
60
64
  end
65
+
66
+ after :each do
67
+ subject.close
68
+ end
61
69
  end
62
70
 
63
71
  context "peer verification is on" do
@@ -70,21 +78,21 @@ unless ENV["CI"]
70
78
  end
71
79
 
72
80
  describe "TLS connection to RabbitMQ with client certificates" do
73
- let(:connection) do
81
+ let(:subject) do
74
82
  c = Bunny.new(username: "bunny_gem",
75
83
  password: "bunny_password",
76
84
  vhost: "bunny_testbed",
77
85
  tls: true,
78
- tls_cert: "spec/tls/client_certificate.pem",
79
- tls_key: "spec/tls/client_key.pem",
80
- tls_ca_certificates: ["./spec/tls/ca_certificate.pem"],
86
+ tls_cert: "#{CERTIFICATE_DIR}/client_certificate.pem",
87
+ tls_key: "#{CERTIFICATE_DIR}/client_key.pem",
88
+ tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
81
89
  verify_peer: false)
82
90
  c.start
83
91
  c
84
92
  end
85
93
 
86
94
  after :each do
87
- connection.close
95
+ subject.close
88
96
  end
89
97
 
90
98
  include_examples "successful TLS connection"
@@ -92,19 +100,19 @@ unless ENV["CI"]
92
100
 
93
101
 
94
102
  describe "TLS connection to RabbitMQ without client certificates" do
95
- let(:connection) do
103
+ let(:subject) do
96
104
  c = Bunny.new(username: "bunny_gem",
97
105
  password: "bunny_password",
98
106
  vhost: "bunny_testbed",
99
107
  tls: true,
100
- tls_ca_certificates: ["./spec/tls/ca_certificate.pem"],
108
+ tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
101
109
  verify_peer: false)
102
110
  c.start
103
111
  c
104
112
  end
105
113
 
106
114
  after :each do
107
- connection.close
115
+ subject.close
108
116
  end
109
117
 
110
118
  include_examples "successful TLS connection"
@@ -112,18 +120,18 @@ unless ENV["CI"]
112
120
 
113
121
 
114
122
  describe "TLS connection to RabbitMQ with a connection string" do
115
- let(:connection) do
123
+ let(:subject) do
116
124
  c = Bunny.new("amqps://bunny_gem:bunny_password@#{local_hostname}/bunny_testbed",
117
- tls_cert: "spec/tls/client_certificate.pem",
118
- tls_key: "spec/tls/client_key.pem",
119
- tls_ca_certificates: ["./spec/tls/ca_certificate.pem"],
125
+ tls_cert: "#{CERTIFICATE_DIR}/client_certificate.pem",
126
+ tls_key: "#{CERTIFICATE_DIR}/client_key.pem",
127
+ tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
120
128
  verify_peer: false)
121
129
  c.start
122
130
  c
123
131
  end
124
132
 
125
133
  after :each do
126
- connection.close
134
+ subject.close
127
135
  end
128
136
 
129
137
  include_examples "successful TLS connection"
@@ -131,16 +139,16 @@ unless ENV["CI"]
131
139
 
132
140
 
133
141
  describe "TLS connection to RabbitMQ with a connection string and w/o client certificate and key" do
134
- let(:connection) do
142
+ let(:subject) do
135
143
  c = Bunny.new("amqps://bunny_gem:bunny_password@#{local_hostname}/bunny_testbed",
136
- tls_ca_certificates: ["./spec/tls/ca_certificate.pem"],
144
+ tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
137
145
  verify_peer: verify_peer)
138
146
  c.start
139
147
  c
140
148
  end
141
149
 
142
150
  after :each do
143
- connection.close
151
+ subject.close
144
152
  end
145
153
 
146
154
  context "peer verification is off" do
@@ -150,7 +158,7 @@ unless ENV["CI"]
150
158
 
151
159
  it "sends the SNI details" do
152
160
  # https://github.com/ruby-amqp/bunny/issues/440
153
- expect(connection.transport.socket.hostname).to_not be_empty
161
+ expect(subject.transport.socket.hostname).to_not be_empty
154
162
  end
155
163
  end
156
164
 
@@ -161,54 +169,54 @@ unless ENV["CI"]
161
169
 
162
170
  it "sends the SNI details" do
163
171
  # https://github.com/ruby-amqp/bunny/issues/440
164
- expect(connection.transport.socket.hostname).to_not be_empty
172
+ expect(subject.transport.socket.hostname).to_not be_empty
165
173
  end
166
174
  end
167
175
  end
168
176
 
169
177
 
170
178
  describe "TLS connection to RabbitMQ with client certificates provided inline" do
171
- let(:connection) do
179
+ let(:subject) do
172
180
  c = Bunny.new(username: "bunny_gem",
173
181
  password: "bunny_password",
174
182
  vhost: "bunny_testbed",
175
183
  tls: true,
176
- tls_cert: File.read("./spec/tls/client_certificate.pem"),
177
- tls_key: File.read("./spec/tls/client_key.pem"),
178
- tls_ca_certificates: ["./spec/tls/ca_certificate.pem"],
184
+ tls_cert: File.read("#{CERTIFICATE_DIR}/client_certificate.pem"),
185
+ tls_key: File.read("#{CERTIFICATE_DIR}/client_key.pem"),
186
+ tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
179
187
  verify_peer: false)
180
188
  c.start
181
189
  c
182
190
  end
183
191
 
184
192
  after :each do
185
- connection.close
193
+ subject.close
186
194
  end
187
195
 
188
196
  include_examples "successful TLS connection"
189
197
  end
190
198
 
191
- describe "TLS connection to RabbitMQ with tls_version TLSv1 specified" do
192
- let(:connection) do
199
+ describe "TLS connection to RabbitMQ with tls_version TLSv1.1 specified" do
200
+ let(:subject) do
193
201
  c = Bunny.new(username: "bunny_gem",
194
202
  password: "bunny_password",
195
203
  vhost: "bunny_testbed",
196
204
  tls: true,
197
- tls_protocol: :TLSv1,
198
- tls_ca_certificates: ["./spec/tls/ca_certificate.pem"],
205
+ tls_protocol: :TLSv1_1,
206
+ tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
199
207
  verify_peer: false)
200
208
  c.start
201
209
  c
202
210
  end
203
211
 
204
212
  after :each do
205
- connection.close
213
+ subject.close
206
214
  end
207
215
 
208
216
  include_examples "successful TLS connection"
209
217
 
210
- it "connects using TLSv1" do
211
- expect(connection.transport.socket.ssl_version).to eq "TLSv1"
218
+ it "connects using TLSv1.1" do
219
+ expect(subject.transport.socket.ssl_version).to eq "TLSv1.1"
212
220
  end
213
221
  end
214
222
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bunny
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.0
4
+ version: 2.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Duncan
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2017-05-10 00:00:00.000000000 Z
15
+ date: 2017-09-24 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: amq-protocol
@@ -231,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
231
  version: '0'
232
232
  requirements: []
233
233
  rubyforge_project:
234
- rubygems_version: 2.6.11
234
+ rubygems_version: 2.6.13
235
235
  signing_key:
236
236
  specification_version: 4
237
237
  summary: Popular easy to use Ruby client for RabbitMQ