bunny 1.7.0 → 2.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. checksums.yaml +5 -5
  2. data/.github/ISSUE_TEMPLATE.md +18 -0
  3. data/.gitignore +6 -1
  4. data/.rspec +1 -3
  5. data/.travis.yml +21 -14
  6. data/CONTRIBUTING.md +132 -0
  7. data/ChangeLog.md +745 -1
  8. data/Gemfile +13 -13
  9. data/LICENSE +1 -1
  10. data/README.md +41 -75
  11. data/Rakefile +54 -0
  12. data/bunny.gemspec +4 -10
  13. data/docker-compose.yml +28 -0
  14. data/docker/Dockerfile +24 -0
  15. data/docker/apt/preferences.d/erlang +3 -0
  16. data/docker/apt/sources.list.d/bintray.rabbitmq.list +2 -0
  17. data/docker/docker-entrypoint.sh +26 -0
  18. data/docker/rabbitmq.conf +29 -0
  19. data/examples/connection/automatic_recovery_with_basic_get.rb +1 -1
  20. data/examples/connection/automatic_recovery_with_client_named_queues.rb +1 -1
  21. data/examples/connection/automatic_recovery_with_multiple_consumers.rb +1 -1
  22. data/examples/connection/automatic_recovery_with_republishing.rb +1 -1
  23. data/examples/connection/automatic_recovery_with_server_named_queues.rb +1 -1
  24. data/examples/connection/channel_level_exception.rb +1 -9
  25. data/examples/connection/disabled_automatic_recovery.rb +1 -1
  26. data/examples/connection/heartbeat.rb +1 -1
  27. data/examples/consumers/high_and_low_priority.rb +1 -1
  28. data/examples/guides/extensions/alternate_exchange.rb +2 -0
  29. data/examples/guides/getting_started/hello_world.rb +2 -0
  30. data/examples/guides/getting_started/weathr.rb +2 -0
  31. data/examples/guides/queues/one_off_consumer.rb +2 -0
  32. data/examples/guides/queues/redeliveries.rb +2 -0
  33. data/lib/bunny.rb +6 -2
  34. data/lib/bunny/channel.rb +192 -109
  35. data/lib/bunny/channel_id_allocator.rb +6 -4
  36. data/lib/bunny/concurrent/continuation_queue.rb +34 -13
  37. data/lib/bunny/consumer_work_pool.rb +34 -6
  38. data/lib/bunny/cruby/socket.rb +29 -16
  39. data/lib/bunny/cruby/ssl_socket.rb +20 -7
  40. data/lib/bunny/exceptions.rb +7 -1
  41. data/lib/bunny/exchange.rb +11 -7
  42. data/lib/bunny/get_response.rb +1 -1
  43. data/lib/bunny/heartbeat_sender.rb +3 -2
  44. data/lib/bunny/jruby/socket.rb +23 -6
  45. data/lib/bunny/jruby/ssl_socket.rb +5 -0
  46. data/lib/bunny/queue.rb +12 -10
  47. data/lib/bunny/reader_loop.rb +31 -18
  48. data/lib/bunny/session.rb +389 -134
  49. data/lib/bunny/test_kit.rb +14 -0
  50. data/lib/bunny/timeout.rb +1 -12
  51. data/lib/bunny/transport.rb +114 -67
  52. data/lib/bunny/version.rb +1 -1
  53. data/repl +1 -1
  54. data/spec/config/rabbitmq.conf +13 -0
  55. data/spec/higher_level_api/integration/basic_ack_spec.rb +154 -22
  56. data/spec/higher_level_api/integration/basic_cancel_spec.rb +77 -11
  57. data/spec/higher_level_api/integration/basic_consume_spec.rb +60 -55
  58. data/spec/higher_level_api/integration/basic_consume_with_objects_spec.rb +6 -6
  59. data/spec/higher_level_api/integration/basic_get_spec.rb +31 -7
  60. data/spec/higher_level_api/integration/basic_nack_spec.rb +22 -19
  61. data/spec/higher_level_api/integration/basic_publish_spec.rb +11 -100
  62. data/spec/higher_level_api/integration/basic_qos_spec.rb +32 -4
  63. data/spec/higher_level_api/integration/basic_reject_spec.rb +94 -16
  64. data/spec/higher_level_api/integration/basic_return_spec.rb +4 -4
  65. data/spec/higher_level_api/integration/channel_close_spec.rb +51 -10
  66. data/spec/higher_level_api/integration/channel_open_spec.rb +12 -12
  67. data/spec/higher_level_api/integration/connection_recovery_spec.rb +412 -286
  68. data/spec/higher_level_api/integration/connection_spec.rb +284 -134
  69. data/spec/higher_level_api/integration/connection_stop_spec.rb +31 -19
  70. data/spec/higher_level_api/integration/consumer_cancellation_notification_spec.rb +17 -17
  71. data/spec/higher_level_api/integration/dead_lettering_spec.rb +14 -14
  72. data/spec/higher_level_api/integration/exchange_bind_spec.rb +5 -5
  73. data/spec/higher_level_api/integration/exchange_declare_spec.rb +32 -31
  74. data/spec/higher_level_api/integration/exchange_delete_spec.rb +12 -12
  75. data/spec/higher_level_api/integration/exchange_unbind_spec.rb +5 -5
  76. data/spec/higher_level_api/integration/exclusive_queue_spec.rb +5 -5
  77. data/spec/higher_level_api/integration/heartbeat_spec.rb +4 -4
  78. data/spec/higher_level_api/integration/message_properties_access_spec.rb +49 -49
  79. data/spec/higher_level_api/integration/predeclared_exchanges_spec.rb +2 -2
  80. data/spec/higher_level_api/integration/publisher_confirms_spec.rb +92 -27
  81. data/spec/higher_level_api/integration/publishing_edge_cases_spec.rb +19 -19
  82. data/spec/higher_level_api/integration/queue_bind_spec.rb +23 -23
  83. data/spec/higher_level_api/integration/queue_declare_spec.rb +129 -34
  84. data/spec/higher_level_api/integration/queue_delete_spec.rb +2 -2
  85. data/spec/higher_level_api/integration/queue_purge_spec.rb +5 -5
  86. data/spec/higher_level_api/integration/queue_unbind_spec.rb +6 -6
  87. data/spec/higher_level_api/integration/read_only_consumer_spec.rb +9 -9
  88. data/spec/higher_level_api/integration/sender_selected_distribution_spec.rb +10 -10
  89. data/spec/higher_level_api/integration/tls_connection_spec.rb +218 -112
  90. data/spec/higher_level_api/integration/toxiproxy_spec.rb +76 -0
  91. data/spec/higher_level_api/integration/tx_commit_spec.rb +1 -1
  92. data/spec/higher_level_api/integration/tx_rollback_spec.rb +1 -1
  93. data/spec/higher_level_api/integration/with_channel_spec.rb +2 -2
  94. data/spec/issues/issue100_spec.rb +11 -12
  95. data/spec/issues/issue141_spec.rb +13 -14
  96. data/spec/issues/issue202_spec.rb +1 -1
  97. data/spec/issues/issue224_spec.rb +5 -5
  98. data/spec/issues/issue465_spec.rb +32 -0
  99. data/spec/issues/issue549_spec.rb +30 -0
  100. data/spec/issues/issue78_spec.rb +21 -24
  101. data/spec/issues/issue83_spec.rb +5 -6
  102. data/spec/issues/issue97_spec.rb +44 -45
  103. data/spec/lower_level_api/integration/basic_cancel_spec.rb +15 -16
  104. data/spec/lower_level_api/integration/basic_consume_spec.rb +20 -21
  105. data/spec/spec_helper.rb +2 -19
  106. data/spec/stress/channel_close_stress_spec.rb +3 -3
  107. data/spec/stress/channel_open_stress_spec.rb +4 -4
  108. data/spec/stress/channel_open_stress_with_single_threaded_connection_spec.rb +7 -7
  109. data/spec/stress/concurrent_consumers_stress_spec.rb +18 -16
  110. data/spec/stress/concurrent_publishers_stress_spec.rb +16 -19
  111. data/spec/stress/connection_open_close_spec.rb +9 -9
  112. data/spec/stress/merry_go_round_spec.rb +105 -0
  113. data/spec/tls/ca_certificate.pem +27 -16
  114. data/spec/tls/ca_key.pem +52 -27
  115. data/spec/tls/client_certificate.pem +27 -16
  116. data/spec/tls/client_key.pem +49 -25
  117. data/spec/tls/generate-server-cert.sh +8 -0
  118. data/spec/tls/server-openssl.cnf +10 -0
  119. data/spec/tls/server.csr +16 -0
  120. data/spec/tls/server_certificate.pem +27 -16
  121. data/spec/tls/server_key.pem +49 -25
  122. data/spec/toxiproxy_helper.rb +28 -0
  123. data/spec/unit/bunny_spec.rb +5 -5
  124. data/spec/unit/concurrent/atomic_fixnum_spec.rb +6 -6
  125. data/spec/unit/concurrent/condition_spec.rb +8 -8
  126. data/spec/unit/concurrent/linked_continuation_queue_spec.rb +2 -2
  127. data/spec/unit/concurrent/synchronized_sorted_set_spec.rb +16 -16
  128. data/spec/unit/exchange_recovery_spec.rb +39 -0
  129. data/spec/unit/version_delivery_tag_spec.rb +3 -3
  130. metadata +42 -35
  131. data/lib/bunny/system_timer.rb +0 -20
  132. data/spec/config/rabbitmq.config +0 -18
  133. data/spec/higher_level_api/integration/basic_recover_spec.rb +0 -18
  134. data/spec/higher_level_api/integration/confirm_select_spec.rb +0 -19
  135. data/spec/higher_level_api/integration/consistent_hash_exchange_spec.rb +0 -50
  136. data/spec/higher_level_api/integration/merry_go_round_spec.rb +0 -85
  137. data/spec/stress/long_running_consumer_spec.rb +0 -83
  138. data/spec/tls/cacert.pem +0 -18
  139. data/spec/tls/client_cert.pem +0 -18
  140. data/spec/tls/server_cert.pem +0 -18
  141. data/spec/unit/system_timer_spec.rb +0 -10
