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.
Files changed (91) hide show
  1. data/.gitignore +7 -1
  2. data/.travis.yml +14 -4
  3. data/ChangeLog.md +72 -0
  4. data/Gemfile +17 -11
  5. data/README.md +82 -0
  6. data/bunny.gemspec +6 -13
  7. data/examples/connection/heartbeat.rb +17 -0
  8. data/lib/bunny.rb +40 -56
  9. data/lib/bunny/channel.rb +615 -19
  10. data/lib/bunny/channel_id_allocator.rb +59 -0
  11. data/lib/bunny/compatibility.rb +24 -0
  12. data/lib/bunny/concurrent/condition.rb +63 -0
  13. data/lib/bunny/consumer.rb +42 -26
  14. data/lib/bunny/consumer_tag_generator.rb +22 -0
  15. data/lib/bunny/consumer_work_pool.rb +67 -0
  16. data/lib/bunny/exceptions.rb +128 -0
  17. data/lib/bunny/exchange.rb +131 -136
  18. data/lib/bunny/framing.rb +53 -0
  19. data/lib/bunny/heartbeat_sender.rb +59 -0
  20. data/lib/bunny/main_loop.rb +70 -0
  21. data/lib/bunny/message_metadata.rb +126 -0
  22. data/lib/bunny/queue.rb +102 -275
  23. data/lib/bunny/session.rb +478 -0
  24. data/lib/bunny/socket.rb +44 -0
  25. data/lib/bunny/system_timer.rb +9 -9
  26. data/lib/bunny/transport.rb +179 -0
  27. data/lib/bunny/version.rb +1 -1
  28. data/spec/compatibility/queue_declare_spec.rb +40 -0
  29. data/spec/higher_level_api/integration/basic_ack_spec.rb +54 -0
  30. data/spec/higher_level_api/integration/basic_consume_spec.rb +51 -0
  31. data/spec/higher_level_api/integration/basic_get_spec.rb +47 -0
  32. data/spec/higher_level_api/integration/basic_nack_spec.rb +39 -0
  33. data/spec/higher_level_api/integration/basic_publish_spec.rb +105 -0
  34. data/spec/higher_level_api/integration/basic_qos_spec.rb +32 -0
  35. data/spec/higher_level_api/integration/basic_recover_spec.rb +18 -0
  36. data/spec/higher_level_api/integration/basic_reject_spec.rb +53 -0
  37. data/spec/higher_level_api/integration/basic_return_spec.rb +33 -0
  38. data/spec/higher_level_api/integration/channel_close_spec.rb +29 -0
  39. data/spec/higher_level_api/integration/channel_flow_spec.rb +24 -0
  40. data/spec/higher_level_api/integration/channel_open_spec.rb +57 -0
  41. data/spec/higher_level_api/integration/channel_open_stress_spec.rb +22 -0
  42. data/spec/higher_level_api/integration/confirm_select_spec.rb +19 -0
  43. data/spec/higher_level_api/integration/connection_spec.rb +340 -0
  44. data/spec/higher_level_api/integration/exchange_bind_spec.rb +31 -0
  45. data/spec/higher_level_api/integration/exchange_declare_spec.rb +183 -0
  46. data/spec/higher_level_api/integration/exchange_delete_spec.rb +37 -0
  47. data/spec/higher_level_api/integration/exchange_unbind_spec.rb +40 -0
  48. data/spec/higher_level_api/integration/queue_bind_spec.rb +109 -0
  49. data/spec/higher_level_api/integration/queue_declare_spec.rb +129 -0
  50. data/spec/higher_level_api/integration/queue_delete_spec.rb +38 -0
  51. data/spec/higher_level_api/integration/queue_purge_spec.rb +30 -0
  52. data/spec/higher_level_api/integration/queue_unbind_spec.rb +33 -0
  53. data/spec/higher_level_api/integration/tx_commit_spec.rb +21 -0
  54. data/spec/higher_level_api/integration/tx_rollback_spec.rb +21 -0
  55. data/spec/lower_level_api/integration/basic_cancel_spec.rb +57 -0
  56. data/spec/lower_level_api/integration/basic_consume_spec.rb +100 -0
  57. data/spec/spec_helper.rb +64 -0
  58. data/spec/unit/bunny_spec.rb +15 -0
  59. data/spec/unit/concurrent/condition_spec.rb +66 -0
  60. metadata +135 -93
  61. data/CHANGELOG +0 -21
  62. data/README.textile +0 -76
  63. data/Rakefile +0 -14
  64. data/examples/simple.rb +0 -32
  65. data/examples/simple_ack.rb +0 -35
  66. data/examples/simple_consumer.rb +0 -55
  67. data/examples/simple_fanout.rb +0 -41
  68. data/examples/simple_headers.rb +0 -42
  69. data/examples/simple_publisher.rb +0 -29
  70. data/examples/simple_topic.rb +0 -61
  71. data/ext/amqp-0.9.1.json +0 -389
  72. data/ext/config.yml +0 -4
  73. data/ext/qparser.rb +0 -426
  74. data/lib/bunny/client.rb +0 -370
  75. data/lib/bunny/subscription.rb +0 -92
  76. data/lib/qrack/amq-client-url.rb +0 -165
  77. data/lib/qrack/channel.rb +0 -20
  78. data/lib/qrack/client.rb +0 -247
  79. data/lib/qrack/errors.rb +0 -5
  80. data/lib/qrack/protocol/protocol.rb +0 -135
  81. data/lib/qrack/protocol/spec.rb +0 -525
  82. data/lib/qrack/qrack.rb +0 -20
  83. data/lib/qrack/queue.rb +0 -40
  84. data/lib/qrack/subscription.rb +0 -152
  85. data/lib/qrack/transport/buffer.rb +0 -305
  86. data/lib/qrack/transport/frame.rb +0 -102
  87. data/spec/spec_09/amqp_url_spec.rb +0 -19
  88. data/spec/spec_09/bunny_spec.rb +0 -76
  89. data/spec/spec_09/connection_spec.rb +0 -34
  90. data/spec/spec_09/exchange_spec.rb +0 -173
  91. 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
@@ -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