bunny 0.8.0 → 0.9.0.pre1
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.
- data/.gitignore +7 -1
- data/.travis.yml +14 -4
- data/ChangeLog.md +72 -0
- data/Gemfile +17 -11
- data/README.md +82 -0
- data/bunny.gemspec +6 -13
- data/examples/connection/heartbeat.rb +17 -0
- data/lib/bunny.rb +40 -56
- data/lib/bunny/channel.rb +615 -19
- data/lib/bunny/channel_id_allocator.rb +59 -0
- data/lib/bunny/compatibility.rb +24 -0
- data/lib/bunny/concurrent/condition.rb +63 -0
- data/lib/bunny/consumer.rb +42 -26
- data/lib/bunny/consumer_tag_generator.rb +22 -0
- data/lib/bunny/consumer_work_pool.rb +67 -0
- data/lib/bunny/exceptions.rb +128 -0
- data/lib/bunny/exchange.rb +131 -136
- data/lib/bunny/framing.rb +53 -0
- data/lib/bunny/heartbeat_sender.rb +59 -0
- data/lib/bunny/main_loop.rb +70 -0
- data/lib/bunny/message_metadata.rb +126 -0
- data/lib/bunny/queue.rb +102 -275
- data/lib/bunny/session.rb +478 -0
- data/lib/bunny/socket.rb +44 -0
- data/lib/bunny/system_timer.rb +9 -9
- data/lib/bunny/transport.rb +179 -0
- data/lib/bunny/version.rb +1 -1
- data/spec/compatibility/queue_declare_spec.rb +40 -0
- data/spec/higher_level_api/integration/basic_ack_spec.rb +54 -0
- data/spec/higher_level_api/integration/basic_consume_spec.rb +51 -0
- data/spec/higher_level_api/integration/basic_get_spec.rb +47 -0
- data/spec/higher_level_api/integration/basic_nack_spec.rb +39 -0
- data/spec/higher_level_api/integration/basic_publish_spec.rb +105 -0
- data/spec/higher_level_api/integration/basic_qos_spec.rb +32 -0
- data/spec/higher_level_api/integration/basic_recover_spec.rb +18 -0
- data/spec/higher_level_api/integration/basic_reject_spec.rb +53 -0
- data/spec/higher_level_api/integration/basic_return_spec.rb +33 -0
- data/spec/higher_level_api/integration/channel_close_spec.rb +29 -0
- data/spec/higher_level_api/integration/channel_flow_spec.rb +24 -0
- data/spec/higher_level_api/integration/channel_open_spec.rb +57 -0
- data/spec/higher_level_api/integration/channel_open_stress_spec.rb +22 -0
- data/spec/higher_level_api/integration/confirm_select_spec.rb +19 -0
- data/spec/higher_level_api/integration/connection_spec.rb +340 -0
- data/spec/higher_level_api/integration/exchange_bind_spec.rb +31 -0
- data/spec/higher_level_api/integration/exchange_declare_spec.rb +183 -0
- data/spec/higher_level_api/integration/exchange_delete_spec.rb +37 -0
- data/spec/higher_level_api/integration/exchange_unbind_spec.rb +40 -0
- data/spec/higher_level_api/integration/queue_bind_spec.rb +109 -0
- data/spec/higher_level_api/integration/queue_declare_spec.rb +129 -0
- data/spec/higher_level_api/integration/queue_delete_spec.rb +38 -0
- data/spec/higher_level_api/integration/queue_purge_spec.rb +30 -0
- data/spec/higher_level_api/integration/queue_unbind_spec.rb +33 -0
- data/spec/higher_level_api/integration/tx_commit_spec.rb +21 -0
- data/spec/higher_level_api/integration/tx_rollback_spec.rb +21 -0
- data/spec/lower_level_api/integration/basic_cancel_spec.rb +57 -0
- data/spec/lower_level_api/integration/basic_consume_spec.rb +100 -0
- data/spec/spec_helper.rb +64 -0
- data/spec/unit/bunny_spec.rb +15 -0
- data/spec/unit/concurrent/condition_spec.rb +66 -0
- metadata +135 -93
- data/CHANGELOG +0 -21
- data/README.textile +0 -76
- data/Rakefile +0 -14
- data/examples/simple.rb +0 -32
- data/examples/simple_ack.rb +0 -35
- data/examples/simple_consumer.rb +0 -55
- data/examples/simple_fanout.rb +0 -41
- data/examples/simple_headers.rb +0 -42
- data/examples/simple_publisher.rb +0 -29
- data/examples/simple_topic.rb +0 -61
- data/ext/amqp-0.9.1.json +0 -389
- data/ext/config.yml +0 -4
- data/ext/qparser.rb +0 -426
- data/lib/bunny/client.rb +0 -370
- data/lib/bunny/subscription.rb +0 -92
- data/lib/qrack/amq-client-url.rb +0 -165
- data/lib/qrack/channel.rb +0 -20
- data/lib/qrack/client.rb +0 -247
- data/lib/qrack/errors.rb +0 -5
- data/lib/qrack/protocol/protocol.rb +0 -135
- data/lib/qrack/protocol/spec.rb +0 -525
- data/lib/qrack/qrack.rb +0 -20
- data/lib/qrack/queue.rb +0 -40
- data/lib/qrack/subscription.rb +0 -152
- data/lib/qrack/transport/buffer.rb +0 -305
- data/lib/qrack/transport/frame.rb +0 -102
- data/spec/spec_09/amqp_url_spec.rb +0 -19
- data/spec/spec_09/bunny_spec.rb +0 -76
- data/spec/spec_09/connection_spec.rb +0 -34
- data/spec/spec_09/exchange_spec.rb +0 -173
- data/spec/spec_09/queue_spec.rb +0 -240
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Bunny::Queue, "#delete" do
|
4
|
+
let(:connection) do
|
5
|
+
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
|
6
|
+
c.start
|
7
|
+
c
|
8
|
+
end
|
9
|
+
|
10
|
+
after :all do
|
11
|
+
connection.close
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
context "with a name of an existing queue" do
|
17
|
+
it "deletes that queue" do
|
18
|
+
ch = connection.create_channel
|
19
|
+
q = ch.queue("")
|
20
|
+
|
21
|
+
q.delete
|
22
|
+
expect {
|
23
|
+
q.delete
|
24
|
+
}.to raise_error(Bunny::NotFound)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
context "with a name of an existing queue" do
|
30
|
+
it "raises an exception" do
|
31
|
+
ch = connection.create_channel
|
32
|
+
|
33
|
+
expect {
|
34
|
+
ch.queue_delete("sdkhflsdjflskdjflsd#{rand}")
|
35
|
+
}.to raise_error(Bunny::NotFound)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Bunny::Queue do
|
4
|
+
let(:connection) do
|
5
|
+
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
|
6
|
+
c.start
|
7
|
+
c
|
8
|
+
end
|
9
|
+
|
10
|
+
after :all do
|
11
|
+
connection.close
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
it "can be purged" do
|
16
|
+
ch = connection.create_channel
|
17
|
+
|
18
|
+
q = ch.queue("", :exclusive => true)
|
19
|
+
x = ch.default_exchange
|
20
|
+
|
21
|
+
x.publish("xyzzy", :routing_key => q.name)
|
22
|
+
sleep(0.5)
|
23
|
+
|
24
|
+
q.message_count.should == 1
|
25
|
+
q.purge
|
26
|
+
q.message_count.should == 0
|
27
|
+
|
28
|
+
ch.close
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Bunny::Queue, "bound to an exchange" do
|
4
|
+
let(:connection) do
|
5
|
+
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
|
6
|
+
c.start
|
7
|
+
c
|
8
|
+
end
|
9
|
+
|
10
|
+
after :all do
|
11
|
+
connection.close
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
it "can be unbound from an exchange it was bound to"
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
describe Bunny::Queue, "NOT bound to an exchange" do
|
21
|
+
let(:connection) do
|
22
|
+
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
|
23
|
+
c.start
|
24
|
+
c
|
25
|
+
end
|
26
|
+
|
27
|
+
after :all do
|
28
|
+
connection.close
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
it "cannot be unbound (raises a channel error)"
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Bunny::Channel, "#tx_commit" do
|
4
|
+
let(:connection) do
|
5
|
+
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
|
6
|
+
c.start
|
7
|
+
c
|
8
|
+
end
|
9
|
+
|
10
|
+
after :all do
|
11
|
+
connection.close if connection.open?
|
12
|
+
end
|
13
|
+
|
14
|
+
it "is supported" do
|
15
|
+
ch = connection.create_channel
|
16
|
+
ch.tx_select
|
17
|
+
ch.tx_commit
|
18
|
+
|
19
|
+
ch.close
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Bunny::Channel, "#tx_rollback" do
|
4
|
+
let(:connection) do
|
5
|
+
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
|
6
|
+
c.start
|
7
|
+
c
|
8
|
+
end
|
9
|
+
|
10
|
+
after :all do
|
11
|
+
connection.close if connection.open?
|
12
|
+
end
|
13
|
+
|
14
|
+
it "is supported" do
|
15
|
+
ch = connection.create_channel
|
16
|
+
ch.tx_select
|
17
|
+
ch.tx_rollback
|
18
|
+
|
19
|
+
ch.close
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Bunny::Channel, "#basic_cancel" do
|
4
|
+
let(:connection) do
|
5
|
+
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
|
6
|
+
c.start
|
7
|
+
c
|
8
|
+
end
|
9
|
+
|
10
|
+
after :all do
|
11
|
+
connection.close if connection.open?
|
12
|
+
end
|
13
|
+
|
14
|
+
it "returns basic.cancel-ok" do
|
15
|
+
ch = connection.create_channel
|
16
|
+
q = ch.queue("", :exclusive => true)
|
17
|
+
|
18
|
+
consume_ok = ch.basic_consume(q, "")
|
19
|
+
cancel_ok = ch.basic_cancel(consume_ok.consumer_tag)
|
20
|
+
|
21
|
+
cancel_ok.should be_instance_of(AMQ::Protocol::Basic::CancelOk)
|
22
|
+
cancel_ok.consumer_tag.should == consume_ok.consumer_tag
|
23
|
+
|
24
|
+
ch.close
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when the given consumer tag is valid" do
|
28
|
+
let(:queue_name) { "bunny.basic.cancel.queue#{rand}" }
|
29
|
+
|
30
|
+
it "cancels the consumer" do
|
31
|
+
delivered_data = []
|
32
|
+
|
33
|
+
t = Thread.new do
|
34
|
+
ch = connection.create_channel
|
35
|
+
q = ch.queue(queue_name, :auto_delete => true, :durable => false)
|
36
|
+
consume_ok = ch.basic_consume(q, "", true, false) do |metadata, payload|
|
37
|
+
delivered_data << payload
|
38
|
+
end
|
39
|
+
|
40
|
+
consume_ok.consumer_tag.should_not be_nil
|
41
|
+
cancel_ok = ch.basic_cancel(consume_ok.consumer_tag)
|
42
|
+
cancel_ok.consumer_tag.should == consume_ok.consumer_tag
|
43
|
+
|
44
|
+
ch.close
|
45
|
+
end
|
46
|
+
t.abort_on_exception = true
|
47
|
+
sleep 0.5
|
48
|
+
|
49
|
+
sleep 0.7
|
50
|
+
delivered_data.should be_empty
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when the given consumer tag is invalid (was never registered)" do
|
55
|
+
it "causes a channel error"
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Bunny::Channel, "#basic_consume" do
|
4
|
+
let(:connection) do
|
5
|
+
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
|
6
|
+
c.start
|
7
|
+
c
|
8
|
+
end
|
9
|
+
|
10
|
+
after :all do
|
11
|
+
connection.close if connection.open?
|
12
|
+
end
|
13
|
+
|
14
|
+
it "returns basic.consume-ok when it is received" do
|
15
|
+
ch = connection.create_channel
|
16
|
+
q = ch.queue("", :exclusive => true)
|
17
|
+
|
18
|
+
consume_ok = ch.basic_consume(q)
|
19
|
+
consume_ok.should be_instance_of(AMQ::Protocol::Basic::ConsumeOk)
|
20
|
+
consume_ok.consumer_tag.should_not be_nil
|
21
|
+
|
22
|
+
ch.close
|
23
|
+
end
|
24
|
+
|
25
|
+
it "carries server-generated consumer tag with basic.consume-ok" do
|
26
|
+
ch = connection.create_channel
|
27
|
+
q = ch.queue("", :exclusive => true)
|
28
|
+
|
29
|
+
consume_ok = ch.basic_consume(q, "")
|
30
|
+
consume_ok.consumer_tag.should =~ /amq\.ctag.*/
|
31
|
+
|
32
|
+
ch.close
|
33
|
+
end
|
34
|
+
|
35
|
+
context "with automatic acknowledgement mode" do
|
36
|
+
let(:queue_name) { "bunny.basic_consume#{rand}" }
|
37
|
+
|
38
|
+
it "causes messages to be automatically removed from the queue after delivery" do
|
39
|
+
delivered_keys = []
|
40
|
+
delivered_data = []
|
41
|
+
|
42
|
+
t = Thread.new do
|
43
|
+
ch = connection.create_channel
|
44
|
+
q = ch.queue(queue_name, :auto_delete => true, :durable => false)
|
45
|
+
ch.basic_consume(q, "", true, false) do |metadata, payload|
|
46
|
+
delivered_keys << metadata.routing_key
|
47
|
+
delivered_data << payload
|
48
|
+
end
|
49
|
+
end
|
50
|
+
t.abort_on_exception = true
|
51
|
+
sleep 0.5
|
52
|
+
|
53
|
+
ch = connection.create_channel
|
54
|
+
x = ch.default_exchange
|
55
|
+
x.publish("hello", :routing_key => queue_name)
|
56
|
+
|
57
|
+
sleep 0.7
|
58
|
+
delivered_keys.should include(queue_name)
|
59
|
+
delivered_data.should include("hello")
|
60
|
+
|
61
|
+
ch.queue(queue_name, :auto_delete => true, :durable => false).message_count.should == 0
|
62
|
+
|
63
|
+
ch.close
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "with manual acknowledgement mode" do
|
68
|
+
let(:queue_name) { "bunny.basic_consume#{rand}" }
|
69
|
+
|
70
|
+
it "waits for an explicit acknowledgement" do
|
71
|
+
delivered_keys = []
|
72
|
+
delivered_data = []
|
73
|
+
|
74
|
+
t = Thread.new do
|
75
|
+
ch = connection.create_channel
|
76
|
+
q = ch.queue(queue_name, :auto_delete => true, :durable => false)
|
77
|
+
ch.basic_consume(q, "", false, false) do |metadata, payload|
|
78
|
+
delivered_keys << metadata.routing_key
|
79
|
+
delivered_data << payload
|
80
|
+
|
81
|
+
ch.close
|
82
|
+
end
|
83
|
+
end
|
84
|
+
t.abort_on_exception = true
|
85
|
+
sleep 0.5
|
86
|
+
|
87
|
+
ch = connection.create_channel
|
88
|
+
x = ch.default_exchange
|
89
|
+
x.publish("hello", :routing_key => queue_name)
|
90
|
+
|
91
|
+
sleep 0.7
|
92
|
+
delivered_keys.should include(queue_name)
|
93
|
+
delivered_data.should include("hello")
|
94
|
+
|
95
|
+
ch.queue(queue_name, :auto_delete => true, :durable => false).message_count.should == 0
|
96
|
+
|
97
|
+
ch.close
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# -*- encoding: utf-8; mode: ruby -*-
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
4
|
+
|
5
|
+
require 'bundler'
|
6
|
+
Bundler.setup(:default, :test)
|
7
|
+
|
8
|
+
|
9
|
+
require "effin_utf8"
|
10
|
+
require "bunny"
|
11
|
+
|
12
|
+
|
13
|
+
require "amq/protocol/version"
|
14
|
+
puts "Using Ruby #{RUBY_VERSION}, amq-protocol #{AMQ::Protocol::VERSION}"
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
#
|
19
|
+
# Ruby version-specific
|
20
|
+
#
|
21
|
+
|
22
|
+
case RUBY_VERSION
|
23
|
+
when "1.8.7" then
|
24
|
+
class Array
|
25
|
+
alias sample choice
|
26
|
+
end
|
27
|
+
when "1.8.6" then
|
28
|
+
raise "Ruby 1.8.6 is not supported. Sorry, pal. Time to move on beyond One True Ruby. Yes, time flies by."
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
module RabbitMQ
|
34
|
+
module Control
|
35
|
+
def rabbitmq_pid
|
36
|
+
$1.to_i if `rabbitmqctl status` =~ /\{pid,(\d+)\}/
|
37
|
+
end
|
38
|
+
|
39
|
+
def start_rabbitmq(delay = 1.0)
|
40
|
+
# this is Homebrew-specific :(
|
41
|
+
`rabbitmq-server > /dev/null 2>&1 &`; sleep(delay)
|
42
|
+
end
|
43
|
+
|
44
|
+
def stop_rabbitmq(pid = rabbitmq_pid, delay = 1.0)
|
45
|
+
`rabbitmqctl stop`; sleep(delay)
|
46
|
+
end
|
47
|
+
|
48
|
+
def kill_rabbitmq(pid = rabbitmq_pid, delay = 1.0)
|
49
|
+
# tango is down, tango is down!
|
50
|
+
Process.kill("KILL", pid); sleep(delay)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
module PlatformDetection
|
57
|
+
def mri?
|
58
|
+
!defined?(RUBY_ENGINE) || (defined?(RUBY_ENGINE) && ("ruby" == RUBY_ENGINE))
|
59
|
+
end
|
60
|
+
|
61
|
+
def rubinius?
|
62
|
+
defined?(RUBY_ENGINE) && (RUBY_ENGINE == 'rbx')
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Bunny do
|
4
|
+
it "has library version" do
|
5
|
+
Bunny::VERSION.should_not be_nil
|
6
|
+
Bunny.version.should_not be_nil
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
it "has AMQP protocol version" do
|
11
|
+
Bunny::PROTOCOL_VERSION.should == "0.9.1"
|
12
|
+
AMQ::Protocol::PROTOCOL_VERSION.should == "0.9.1"
|
13
|
+
Bunny.protocol_version.should == "0.9.1"
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "bunny/concurrent/condition"
|
3
|
+
|
4
|
+
describe Bunny::Concurrent::Condition do
|
5
|
+
describe "#wait" do
|
6
|
+
it "blocks current thread until notified" do
|
7
|
+
condition = described_class.new
|
8
|
+
xs = []
|
9
|
+
|
10
|
+
t = Thread.new do
|
11
|
+
xs << :notified
|
12
|
+
|
13
|
+
sleep 0.25
|
14
|
+
condition.notify
|
15
|
+
end
|
16
|
+
|
17
|
+
condition.wait
|
18
|
+
xs.should == [:notified]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#notify" do
|
23
|
+
it "notifies a single thread waiting on the latch" do
|
24
|
+
condition = described_class.new
|
25
|
+
xs = []
|
26
|
+
|
27
|
+
t1 = Thread.new do
|
28
|
+
condition.wait
|
29
|
+
xs << :notified1
|
30
|
+
end
|
31
|
+
|
32
|
+
t2 = Thread.new do
|
33
|
+
condition.wait
|
34
|
+
xs << :notified2
|
35
|
+
end
|
36
|
+
|
37
|
+
sleep 0.25
|
38
|
+
condition.notify
|
39
|
+
sleep 0.5
|
40
|
+
xs.should satisfy { |ys| ys.size == 1 && (ys.include?(:notified1) || ys.include?(:notified2)) }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#notify_all" do
|
45
|
+
it "notifies all the threads waiting on the latch" do
|
46
|
+
condition = described_class.new
|
47
|
+
@xs = []
|
48
|
+
|
49
|
+
t1 = Thread.new do
|
50
|
+
condition.wait
|
51
|
+
@xs << :notified1
|
52
|
+
end
|
53
|
+
|
54
|
+
t2 = Thread.new do
|
55
|
+
condition.wait
|
56
|
+
@xs << :notified2
|
57
|
+
end
|
58
|
+
|
59
|
+
sleep 0.5
|
60
|
+
condition.notify_all
|
61
|
+
sleep 0.5
|
62
|
+
@xs.should include(:notified1)
|
63
|
+
@xs.should include(:notified2)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|