@@ -2,7 +2,7 @@ require "spec_helper"
2
2
 
3
3
  describe Bunny::Exchange, "#delete" do
4
4
  let(:connection) do
5
- c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
5
+ c = Bunny.new(username: "bunny_gem", password: "bunny_password", vhost: "bunny_testbed")
6
6
  c.start
7
7
  c
8
8
  end
@@ -21,7 +21,7 @@ describe Bunny::Exchange, "#delete" do
21
21
  # no exception as of RabbitMQ 3.2. MK.
22
22
  x.delete
23
23
 
24
- ch.exchanges.size.should == 0
24
+ expect(ch.exchanges.size).to eq 0
25
25
  end
26
26
  end
27
27
 
@@ -43,7 +43,7 @@ describe Bunny::Exchange, "#delete" do
43
43
  ch = connection.create_channel
44
44
  x = ch.direct('amq.direct')
45
45
 
46
- x.delete.should == nil
46
+ expect(x.delete).to eq nil
47
47
  end
48
48
  end
49
49
 
@@ -52,7 +52,7 @@ describe Bunny::Exchange, "#delete" do
52
52
  ch = connection.create_channel
53
53
  x = ch.fanout('amq.fanout')
54
54
 
55
- x.delete.should == nil
55
+ expect(x.delete).to eq nil
56
56
  end
