Hello community,

here is the log from the commit of package rubygem-bunny for openSUSE:Factory 
checked in at 2016-08-26 23:16:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rubygem-bunny (Old)
 and      /work/SRC/openSUSE:Factory/.rubygem-bunny.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "rubygem-bunny"

Changes:
--------
--- /work/SRC/openSUSE:Factory/rubygem-bunny/rubygem-bunny.changes      
2016-06-14 23:08:07.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.rubygem-bunny.new/rubygem-bunny.changes 
2016-08-26 23:16:45.000000000 +0200
@@ -1,0 +2,11 @@
+Sat Jul 23 09:01:36 UTC 2016 - [email protected]
+
+- Run fdupes to elide duplicate documentation files
+
+-------------------------------------------------------------------
+Thu Jul 21 04:29:18 UTC 2016 - [email protected]
+
+- updated to version 2.5.0
+ see installed ChangeLog.md
+
+-------------------------------------------------------------------

Old:
----
  bunny-2.4.0.gem

New:
----
  bunny-2.5.0.gem

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ rubygem-bunny.spec ++++++
--- /var/tmp/diff_new_pack.25Xpzs/_old  2016-08-26 23:16:46.000000000 +0200
+++ /var/tmp/diff_new_pack.25Xpzs/_new  2016-08-26 23:16:46.000000000 +0200
@@ -24,13 +24,14 @@
 #
 
 Name:           rubygem-bunny
-Version:        2.4.0
+Version:        2.5.0
 Release:        0
 %define mod_name bunny
 %define mod_full_name %{mod_name}-%{version}
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 BuildRequires:  %{ruby >= 2.0}
 BuildRequires:  %{rubygem gem2rpm}
+BuildRequires:  fdupes
 BuildRequires:  ruby-macros >= 5
 Url:            http://rubybunny.info
 Source:         http://rubygems.org/gems/%{mod_full_name}.gem
@@ -50,6 +51,7 @@
 %gem_install \
   --doc-files="ChangeLog.md LICENSE README.md" \
   -f
+%fdupes %buildroot/%_prefix
 
 %gem_packages
 

++++++ bunny-2.4.0.gem -> bunny-2.5.0.gem ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CONTRIBUTING.md new/CONTRIBUTING.md
--- old/CONTRIBUTING.md 2016-06-11 23:24:31.000000000 +0200
+++ new/CONTRIBUTING.md 2016-07-20 13:34:54.000000000 +0200
@@ -55,7 +55,7 @@
 ### Running Test Suites
 
 Prior to running the tests, configure the RabbitMQ permissions
-by running `./bin/ci/before_script`. The script uses `rabbitmqctl` and 
`rabbitmq-plugins`
+by running `./bin/ci/before_build`. The script uses `rabbitmqctl` and 
`rabbitmq-plugins`
 to set up RabbitMQ in a way that Bunny test suites expect. Two environment 
variables,
 `RABBITMQCTL` and `RABBITMQ_PLUGINS`, are available to control what 
`rabbitmqctl` and
 `rabbitmq-plugins` commands will be used. By default they are taken from `PATH`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ChangeLog.md new/ChangeLog.md
--- old/ChangeLog.md    2016-06-11 23:24:31.000000000 +0200
+++ new/ChangeLog.md    2016-07-20 13:34:54.000000000 +0200
@@ -1,4 +1,9 @@
-## Changes between Bunny 2.3.0 and 2.4.0 (unreleased)
+## Changes between Bunny 2.4.0 and 2.5.0 (unreleased)
+
+No changes yet.
+
+
+## Changes between Bunny 2.3.0 and 2.4.0 (June 11th, 2016)
 
 ### Unconfirmed Delivery Tag Set Reset on Network Recovery
 
Files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/bunny/channel.rb new/lib/bunny/channel.rb
--- old/lib/bunny/channel.rb    2016-06-11 23:24:31.000000000 +0200
+++ new/lib/bunny/channel.rb    2016-07-20 13:34:54.000000000 +0200
@@ -1783,6 +1783,8 @@
 
     # @private
     def wait_on_confirms_continuations
+      raise_if_no_longer_open!
+
       if @connection.threaded
         t = Thread.current
         @threads_waiting_on_confirms_continuations << t
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/bunny/exchange.rb new/lib/bunny/exchange.rb
--- old/lib/bunny/exchange.rb   2016-06-11 23:24:31.000000000 +0200
+++ new/lib/bunny/exchange.rb   2016-07-20 13:34:54.000000000 +0200
@@ -1,3 +1,5 @@
+require 'amq/protocol'
+
 module Bunny
   # Represents AMQP 0.9.1 exchanges.
   #
@@ -80,6 +82,8 @@
       @internal         = @options[:internal]
       @arguments        = @options[:arguments]
 