57
57
  end
58
58
 
@@ -61,7 +61,7 @@ describe Bunny::Exchange, "#delete" do
61
61
  ch = connection.create_channel
62
62
  x = ch.topic('amq.topic')
63
63
 
64
- x.delete.should == nil
64
+ expect(x.delete).to eq nil
65
65
  end
66
66
  end
67
67
 
@@ -70,7 +70,7 @@ describe Bunny::Exchange, "#delete" do
70
70
  ch = connection.create_channel
71
71
  x = ch.headers('amq.headers')
72
72
 
73
- x.delete.should == nil
73
+ expect(x.delete).to eq nil
74
74
  end
75
75
  end
76
76
 
@@ -79,7 +79,7 @@ describe Bunny::Exchange, "#delete" do
79
79
  ch = connection.create_channel
80
80
  x = ch.headers('amq.match')
81
81
 
82
- x.delete.should == nil
82
+ expect(x.delete).to eq nil
83
83
  end
84
84
  end
85
85
 
@@ -89,16 +89,16 @@ describe Bunny::Exchange, "#delete" do
89
89
  it "returns true" do
90
90
  ch = connection.create_channel
91
91
 
92
- connection.exchange_exists?("amq.fanout").should be_true
93
- connection.exchange_exists?("amq.direct").should be_true
94
- connection.exchange_exists?("amq.topic").should be_true
95
- connection.exchange_exists?("amq.match").should be_true
92
+ expect(connection.exchange_exists?("amq.fanout")).to eq true
93
+ expect(connection.exchange_exists?("amq.direct")).to eq true
94
+ expect(connection.exchange_exists?("amq.topic")).to eq true
95
+ expect(connection.exchange_exists?("amq.match")).to eq true
96
96
  end