+      @bindings         = Set.new
+
       declare! unless opts[:no_declare] || predeclared? || (@name == 
AMQ::Protocol::EMPTY_STRING)
 
       @channel.register_exchange(self)
@@ -169,6 +173,7 @@
     # @api public
     def bind(source, opts = {})
       @channel.exchange_bind(source, self, opts)
+      @bindings.add(source: source, opts: opts)
 
       self
     end
@@ -189,6 +194,7 @@
     # @api public
     def unbind(source, opts = {})
       @channel.exchange_unbind(source, self, opts)
+      @bindings.delete(source: source, opts: opts)
 
       self
     end
@@ -214,8 +220,11 @@
 
     # @private
     def recover_from_network_failure
-      # puts "Recovering exchange #{@name} from network failure"
-      declare! unless predefined?
+      declare! unless @options[:no_declare] ||predefined?
+
+      @bindings.each do |b|
+        bind(b[:source], b[:opts])
+      end
     end
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/bunny/queue.rb new/lib/bunny/queue.rb
--- old/lib/bunny/queue.rb      2016-06-11 23:24:31.000000000 +0200
+++ new/lib/bunny/queue.rb      2016-07-20 13:34:54.000000000 +0200
@@ -341,7 +341,7 @@
       # TODO: inject and use logger
       # puts "Recovering queue #{@name}"
       begin
-        declare!
+        declare! unless @options[:no_declare]
 
         @channel.register_queue(self)
       rescue Exception => e
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/bunny/session.rb new/lib/bunny/session.rb
--- old/lib/bunny/session.rb    2016-06-11 23:24:31.000000000 +0200
+++ new/lib/bunny/session.rb    2016-07-20 13:34:54.000000000 +0200
@@ -108,6 +108,7 @@
     # @option connection_string_or_opts [String] :tls_key (nil) Path to client 
TLS/SSL private key file (.pem)
     # @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
     # @option connection_string_or_opts [String] :verify_peer (true) Whether 
TLS peer verification should be performed
+    # @option connection_string_or_opts [Keyword] :tls_version (negotiated) 
What TLS version should be used (:TLSv1, :TLSv1_1, or :TLSv1_2)
     # @option connection_string_or_opts [Integer] :continuation_timeout 
(15000) Timeout for client operations that expect a response (e.g. 
{Bunny::Queue#get}), in milliseconds.
     # @option connection_string_or_opts [Integer] :connection_timeout (5) 
Timeout in seconds for connecting to the server.
     # @option connection_string_or_opts [Proc] :hosts_shuffle_strategy A Proc 
that reorders a list of host strings, defaults to Array#shuffle
@@ -668,30 +669,28 @@
 
     # @private
     def recover_from_network_failure
-      begin
-        sleep @network_recovery_interval
-        @logger.debug "About to start connection recovery..."
+      sleep @network_recovery_interval
+      @logger.debug "About to start connection recovery..."
 
-        self.initialize_transport
+      self.initialize_transport
 
-        @logger.warn "Retrying connection on next host in line: 
#{@transport.host}:#{@transport.port}"
-        self.start
+      @logger.warn "Retrying connection on next host in line: 
#{@transport.host}:#{@transport.port}"
+      self.start
 
-        if open?
-          @recovering_from_network_failure = false
+      if open?
+        @recovering_from_network_failure = false
 
-          recover_channels
-        end
-      rescue HostListDepleted
-        reset_address_index
-        retry
-      rescue TCPConnectionFailedForAllHosts, TCPConnectionFailed, 
AMQ::Protocol::EmptyResponseError => e
-        @logger.warn "TCP connection failed, reconnecting in 
#{@network_recovery_interval} seconds"
-        sleep @network_recovery_interval
-        if should_retry_recovery?
-          @recovery_attempts -= 1 if @recovery_attempts
-          retry if recoverable_network_failure?(e)
-        end
+        recover_channels
+      end
+    rescue HostListDepleted
+      reset_address_index
+      retry
+    rescue TCPConnectionFailedForAllHosts, TCPConnectionFailed, 
AMQ::Protocol::EmptyResponseError => e
+      @logger.warn "TCP connection failed, reconnecting in 
#{@network_recovery_interval} seconds"
+      sleep @network_recovery_interval
+      if should_retry_recovery?
+        @recovery_attempts -= 1 if @recovery_attempts
+        retry if recoverable_network_failure?(e)
       end
     end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/bunny/version.rb new/lib/bunny/version.rb
--- old/lib/bunny/version.rb    2016-06-11 23:24:31.000000000 +0200
+++ new/lib/bunny/version.rb    2016-07-20 13:34:54.000000000 +0200
@@ -2,5 +2,5 @@
 
 module Bunny
   # @return [String] Version of the library
-  VERSION = "2.4.0"
+  VERSION = "2.5.0"
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata        2016-06-11 23:24:31.000000000 +0200
+++ new/metadata        2016-07-20 13:34:54.000000000 +0200
@@ -1,7 +1,7 @@
 --- !ruby/object:Gem::Specification
 name: bunny
 version: !ruby/object:Gem::Version
-  version: 2.4.0
+  version: 2.5.0
 platform: ruby
 authors:
 - Chris Duncan
@@ -12,7 +12,7 @@
 autorequire: 
 bindir: bin
 cert_chain: []
-date: 2016-06-11 00:00:00.000000000 Z
+date: 2016-07-20 00:00:00.000000000 Z
 dependencies:
 - !ruby/object:Gem::Dependency
   name: amq-protocol
@@ -150,7 +150,6 @@
 - spec/higher_level_api/integration/basic_return_spec.rb
 - spec/higher_level_api/integration/channel_close_spec.rb
 - spec/higher_level_api/integration/channel_open_spec.rb
-- spec/higher_level_api/integration/confirm_select_spec.rb
 - spec/higher_level_api/integration/connection_recovery_spec.rb
 - spec/higher_level_api/integration/connection_spec.rb
 - spec/higher_level_api/integration/connection_stop_spec.rb
@@ -209,6 +208,7 @@
 - spec/unit/concurrent/condition_spec.rb
 - spec/unit/concurrent/linked_continuation_queue_spec.rb
 - spec/unit/concurrent/synchronized_sorted_set_spec.rb
+- spec/unit/exchange_recovery_spec.rb
 - spec/unit/version_delivery_tag_spec.rb
 homepage: http://rubybunny.info
 licenses:
@@ -230,7 +230,7 @@
       version: '0'
 requirements: []
 rubyforge_project: 
-rubygems_version: 2.4.8
+rubygems_version: 2.5.1
 signing_key: 
 specification_version: 4
 summary: Popular easy to use Ruby client for RabbitMQ
@@ -250,7 +250,6 @@
 - spec/higher_level_api/integration/basic_return_spec.rb
 - spec/higher_level_api/integration/channel_close_spec.rb
 - spec/higher_level_api/integration/channel_open_spec.rb
-- spec/higher_level_api/integration/confirm_select_spec.rb
 - spec/higher_level_api/integration/connection_recovery_spec.rb
 - spec/higher_level_api/integration/connection_spec.rb
 - spec/higher_level_api/integration/connection_stop_spec.rb
@@ -309,5 +308,6 @@
 - spec/unit/concurrent/condition_spec.rb
 - spec/unit/concurrent/linked_continuation_queue_spec.rb
 - spec/unit/concurrent/synchronized_sorted_set_spec.rb
+- spec/unit/exchange_recovery_spec.rb
 - spec/unit/version_delivery_tag_spec.rb
 has_rdoc: true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/spec/higher_level_api/integration/confirm_select_spec.rb 
new/spec/higher_level_api/integration/confirm_select_spec.rb
--- old/spec/higher_level_api/integration/confirm_select_spec.rb        
2016-06-11 23:24:31.000000000 +0200
+++ new/spec/higher_level_api/integration/confirm_select_spec.rb        
1970-01-01 01:00:00.000000000 +0100
@@ -1,19 +0,0 @@
-require "spec_helper"
-
-describe Bunny::Channel, "#confirm_select" do
-  let(:connection) do
-    c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost 
=> "bunny_testbed")
-    c.start
-    c
-  end
-
-  after :each do
-    connection.close if connection.open?
-  end
-
-  it "is supported" do
-    connection.with_channel do |ch|
-      ch.confirm_select
-    end
-  end
-end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/spec/higher_level_api/integration/connection_recovery_spec.rb 
new/spec/higher_level_api/integration/connection_recovery_spec.rb
--- old/spec/higher_level_api/integration/connection_recovery_spec.rb   
2016-06-11 23:24:31.000000000 +0200
+++ new/spec/higher_level_api/integration/connection_recovery_spec.rb   
2016-07-20 13:34:54.000000000 +0200
@@ -1,403 +1,421 @@
 require "spec_helper"
 require "rabbitmq/http/client"
 
-unless ENV["CI"]
-  describe "Connection recovery" do
-    let(:connection)  {  }
-    let(:http_client) { RabbitMQ::HTTP::Client.new("http://127.0.0.1:15672";) }
-
-    def close_all_connections!
-      http_client.list_connections.each do |conn_info|
-        begin
-          http_client.close_connection(conn_info.name)
-        rescue Bunny::ConnectionForced
-          # This is not a problem, but the specs intermittently believe it is.
-        end
-      end
+describe "Connection recovery" do
+  let(:http_client) { RabbitMQ::HTTP::Client.new("http://127.0.0.1:15672";) }
+  let(:logger) { Logger.new($stderr).tap {|logger| logger.level = 
Logger::FATAL} }
+  let(:recovery_interval) { 0.2 }
+
+  it "reconnects after grace period" do
+    with_open do |c|
+      close_all_connections!
+      wait_on_loss_and_recovery_of { connections.any? }
     end
+  end
 
-    def wait_for_recovery
-      sleep 1.5
+  it "reconnects after grace period (with multiple hosts)" do
+    with_open_multi_host do |c|
+      close_all_connections!
+      wait_on_loss_and_recovery_of { connections.any? }
     end
+  end
 
-    def with_open(c = Bunny.new(:network_recovery_interval => 0.2, 
:recover_from_connection_close => true), &block)
-      begin
-        c.start
-        block.call(c)
-      ensure
-        c.close
-      end
+  it "reconnects after grace period (with multiple hosts, including a broken 
one)" do
+    with_open_multi_broken_host do |c|
+      close_all_connections!
+      wait_on_loss_and_recovery_of { connections.any? }
     end