97
97
  end
98
98
 
99
99
  context "when a exchange DOES NOT exist" do
100
100
  it "returns false" do
101
- connection.exchange_exists?("suf89u9a4jo3ndnakls##{Time.now.to_i}").should be_false
101
+ expect(connection.exchange_exists?("suf89u9a4jo3ndnakls##{Time.now.to_i}")).to eq false
102
102
  end
103
103
  end
104
104
  end
@@ -2,7 +2,7 @@ require "spec_helper"
2
2
 
3
3
  describe Bunny::Exchange do
4
4
  let(:connection) do
5
- c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
5
+ c = Bunny.new(username: "bunny_gem", password: "bunny_password", vhost: "bunny_testbed")
6
6
  c.start
7
7
  c
8
8
  end
@@ -17,21 +17,21 @@ describe Bunny::Exchange do
17
17
  source = ch.fanout("bunny.exchanges.source#{rand}")
18
18
  destination = ch.fanout("bunny.exchanges.destination#{rand}")
19
19
 
20
- queue = ch.queue("", :exclusive => true)
20
+ queue = ch.queue("", exclusive: true)
21
21
  queue.bind(destination)
22
22
 
23
23
  destination.bind(source)
24
24
  source.publish("")
25
25
  sleep 0.5
26
26
 
27
- queue.message_count.should be == 1
28
- queue.pop(:manual_ack => true)
27
+ expect(queue.message_count).to eq 1
28
+ queue.pop(manual_ack: true)
29
29
 
30
30
  destination.unbind(source)
31
31
  source.publish("")
32
32
  sleep 0.5
33
33
 
34
- queue.message_count.should be == 0
34
+ expect(queue.message_count).to eq 0
35
35
 
36
36
  source.delete
37
37
  destination.delete
@@ -2,7 +2,7 @@ require "spec_helper"
2
2
 
3
3
  describe Bunny::Queue do
4
4
  let(:connection) do
5
- c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
5
+ c = Bunny.new(username: "bunny_gem", password: "bunny_password", vhost: "bunny_testbed")
6
6
  c.start
7
7
  c
8
8
  end
@@ -14,13 +14,13 @@ describe Bunny::Queue do
14
14
  it "is closed when the connection it was declared on is closed" do
15
15
  ch1 = connection.create_channel
16
16
  ch2 = connection.create_channel
17
- q = ch1.queue("", :exclusive => true)
17
+ q = ch1.queue("", exclusive: true)
18
18
 
19
- ch1.queue_declare(q.name, :passive => true)
20
- ch2.queue_declare(q.name, :passive => true)
19
+ ch1.queue_declare(q.name, passive: true)
20
+ ch2.queue_declare(q.name, passive: true)
21
21
 