+  end
 
-    def with_open_multi_host( c = Bunny.new( :hosts => ["127.0.0.1", 
"localhost"],
-                                             :network_recovery_interval => 0.2,
-                                             :recover_from_connection_close => 
true), &block)
-      begin
-        c.start
-        block.call(c)
-      ensure
-        c.close
-      end
+  it "recovers channels" do
+    with_open do |c|
+      ch1 = c.create_channel
+      ch2 = c.create_channel
+      close_all_connections!
+      poll_until { channels.count.zero? }
+      poll_until { channels.count == 2 }
+      expect(ch1).to be_open
+      expect(ch2).to be_open
     end
+  end
 
-    def with_open_multi_broken_host( c = Bunny.new( :hosts => ["broken", 
"127.0.0.1", "localhost"],
-                                             :hosts_shuffle_strategy => 
Proc.new { |hosts| hosts }, # We do not shuffle for these tests so we always 
hit the broken host
-                                             :network_recovery_interval => 0.2,
-                                             :recover_from_connection_close => 
true), &block)
-      begin
-        c.start
-        block.call(c)
-      ensure
-        c.close
-      end
+  it "recovers channels (with multiple hosts)" do
+    with_open_multi_host do |c|
+      ch1 = c.create_channel
+      ch2 = c.create_channel
+      close_all_connections!
+      poll_until { channels.count.zero? }
+      poll_until { channels.count == 2 }
+      expect(ch1).to be_open
+      expect(ch2).to be_open
     end
+  end
 
-    def with_recovery_attempts_limited_to(attempts = 3, &block)
-      c = Bunny.new(:recover_from_connection_close => true, 
:network_recovery_interval => 0.2, :recovery_attempts => attempts)
-      begin
-        c.start
-        block.call(c)
-      ensure
-        c.close
-      end
+  it "recovers channels (with multiple hosts, including a broken one)" do
+    with_open_multi_broken_host do |c|
+      ch1 = c.create_channel
+      ch2 = c.create_channel
+      close_all_connections!
+      poll_until { channels.count.zero? }
+      poll_until { channels.count == 2 }
+      expect(ch1).to be_open
+      expect(ch2).to be_open
     end
+  end
 
-    def ensure_queue_recovery(ch, q)
-      ch.confirm_select
-      q.purge
-      x = ch.default_exchange
-      x.publish("msg", :routing_key => q.name)
-      ch.wait_for_confirms
-      sleep 0.5
-      expect(q.message_count).to eq 1
-      q.purge
+  it "recovers basic.qos prefetch setting" do
+    with_open do |c|
+      ch = c.create_channel
+      ch.prefetch(11)
+      expect(ch.prefetch_count).to eq 11
+      expect(ch.prefetch_global).to be false
+      close_all_connections!
+      wait_on_loss_and_recovery_of { connections.any? }
+      expect(ch).to be_open
+      expect(ch.prefetch_count).to eq 11
+      expect(ch.prefetch_global).to be false
     end
+  end
 
-    def ensure_queue_binding_recovery(ch, x, q, routing_key = "")
-      ch.confirm_select
-      q.purge
-      x.publish("msg", :routing_key => routing_key)
-      ch.wait_for_confirms
-      sleep 0.5
-      expect(q.message_count).to eq 1
-      q.purge
+  it "recovers basic.qos prefetch global setting" do
+    with_open do |c|
+      ch = c.create_channel
+      ch.prefetch(42, true)
+      expect(ch.prefetch_count).to eq 42
+      expect(ch.prefetch_global).to be true
+      close_all_connections!
+      wait_on_loss_and_recovery_of { connections.any? }
+      expect(ch).to be_open
+      expect(ch.prefetch_count).to eq 42
+      expect(ch.prefetch_global).to be true
     end
+  end
 
-    def ensure_exchange_binding_recovery(ch, source, destination, routing_key 
= "")
+  it "recovers publisher confirms setting" do
+    with_open do |c|
+      ch = c.create_channel
       ch.confirm_select