22
22
  ch1.close
23
- ch2.queue_declare(q.name, :passive => true)
23
+ ch2.queue_declare(q.name, passive: true)
24
24
 
25
25
  ch2.queue_delete(q.name)
26
26
  ch2.close
@@ -3,7 +3,7 @@ require "spec_helper"
3
3
  describe "Client-defined heartbeat interval" do
4
4
  context "with value > 0" do
5
5
  let(:connection) do
6
- c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed", :heartbeat_interval => 4)
6
+ c = Bunny.new(username: "bunny_gem", password: "bunny_password", vhost: "bunny_testbed", heartbeat_timeout: 4)
7
7
  c.start
8
8
  c
9
9
  end
@@ -18,8 +18,8 @@ describe "Client-defined heartbeat interval" do
18
18
  # issue 267
19
19
  context "with value = 0" do
20
20
  let(:connection) do
21
- c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed",
22
- :heartbeat_interval => 0, :automatically_recover => false)
21
+ c = Bunny.new(username: "bunny_gem", password: "bunny_password", vhost: "bunny_testbed",
22
+ heartbeat_timeout: 0, automatically_recover: false)
23
23
  c.start
24
24
  c
25
25
  end
@@ -35,7 +35,7 @@ end
35
35
 
36
36
  describe "Server-defined heartbeat interval" do
37
37
  let(:connection) do
38
- c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed", :heartbeat_interval => :server)
38
+ c = Bunny.new(username: "bunny_gem", password: "bunny_password", vhost: "bunny_testbed", heartbeat_timeout: :server)
39
39
  c.start
40
40
  c
41
41
  end
@@ -2,7 +2,7 @@ require "spec_helper"
2
2
 
3
3
  describe Bunny::Queue, "#subscribe" do
4
4
  let(:connection) do
5
- c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
5
+ c = Bunny.new(username: "bunny_gem", password: "bunny_password", vhost: "bunny_testbed")
6
6
  c.start
7
7
  c
8
8
  end
@@ -20,8 +20,8 @@ describe Bunny::Queue, "#subscribe" do
20
20
 
21
21
  t = Thread.new do
22
22
  ch = connection.create_channel
23
- q = ch.queue(queue_name, :auto_delete => true, :durable => false)
24
- q.subscribe(:exclusive => true, :manual_ack => false) do |delivery_info, properties, payload|
23
+ q = ch.queue(queue_name, auto_delete: true, durable: false)
24
+ q.subscribe(exclusive: true, manual_ack: false) do |delivery_info, properties, payload|
25
25
  metadata = properties
26
26
  envelope = delivery_info
27
27
  end
@@ -32,63 +32,63 @@ describe Bunny::Queue, "#subscribe" do
32
32
  ch = connection.create_channel
33
33
  x = ch.default_exchange