-      q  = ch.queue("", :exclusive => true)
-      q.bind(destination, :routing_key => routing_key)
-
-      source.publish("msg", :routing_key => routing_key)
-      ch.wait_for_confirms
-      sleep 0.5
-      expect(q.message_count).to eq 1
-      q.delete
+      expect(ch).to be_using_publisher_confirms
+      close_all_connections!
+      wait_on_loss_and_recovery_of { connections.any? }
+      expect(ch).to be_open
+      expect(ch).to be_using_publisher_confirms
     end
+  end
 
-    #
-    # Examples
-    #
-
-    it "reconnects after grace period" do
-      with_open do |c|
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
-
-        wait_for_recovery
-        expect(c).to be_open
-      end
+  it "recovers transactionality setting" do
+    with_open do |c|
+      ch = c.create_channel
+      ch.tx_select
+      expect(ch).to be_using_tx
+      close_all_connections!
+      wait_on_loss_and_recovery_of { connections.any? }
+      expect(ch).to be_open
+      expect(ch).to be_using_tx
     end
+  end
 
-    it "reconnects after grace period (with multiple hosts)" do
-      with_open_multi_host do |c|
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
+  it "recovers client-named queues" do
+    with_open do |c|
+      ch = c.create_channel
+      q  = ch.queue("bunny.tests.recovery.client-named#{rand}")
+      close_all_connections!
+      wait_on_loss_and_recovery_of { connections.any? }
+      expect(ch).to be_open
+      ensure_queue_recovery(ch, q)
+      q.delete
+    end
+  end
 
-        wait_for_recovery
-        expect(c).to be_open
-      end
+  # a very simplistic test for queues inspired by #412
+  it "recovers client-named queues declared with passive = true" do
+    with_open do |c|
+      ch  = c.create_channel
+      ch2 = c.create_channel
+
+      n   = rand
+      s   = "bunny.tests.recovery.client-named#{n}"
+
+      q   = ch.queue(s)
+      q2  = ch2.queue(s, no_declare: true)
+
+      close_all_connections!
+      wait_on_loss_and_recovery_of { connections.any? }
+      expect(ch).to be_open
+      ensure_queue_recovery(ch, q)
+      q.delete
     end
+  end
 
-    it "reconnects after grace period (with multiple hosts, including a broken 
one)" do
-      with_open_multi_broken_host do |c|
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
 
-        wait_for_recovery
-        expect(c).to be_open
-      end
+  it "recovers server-named queues" do
+    with_open do |c|
+      ch = c.create_channel
+      q  = ch.queue("", :exclusive => true)
+      close_all_connections!
+      wait_on_loss_and_recovery_of { connections.any? }
+      expect(ch).to be_open
+      ensure_queue_recovery(ch, q)
     end
+  end
 
-    it "recovers channels" do
-      with_open do |c|
-        ch1 = c.create_channel
-        ch2 = c.create_channel
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
-
-        wait_for_recovery
-        expect(ch1).to be_open
-        expect(ch2).to be_open
-      end
+  it "recovers queue bindings" do
+    with_open do |c|
+      ch = c.create_channel
+      x  = ch.fanout("amq.fanout")
+      q  = ch.queue("", :exclusive => true)
+      q.bind(x)
+      close_all_connections!
+      wait_on_loss_and_recovery_of { connections.any? }
+      expect(ch).to be_open
+      ensure_queue_binding_recovery(ch, x, q)
     end
+  end
 
-    it "recovers channels (with multiple hosts)" do
-      with_open_multi_host do |c|
-        ch1 = c.create_channel
-        ch2 = c.create_channel
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
-
-        wait_for_recovery
-        expect(ch1).to be_open
-        expect(ch2).to be_open
-      end
-    end
+  it "recovers exchanges and their bindings" do
+    with_open do |c|
+      ch          = c.create_channel
+      source      = ch.fanout("source.exchange.recovery.example", auto_delete: 
true)
+      destination = ch.fanout("destination.exchange.recovery.example", 
auto_delete: true)
 
-    it "recovers channels (with multiple hosts, including a broken one)" do
-      with_open_multi_broken_host do |c|
-        ch1 = c.create_channel
-        ch2 = c.create_channel
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
-
-        wait_for_recovery
-        expect(ch1).to be_open
-        expect(ch2).to be_open
-      end
-    end
+      destination.bind(source)
 
-    it "recovers basic.qos prefetch setting" do
-      with_open do |c|
-        ch = c.create_channel
-        ch.prefetch(11)
-        expect(ch.prefetch_count).to eq 11
-        expect(ch.prefetch_global).to be false
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
-
-        wait_for_recovery
-        expect(ch).to be_open
-        expect(ch.prefetch_count).to eq 11
-        expect(ch.prefetch_global).to be false
-      end
-    end
+      # Exchanges won't get auto-deleted on connection loss unless they have
+      # had an exclusive queue bound to them.
+      dst_queue   = ch.queue("", exclusive: true)
+      dst_queue.bind(destination, routing_key: "")
 
-    it "recovers basic.qos prefetch global setting" do
-      with_open do |c|
-        ch = c.create_channel
-        ch.prefetch(42, true)
-        expect(ch.prefetch_count).to eq 42
-        expect(ch.prefetch_global).to be true
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
-
-        wait_for_recovery
-        expect(ch).to be_open
-        expect(ch.prefetch_count).to eq 42
-        expect(ch.prefetch_global).to be true
-      end
-    end
+      src_queue   = ch.queue("", exclusive: true)
+      src_queue.bind(source, routing_key: "")
 
-    it "recovers publisher confirms setting" do
-      with_open do |c|
-        ch = c.create_channel
-        ch.confirm_select
-        expect(ch).to be_using_publisher_confirms
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
-
-        wait_for_recovery
-        expect(ch).to be_open
-        expect(ch).to be_using_publisher_confirms
-      end
+      close_all_connections!
+
+      wait_on_loss_and_recovery_of { 
exchange_names_in_vhost("/").include?(source.name) }
+
+      ch.confirm_select
+
+      source.publish("msg", routing_key: "")
+      ch.wait_for_confirms
+      expect(dst_queue.message_count).to eq 1
     end
+  end
 
-    it "recovers transactionality setting" do
-      with_open do |c|
-        ch = c.create_channel
-        ch.tx_select
-        expect(ch).to be_using_tx
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
-
-        wait_for_recovery
-        expect(ch).to be_open
-        expect(ch).to be_using_tx
-      end
+  # this is a simplistic test that primarily execises the code path from #412
+  it "recovers exchanges that were declared with passive = true" do
+    with_open do |c|
+      ch          = c.create_channel
+      ch2         = c.create_channel
+      source      = ch.fanout("source.exchange.recovery.example", auto_delete: 
true)
+      destination = ch.fanout("destination.exchange.recovery.example", 
auto_delete: true)
+
+      source2      = ch2.fanout("source.exchange.recovery.example", 
no_declare: true)
+      destination2 = ch2.fanout("destination.exchange.recovery.example", 
no_declare: true)
+
+      destination.bind(source)
+
+      # Exchanges won't get auto-deleted on connection loss unless they have
+      # had an exclusive queue bound to them.
+      dst_queue   = ch.queue("", exclusive: true)
+      dst_queue.bind(destination, routing_key: "")
+
+      src_queue   = ch.queue("", exclusive: true)
+      src_queue.bind(source, routing_key: "")
+
+      close_all_connections!
+
+      wait_on_loss_and_recovery_of { 
exchange_names_in_vhost("/").include?(source.name) }
+
+      ch2.confirm_select
+
+      source2.publish("msg", routing_key: "")
+      ch2.wait_for_confirms
+      expect(dst_queue.message_count).to eq 1
     end
+  end
 
-    it "recovers client-named queues" do
-      with_open do |c|
-        ch = c.create_channel
-        q  = ch.queue("bunny.tests.recovery.client-named#{rand}")
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
-
-        wait_for_recovery
-        expect(ch).to be_open
-        ensure_queue_recovery(ch, q)
-        q.delete
-      end
+  it "recovers allocated channel ids" do
+    with_open do |c|
+      q = "queue#{Time.now.to_i}"
+      10.times { c.create_channel }
+      expect(c.queue_exists?(q)).to eq false
+      close_all_connections!
+      wait_on_loss_and_recovery_of { channels.any? }
+      # make sure the connection isn't closed shortly after
+      # due to "second 'channel.open' seen". MK.
+      expect(c).to be_open
+      sleep 0.1
+      expect(c).to be_open
+      sleep 0.1
+      expect(c).to be_open
     end
+  end
 
+  it "recovers consumers" do
+    with_open do |c|
+      delivered = false
 
-    it "recovers server-named queues" do
-      with_open do |c|
-        ch = c.create_channel
-        q  = ch.queue("", :exclusive => true)
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
-
-        wait_for_recovery
-        expect(ch).to be_open
-        ensure_queue_recovery(ch, q)
+      ch = c.create_channel
+      q  = ch.queue("", :exclusive => true)
+      q.subscribe do |_, _, _|
+        delivered = true
       end
+      close_all_connections!
+      wait_on_loss_and_recovery_of { connections.any? }
+      expect(ch).to be_open
+
+      q.publish("")
+
+      poll_until { delivered }
     end
+  end
 
-    it "recovers queue bindings" do
-      with_open do |c|
-        ch = c.create_channel
-        x  = ch.fanout("amq.fanout")
-        q  = ch.queue("", :exclusive => true)
-        q.bind(x)
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
-
-        wait_for_recovery
-        expect(ch).to be_open
-        ensure_queue_binding_recovery(ch, x, q)
-      end
+  it "recovers all consumers" do
+    n = 1024
+
+    with_open do |c|
+      ch = c.create_channel
+      q  = ch.queue("", :exclusive => true)
+      n.times { q.subscribe { |_, _, _| } }
+      close_all_connections!
+      wait_on_loss_and_recovery_of { connections.any? }
+      expect(ch).to be_open
+      sleep 0.5
+
+      expect(q.consumer_count).to eq n
     end