34
34
  x.publish("hello",
35
- :routing_key => queue_name,
36
- :app_id => "bunny.example",
37
- :priority => 8,
38
- :type => "kinda.checkin",
35
+ routing_key: queue_name,
36
+ app_id: "bunny.example",
37
+ priority: 8,
38
+ type: "kinda.checkin",
39
39
  # headers table keys can be anything
40
- :headers => {
41
- :coordinates => {
42
- :latitude => 59.35,
43
- :longitude => 18.066667
40
+ headers: {
41
+ coordinates: {
42
+ latitude: 59.35,
43
+ longitude: 18.066667
44
44
  },
45
- :time => @now,
46
- :participants => 11,
47
- :venue => "Stockholm",
48
- :true_field => true,
49
- :false_field => false,
50
- :nil_field => nil,
51
- :ary_field => ["one", 2.0, 3, [{"abc" => 123}]]
45
+ time: @now,
46
+ participants: 11,
47
+ venue: "Stockholm",
48
+ true_field: true,
49
+ false_field: false,
50
+ nil_field: nil,
51
+ ary_field: ["one", 2.0, 3, [{"abc" => 123}]]
52
52
  },
53
- :timestamp => @now.to_i,
54
- :reply_to => "a.sender",
55
- :correlation_id => "r-1",
56
- :message_id => "m-1")
53
+ timestamp: @now.to_i,
54
+ reply_to: "a.sender",
55
+ correlation_id: "r-1",
56
+ message_id: "m-1")
57
57
 
58
58
  sleep 0.7
59
59
 
60
- metadata.content_type.should == "application/octet-stream"
61
- metadata.priority.should == 8
60
+ expect(metadata.content_type).to eq "application/octet-stream"
61
+ expect(metadata.priority).to eq 8
62
62
 
63
63
  time = metadata.headers["time"]
64
- time.year.should == @now.year
65
- time.month.should == @now.month
66
- time.day.should == @now.day
67
- time.hour.should == @now.hour
68
- time.min.should == @now.min
69
- time.sec.should == @now.sec
64
+ expect(time.year).to eq @now.year
65
+ expect(time.month).to eq @now.month
66
+ expect(time.day).to eq @now.day
67
+ expect(time.hour).to eq @now.hour
68
+ expect(time.min).to eq @now.min
69
+ expect(time.sec).to eq @now.sec
70
70
 
71
- metadata.headers["coordinates"]["latitude"].should == 59.35
72
- metadata.headers["participants"].should == 11
73
- metadata.headers["venue"].should == "Stockholm"
74
- metadata.headers["true_field"].should == true
75
- metadata.headers["false_field"].should == false
76
- metadata.headers["nil_field"].should be_nil
77
- metadata.headers["ary_field"].should == ["one", 2.0, 3, [{ "abc" => 123}]]
71
+ expect(metadata.headers["coordinates"]["latitude"]).to eq 59.35
72
+ expect(metadata.headers["participants"]).to eq 11
73
+ expect(metadata.headers["venue"]).to eq "Stockholm"
74
+ expect(metadata.headers["true_field"]).to eq true
75
+ expect(metadata.headers["false_field"]).to eq false
76
+ expect(metadata.headers["nil_field"]).to be_nil
77
+ expect(metadata.headers["ary_field"]).to eq ["one", 2.0, 3, [{ "abc" => 123}]]
78
78
 
79
- metadata.timestamp.should == Time.at(@now.to_i)
80
- metadata.type.should == "kinda.checkin"
81
- metadata.reply_to.should == "a.sender"
82
- metadata.correlation_id.should == "r-1"
83
- metadata.message_id.should == "m-1"
84
- metadata.app_id.should == "bunny.example"
79
+ expect(metadata.timestamp).to eq Time.at(@now.to_i)
80
+ expect(metadata.type).to eq "kinda.checkin"
81
+ expect(metadata.reply_to).to eq "a.sender"
82
+ expect(metadata.correlation_id).to eq "r-1"
83
+ expect(metadata.message_id).to eq "m-1"
84
+ expect(metadata.app_id).to eq "bunny.example"
85
85
 
86
- envelope.consumer_tag.should_not be_nil
87
- envelope.consumer_tag.should_not be_empty
88
- envelope.should_not be_redelivered
89
- envelope.delivery_tag.should == 1
90
- envelope.routing_key.should == queue_name
91
- envelope.exchange.should == ""
86
+ expect(envelope.consumer_tag).not_to be_nil
87
+ expect(envelope.consumer_tag).not_to be_empty
88
+ expect(envelope).not_to be_redelivered
89
+ expect(envelope.delivery_tag).to eq 1
90
+ expect(envelope.routing_key).to eq queue_name
91
+ expect(envelope.exchange).to eq ""
92
92
 
93
93
  ch.close
94
94
  end
@@ -2,7 +2,7 @@ require "spec_helper"
2
2
 
3
3
  describe "amq.* exchanges" do
4
4
  let(:connection) do
5
- c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
5
+ c = Bunny.new(username: "bunny_gem", password: "bunny_password", vhost: "bunny_testbed")
6
6
  c.start
7
7
  c
8
8
  end
@@ -16,7 +16,7 @@ describe "amq.* exchanges" do
16
16
 
17
17
  ["amq.fanout", "amq.direct", "amq.topic", "amq.match", "amq.headers"].each do |e|
18
18
  x = ch.exchange(e)
19
- x.should be_predeclared
19
+ expect(x).to be_predeclared
20
20
  end
21
21
 
22
22
  ch.close
@@ -11,23 +11,23 @@ describe Bunny::Channel do
11
11
  context "when publishing with confirms enabled" do
12
12
  it "increments delivery index" do
13
13
  ch = connection.create_channel
14
- ch.should_not be_using_publisher_confirmations
14
+ expect(ch).not_to be_using_publisher_confirmations
15
15
 
16
16
  ch.confirm_select
17
- ch.should be_using_publisher_confirmations
17
+ expect(ch).to be_using_publisher_confirmations
18
18
 
19
- q = ch.queue("", :exclusive => true)
19
+ q = ch.queue("", exclusive: true)
20
20
  x = ch.default_exchange
21
21
 
22
22
  n.times do
23
- x.publish("xyzzy", :routing_key => q.name)
23
+ x.publish("xyzzy", routing_key: q.name)
24
24
  end
25
25
 
26
- ch.next_publish_seq_no.should == n + 1
27
- ch.wait_for_confirms.should be_true
26
+ expect(ch.next_publish_seq_no).to eq n + 1
27
+ expect(ch.wait_for_confirms).to eq true
28
28
  sleep 0.25
29
29
 
30
- q.message_count.should == n
30
+ expect(q.message_count).to eq n
31
31
  q.purge
32
32
 
33
33
  ch.close
@@ -36,45 +36,57 @@ describe Bunny::Channel do
36
36
  describe "#wait_for_confirms" do
37
37
  it "should not hang when all the publishes are confirmed" do
38
38
  ch = connection.create_channel
39
- ch.should_not be_using_publisher_confirmations
39
+ expect(ch).not_to be_using_publisher_confirmations
40
40
 
41
41
  ch.confirm_select
42
- ch.should be_using_publisher_confirmations
42
+ expect(ch).to be_using_publisher_confirmations
43
43
 
44
- q = ch.queue("", :exclusive => true)
44
+ q = ch.queue("", exclusive: true)
45
45
  x = ch.default_exchange
46
46
 
47
47
  n.times do
48
- x.publish("xyzzy", :routing_key => q.name)
48
+ x.publish("xyzzy", routing_key: q.name)
49
49
  end
50
50
 
51
- ch.next_publish_seq_no.should == n + 1
52
- ch.wait_for_confirms.should be_true
51
+ expect(ch.next_publish_seq_no).to eq n + 1
52
+ expect(ch.wait_for_confirms).to eq true
53
53
 
54
54
  sleep 0.25
55
55
 
56
56
  expect {
57
57
  Bunny::Timeout.timeout(2) do
58
- ch.wait_for_confirms.should be_true
58
+ expect(ch.wait_for_confirms).to eq true
59
59
  end
60
60
  }.not_to raise_error
61
61
 
62
62
  end
63
+
64
+ it "raises an error when called on a closed channel" do
65
+ ch = connection.create_channel
66
+
67
+ ch.confirm_select
68
+
69
+ ch.close
70
+
71
+ expect {
72
+ ch.wait_for_confirms
73
+ }.to raise_error(Bunny::ChannelAlreadyClosed)
74
+ end
63
75
  end
64
76
 
65
77
  context "when some of the messages get nacked" do
66
78
  it "puts the nacks in the nacked_set" do
67
79
  ch = connection.create_channel
68
- ch.should_not be_using_publisher_confirmations
80
+ expect(ch).not_to be_using_publisher_confirmations
69
81
 
70
82
  ch.confirm_select
71
- ch.should be_using_publisher_confirmations
83
+ expect(ch).to be_using_publisher_confirmations
72
84
 
73
- q = ch.queue("", :exclusive => true)
85
+ q = ch.queue("", exclusive: true)
74
86
  x = ch.default_exchange
75
87
 
76
88
  n.times do
77
- x.publish("xyzzy", :routing_key => q.name)
89
+ x.publish("xyzzy", routing_key: q.name)
78
90
  end
79
91
 
80
92
  #be sneaky to simulate a nack
@@ -85,17 +97,17 @@ describe Bunny::Channel do
85
97
  ch.handle_ack_or_nack(nacked_tag, false, true)
86
98
  end
87
99
 
88
- ch.nacked_set.should_not be_empty
89
- ch.nacked_set.should include(nacked_tag)
100
+ expect(ch.nacked_set).not_to be_empty
101
+ expect(ch.nacked_set).to include(nacked_tag)
90
102
 
91
- ch.next_publish_seq_no.should == n + 1
92
- ch.wait_for_confirms.should be_false
103
+ expect(ch.next_publish_seq_no).to eq n + 1
104
+ expect(ch.wait_for_confirms).to eq false
93
105
 
94
- ch.nacked_set.should_not be_empty
95
- ch.nacked_set.should include(nacked_tag)
106
+ expect(ch.nacked_set).not_to be_empty
107
+ expect(ch.nacked_set).to include(nacked_tag)
96
108
 
97
109
  sleep 0.25
98
- q.message_count.should == n
110
+ expect(q.message_count).to eq n
99
111
  q.purge
100
112
 
101
113
  ch.close
@@ -106,17 +118,70 @@ describe Bunny::Channel do
106
118
 
107
119
  context "with a multi-threaded connection" do
108
120
  let(:connection) do
109
- c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed", :continuation_timeout => 10000)
121
+ c = Bunny.new(username: "bunny_gem", password: "bunny_password", vhost: "bunny_testbed", continuation_timeout: 10000)
110
122
  c.start
111
123
  c
112
124
  end
113
125
 
114
126
  include_examples "publish confirms"
127
+
128
+ it "returns only when all confirmations for publishes are received" do
129
+ ch = connection.create_channel
130
+
131
+ operations_log = []
132
+ operations_log_mutex = Mutex.new
133
+ acks_received = Queue.new
134
+
135
+ log_acks = proc do |tag, _, is_nack|
136
+ operations_log_mutex.synchronize do
137
+ operation = "#{'n' if is_nack}ack_#{tag}"
138
+ operations_log << operation unless operations_log.include?(operation)
139
+ end
140
+ acks_received << true
141
+ end
142
+
143
+ ch.confirm_select(log_acks)
144
+
145
+ x = ch.default_exchange
146
+ q = ch.temporary_queue
147
+
148
+ x.publish('msg', routing_key: q.name)
149
+
150
+ # wait for the confirmation to arrive
151
+ acks_received.pop
152
+
153
+ # artificially simulate a slower ack. the test should work properly even
154
+ # without this patch, but it's here just to be sure we catch it.
155
+ def (x.channel).handle_ack_or_nack(delivery_tag_before_offset, multiple, nack)
156
+ sleep 0.1
157
+ super
158
+ end
159
+
160
+ x.publish('msg', routing_key: q.name)
161
+ x.publish('msg', routing_key: q.name)
162
+
163
+ if x.wait_for_confirms
164
+ operations_log_mutex.synchronize do
165
+ operations_log << 'all_confirmed'
166
+ end
167
+ end
168
+
169
+ # wait for all the confirmations to arrive
170
+ acks_received.pop
171
+ acks_received.pop
172
+
173
+ expect(operations_log).to eq([
174
+ 'ack_1',
175
+ 'ack_2',
176
+ 'ack_3',
177
+ 'all_confirmed',
178
+ ])
179
+ end
115
180
  end
116
181
 
117
182
  context "with a single-threaded connection" do
118
183
  let(:connection) do
119
- c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed", :continuation_timeout => 10000, :threaded => false)
184
+ c = Bunny.new(username: "bunny_gem", password: "bunny_password", vhost: "bunny_testbed", continuation_timeout: 10000, threaded: false)
120
185
  c.start
121
186
  c
122
187
  end