+  end
+
+  it "recovers all queues" do
+    n = 256
+
+    qs = []
+
+    with_open do |c|
+      ch = c.create_channel
 
-    it "recovers exchange bindings" do
-      with_open do |c|
-        ch = c.create_channel
-        x  = ch.fanout("amq.fanout")
-        x2 = ch.fanout("bunny.tests.recovery.fanout")
-        x2.bind(x)
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
-
-        wait_for_recovery
-        expect(ch).to be_open
-        ensure_exchange_binding_recovery(ch, x, x2)
+      n.times do
+        qs << ch.queue("", :exclusive => true)
       end
-    end
+      close_all_connections!
+      wait_on_loss_and_recovery_of { queue_names.include?(qs.first.name) }
+      sleep 0.5
+      expect(ch).to be_open
 
-    it "recovers allocated channel ids" do
-      with_open do |c|
-        q = "queue#{Time.now.to_i}"
-        10.times { c.create_channel }
-        expect(c.queue_exists?(q)).to eq false
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
-
-        wait_for_recovery
-        expect(c.queue_exists?(q)).to eq false
-        # make sure the connection isn't closed shortly after
-        # due to "second 'channel.open' seen". MK.
-        expect(c).to be_open
-        sleep 0.1
-        expect(c).to be_open
-        sleep 0.1
-        expect(c).to be_open
+      qs.each do |q|
+        ch.queue_declare(q.name, :passive => true)
       end
     end
+  end
 
-    it "recovers consumers" do
-      with_open do |c|
-        delivered = false
-
-        ch = c.create_channel
-        q  = ch.queue("", :exclusive => true)
-        q.subscribe do |_, _, _|
-          delivered = true
-        end
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
-
-        wait_for_recovery
-        expect(ch).to be_open
-
-        q.publish("")
-        sleep 0.5
-        expect(delivered).to eq true
-      end
+  it "tries to recover for a given number of attempts" do
+    pending "Need a fix for https://github.com/ruby-amqp/bunny/issues/408";
+    with_recovery_attempts_limited_to(2) do |c|
+      close_all_connections!
+      wait_on_loss_and_recovery_of { connections.any? }
+
+      close_all_connections!
+      wait_on_loss_and_recovery_of { connections.any? }
+
+      close_all_connections!
+      sleep(recovery_interval + 0.5)
+      expect(connections).to be_empty
     end
+  end
 
-    it "recovers all consumers" do
-      n = 1024
+  def exchange_names_in_vhost(vhost)
+    http_client.list_exchanges(vhost).map {|e| e["name"]}
+  end
 
-      with_open do |c|
-        ch = c.create_channel
-        q  = ch.queue("", :exclusive => true)
-        n.times do
-          q.subscribe do |_, _, _|
-            delivered = true
-          end
-        end
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
-
-        wait_for_recovery
-        sleep 1
-        expect(ch).to be_open
+  def connections
+    http_client.list_connections
+  end
 
-        expect(q.consumer_count).to eq n
-      end
+  def channels
+    http_client.list_channels
+  end
+
+  def queue_names
+    http_client.list_queues.map {|q| q["name"]}
+  end
+
+  def close_all_connections!
+    connections.each do |conn_info|
+      close_ignoring_permitted_exceptions(conn_info.name)
     end
+  end
 
-    it "recovers all queues" do
-      n = 256
+  def close_ignoring_permitted_exceptions(connection_name)
+    http_client.close_connection(connection_name)
+  rescue Bunny::ConnectionForced
+  end
 
-      qs = []
+  def wait_on_loss_and_recovery_of(&probe)
+    poll_while &probe
+    poll_until &probe
+  end
 
-      with_open do |c|
-        ch = c.create_channel
+  def poll_while(&probe)
+    Timeout::timeout(10) {
+      sleep 0.1 while probe[]
+    }
+  end
 
-        n.times do
-          qs << ch.queue("", :exclusive => true)
-        end
-        close_all_connections!
-        sleep 0.1
-        expect(c).not_to be_open
-
-        wait_for_recovery
-        sleep 1
-        expect(ch).to be_open
-
-        qs.each do |q|
-          ch.queue_declare(q.name, :passive => true)
-        end
-      end
-    end
+  def poll_until(&probe)
+    Timeout::timeout(10) {
+      sleep 0.1 until probe[]
+    }
+  end
 
-    it "tries to recover for a given number of attempts" do
-      with_recovery_attempts_limited_to(2) do |c|
-        close_all_connections!
-        expect(c).to 
receive(:start).exactly(2).times.and_raise(Bunny::TCPConnectionFailed.new("test"))
+  def with_open(c = Bunny.new(network_recovery_interval: recovery_interval,
+                              recover_from_connection_close: true,
+                              logger: logger), &block)
+    c.start
+    block.call(c)
+  ensure
+    c.close
+  end
 
-        wait_for_recovery
-      end
-    end
+  def with_open_multi_host(&block)
+    c = Bunny.new(hosts: ["127.0.0.1", "localhost"],
+                  network_recovery_interval: recovery_interval,
+                  recover_from_connection_close: true,
+                  logger: logger)
+    with_open(c, &block)
+  end
+
+  def with_open_multi_broken_host(&block)
+    c = Bunny.new(hosts: ["broken", "127.0.0.1", "localhost"],
+                  hosts_shuffle_strategy: Proc.new { |hosts| hosts }, # We do 
not shuffle for these tests so we always hit the broken host
+                  network_recovery_interval: recovery_interval,
+                  recover_from_connection_close: true,
+                  logger: logger)
+    with_open(c, &block)
+  end
+
+  def with_recovery_attempts_limited_to(attempts = 3, &block)
+    c = Bunny.new(recover_from_connection_close: true,
+                  network_recovery_interval: recovery_interval,
+                  recovery_attempts: attempts,
+                  logger: logger)
+    with_open(c, &block)
+  end
+
+  def ensure_queue_recovery(ch, q)
+    ch.confirm_select
+    q.purge
+    x = ch.default_exchange
+    x.publish("msg", routing_key: q.name)
+    ch.wait_for_confirms
+    expect(q.message_count).to eq 1
+    q.purge
+  end
+
+  def ensure_queue_binding_recovery(ch, x, q, routing_key = "")
+    ch.confirm_select
+    q.purge
+    x.publish("msg", routing_key: routing_key)
+    ch.wait_for_confirms
+    expect(q.message_count).to eq 1
+    q.purge
   end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/spec/higher_level_api/integration/publisher_confirms_spec.rb 
new/spec/higher_level_api/integration/publisher_confirms_spec.rb
--- old/spec/higher_level_api/integration/publisher_confirms_spec.rb    
2016-06-11 23:24:31.000000000 +0200
+++ new/spec/higher_level_api/integration/publisher_confirms_spec.rb    
2016-07-20 13:34:54.000000000 +0200
@@ -60,6 +60,18 @@
           }.not_to raise_error
 
         end
+
+        it "raises an error when called on a closed channel" do
+          ch = connection.create_channel
+
+          ch.confirm_select
+
+          ch.close
+
+          expect {
+            ch.wait_for_confirms
+          }.to raise_error(Bunny::ChannelAlreadyClosed)
+        end
       end
 
       context "when some of the messages get nacked" do
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/unit/exchange_recovery_spec.rb 
new/spec/unit/exchange_recovery_spec.rb
--- old/spec/unit/exchange_recovery_spec.rb     1970-01-01 01:00:00.000000000 
+0100
+++ new/spec/unit/exchange_recovery_spec.rb     2016-07-20 13:34:54.000000000 
+0200
@@ -0,0 +1,39 @@
+require_relative '../../lib/bunny/channel'
+require_relative '../../lib/bunny/exchange'
+
+module Bunny
+  describe Exchange do
+    context "recovery" do
+      it "recovers exchange bindings, unless already unbound" do
+        ch = instance_double(Bunny::Channel,
+                             exchange_declare: nil,
+                             register_exchange: nil)
+        src1 = Exchange.new(ch, "direct", "src1")
+        src2 = Exchange.new(ch, "direct", "src2")
+        src3 = Exchange.new(ch, "direct", "src3")
+        dst = Exchange.new(ch, "direct", "dst")
+
+        original_binds_count = 5
+        expected_rebinds_count = 3
+        expected_total_binds = original_binds_count + expected_rebinds_count
+        allow(ch).to 
receive(:exchange_bind).exactly(expected_total_binds).times
+
+        dst.bind(src1, routing_key: "abc")
+        dst.bind(src2, routing_key: "def")
+        dst.bind(src2, routing_key: "ghi")
+        dst.bind(src3, routing_key: "jkl")
+        dst.bind(src3, routing_key: "jkl", arguments: {"key" => "value"})
+
+        allow(ch).to receive(:exchange_unbind).twice
+        dst.unbind(src2, routing_key: "def")
+        dst.unbind(src3, routing_key: "jkl", arguments: {"key" => "value"})
+
+        expect(ch).to receive(:exchange_bind).with(src1, dst, routing_key: 
"abc")
+        expect(ch).to receive(:exchange_bind).with(src2, dst, routing_key: 
"ghi")
+        expect(ch).to receive(:exchange_bind).with(src3, dst, routing_key: 
"jkl")
+
+        dst.recover_from_network_failure
+      end
+    end
+  end
+end


Reply via email to