amqp 0.8.0.rc11 → 0.8.0.rc12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. data/CHANGELOG +1 -0
  2. data/Gemfile +2 -1
  3. data/amqp.gemspec +1 -1
  4. data/docs/ConnectingToTheBroker.textile +136 -6
  5. data/docs/GettingStarted.textile +2 -2
  6. data/docs/Queues.textile +14 -14
  7. data/examples/channels/open_channel_with_one_arity_callback.rb +30 -0
  8. data/examples/deprecated/default_thread_local_channel_instance.rb +34 -0
  9. data/examples/error_handling/channel_level_exception.rb +1 -1
  10. data/examples/error_handling/channel_level_exception_with_multiple_channels_involved.rb +1 -1
  11. data/examples/error_handling/global_channel_level_exception_handler.rb +1 -1
  12. data/examples/guides/getting_started/03_babblr.rb +1 -1
  13. data/examples/guides/queues/05_binding_a_queue_using_exchange_instance.rb +1 -1
  14. data/examples/guides/queues/06_biding_a_queue_using_exchange_name_string.rb +1 -1
  15. data/examples/guides/queues/07_subscribing_to_receive_messages.rb +1 -1
  16. data/examples/guides/queues/08_poll_for_messages.rb +1 -1
  17. data/examples/guides/queues/09_unsubscribing_a_consumer.rb +1 -1
  18. data/examples/guides/queues/10_unbinding_from_exchange.rb +1 -1
  19. data/examples/guides/queues/11_purge_a_queue.rb +1 -1
  20. data/examples/guides/queues/12_deleting_a_queue.rb +1 -1
  21. data/examples/queues/declare_a_queue_without_assignment.rb +1 -1
  22. data/examples/queues/declare_and_bind_a_server_named_queue.rb +1 -1
  23. data/lib/amqp/channel.rb +27 -1
  24. data/lib/amqp/client.rb +36 -8
  25. data/lib/amqp/connection.rb +6 -3
  26. data/lib/amqp/deprecated/mq.rb +0 -22
  27. data/lib/amqp/queue.rb +19 -13
  28. data/lib/amqp/version.rb +1 -1
  29. data/spec/integration/authentication_spec.rb +7 -5
  30. data/spec/spec_helper.rb +1 -0
  31. data/spec/unit/amqp/client_spec.rb +149 -0
  32. data/spec/unit/amqp/connection_spec.rb +20 -0
  33. metadata +108 -86
@@ -4,7 +4,7 @@
4
4
  require "rubygems"
5
5
  require "amqp"
6
6
 
7
- AMQP.start("amqp://dev.rabbitmq.com:5672/") do |connection|
7
+ AMQP.start("amqp://dev.rabbitmq.com:5672") do |connection|
8
8
  channel = AMQP::Channel.new(connection)
9
9
  exchange = channel.fanout("nba.scores")
10
10
 
@@ -5,7 +5,7 @@ require "rubygems"
5
5
  require "amqp"
6
6
 
7
7
  # Binding a queue to an exchange
8
- AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672/") do |connection, open_ok|
8
+ AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok|
9
9
  AMQP::Channel.new do |channel, open_ok|
10
10
  exchange = channel.fanout("amq.fanout")
11
11
 
@@ -5,7 +5,7 @@ require "rubygems"
5
5
  require "amqp"
6
6
 
7
7
  # Binding a queue to an exchange
8
- AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672/") do |connection, open_ok|
8
+ AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok|
9
9
  AMQP::Channel.new do |channel, open_ok|
10
10
  exchange_name = "amq.fanout"
11
11
 
@@ -4,7 +4,7 @@
4
4
  require "rubygems"
5
5
  require "amqp"
6
6
 
7
- AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672/") do |connection, open_ok|
7
+ AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok|
8
8
  AMQP::Channel.new do |channel, open_ok|
9
9
  exchange = channel.fanout("amq.fanout")
10
10
 
@@ -4,7 +4,7 @@
4
4
  require "rubygems"
5
5
  require "amqp"
6
6
 
7
- AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672/") do |connection, open_ok|
7
+ AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok|
8
8
  AMQP::Channel.new do |channel, open_ok|
9
9
  exchange = channel.fanout("amq.fanout")
10
10
 
@@ -4,7 +4,7 @@
4
4
  require "rubygems"
5
5
  require "amqp"
6
6
 
7
- AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672/") do |connection, open_ok|
7
+ AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok|
8
8
  AMQP::Channel.new do |channel, open_ok|
9
9
  exchange = channel.fanout("amq.fanout")
10
10
 
@@ -4,7 +4,7 @@
4
4
  require "rubygems"
5
5
  require "amqp"
6
6
 
7
- AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672/") do |connection, open_ok|
7
+ AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok|
8
8
  puts "Connected"
9
9
  AMQP::Channel.new(connection) do |channel, open_ok|
10
10
  puts "Opened a channel"
@@ -4,7 +4,7 @@
4
4
  require "rubygems"
5
5
  require "amqp"
6
6
 
7
- AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672/") do |connection, open_ok|
7
+ AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok|
8
8
  puts "Connected"
9
9
  AMQP::Channel.new(connection) do |channel, open_ok|
10
10
  puts "Opened a channel"
@@ -4,7 +4,7 @@
4
4
  require "rubygems"
5
5
  require "amqp"
6
6
 
7
- AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672/") do |connection, open_ok|
7
+ AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok|
8
8
  puts "Connected"
9
9
  AMQP::Channel.new(connection) do |channel, open_ok|
10
10
  puts "Opened a channel"
@@ -11,7 +11,7 @@ require 'amqp'
11
11
 
12
12
  puts "=> Queue#initialize example that uses a block"
13
13
  puts
14
- AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672/") do |connection, open_ok|
14
+ AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok|
15
15
  AMQP::Channel.new do |channel, open_ok|
16
16
  puts "Channel ##{channel.id} is now open!"
17
17
 
@@ -11,7 +11,7 @@ require 'amqp'
11
11
 
12
12
  puts "=> Queue#initialize example that uses a block"
13
13
  puts
14
- AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672/") do |connection, open_ok|
14
+ AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok|
15
15
  AMQP::Channel.new do |channel, open_ok|
16
16
  puts "Channel ##{channel.id} is now open!" if channel.open?
17
17
 
@@ -80,7 +80,7 @@ module AMQP
80
80
  # It is possible (and, indeed, recommended) to handle channel-level exceptions by defining an errback using #on_error:
81
81
  #
82
82
  # @example Queue declaration with incompatible attributes results in a channel-level exception
83
- # AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672/") do |connection, open_ok|
83
+ # AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok|
84
84
  # AMQP::Channel.new do |channel, open_ok|
85
85
  # puts "Channel ##{channel.id} is now open!"
86
86
  #
@@ -926,6 +926,32 @@ module AMQP
926
926
  end
927
927
 
928
928
 
929
+ #
930
+ # Backwards compatibility with 0.6.x
931
+ #
932
+
933
+ # unique identifier
934
+ # @deprecated
935
+ def self.id
936
+ Thread.current[:mq_id] ||= "#{`hostname`.strip}-#{Process.pid}-#{Thread.current.object_id}"
937
+ end
938
+
939
+ # @private
940
+ # @deprecated
941
+ def self.default
942
+ # TODO: clear this when connection is closed
943
+ Thread.current[:mq] ||= AMQP::Channel.new
944
+ end
945
+
946
+ # Allows for calls to all MQ instance methods. This implicitly calls
947
+ # AMQP::Channel.new so that a new channel is allocated for subsequent operations.
948
+ # @deprecated
949
+ def self.method_missing(meth, *args, &blk)
950
+ self.default.__send__(meth, *args, &blk)
951
+ end
952
+
953
+
954
+
929
955
  protected
930
956
 
931
957
  # @private
@@ -21,6 +21,8 @@ module AMQP
21
21
  # @see AMQP.start
22
22
  # @see AMQP.connect
23
23
  # @api plugin
24
+ #
25
+ # @see http://bit.ly/ks8MXK Connecting to The Broker documentation guide
24
26
  def self.connect(connection_string_or_options = {}, options = {}, &block)
25
27
  opts = case connection_string_or_options
26
28
  when String then
@@ -40,21 +42,47 @@ module AMQP
40
42
 
41
43
  # Parses AMQP connection string and returns it's components as a hash.
42
44
  #
43
- # @param [String] connection_string AMQP connection URI, à la JDBC connection string. For example: amqp://bus.megacorp.internal:5877/qa
45
+ # h2. vhost naming schemes
46
+ #
47
+ # AMQP 0.9.1 spec does not define what vhost naming scheme should be. RabbitMQ and Apache Qpid use different schemes
48
+ # (Qpid said to have two) but the bottom line is: even though some brokers use / as the default vhost, it can be *any string*.
49
+ # Host (and optional port) part must be separated from vhost (path component) with a slash character (/).
50
+ #
51
+ # This method will also unescape path part of the URI.
52
+ #
53
+ # @example How vhost is parsed
54
+ #
55
+ # AMQP::Client.parse_connection_uri("amqp://dev.rabbitmq.com") # => vhost is nil, so default (/) will be used
56
+ # AMQP::Client.parse_connection_uri("amqp://dev.rabbitmq.com/") # => vhost is an empty string
57
+ # AMQP::Client.parse_connection_uri("amqp://dev.rabbitmq.com//") # => vhost is /
58
+ # AMQP::Client.parse_connection_uri("amqp://dev.rabbitmq.com//vault") # => vhost is /vault
59
+ # AMQP::Client.parse_connection_uri("amqp://dev.rabbitmq.com/%2Fvault") # => vhost is /vault
60
+ # AMQP::Client.parse_connection_uri("amqp://dev.rabbitmq.com/production") # => vhost is production
61
+ # AMQP::Client.parse_connection_uri("amqp://dev.rabbitmq.com/a.b.c") # => vhost is a.b.c
62
+ # AMQP::Client.parse_connection_uri("amqp://dev.rabbitmq.com///a/b/c/d") # => vhost is //a/b/c/d
63
+ #
64
+ #
65
+ # @param [String] connection_string AMQP connection URI, à la JDBC connection string. For example: amqp://bus.megacorp.internal:5877.
44
66
  # @return [Hash] Connection parameters (:username, :password, :vhost, :host, :port, :ssl)
67
+ #
68
+ # @raise [ArgumentError] When connection URI schema is not amqp or amqps.
69
+ #
70
+ # @see http://bit.ly/ks8MXK Connecting to The Broker documentation guide
45
71
  # @api public
46
72
  def self.parse_connection_uri(connection_string)
47
73
  uri = URI.parse(connection_string)
48
- raise("Connection URI must use amqp or amqps schema (example: amqp://bus.megacorp.internal:5766/testbed)") unless %w{amqp amqps}.include?(uri.scheme)
74
+ raise ArgumentError.new("Connection URI must use amqp or amqps schema (example: amqp://bus.megacorp.internal:5766), learn more at http://bit.ly/ks8MXK") unless %w{amqp amqps}.include?(uri.scheme)
49
75
 
50
76
  opts = {}
51
77
 
52
- opts[:user] = URI.unescape(uri.user) if uri.user
53
- opts[:pass] = URI.unescape(uri.password) if uri.password
54
- opts[:vhost] = URI.unescape(uri.path) if uri.path
55
- opts[:host] = uri.host if uri.host
56
- opts[:port] = uri.port || AMQP_PORTS[uri.scheme]
57
- opts[:ssl] = uri.scheme == AMQPS
78
+
79
+ opts[:scheme] = uri.scheme
80
+ opts[:user] = URI.unescape(uri.user) if uri.user
81
+ opts[:pass] = URI.unescape(uri.password) if uri.password
82
+ opts[:vhost] = URI.unescape($1) if uri.path =~ %r{^/(.*)}
83
+ opts[:host] = uri.host if uri.host
84
+ opts[:port] = uri.port || AMQP_PORTS[uri.scheme]
85
+ opts[:ssl] = uri.scheme == AMQPS
58
86
 
59
87
  opts
60
88
  end
@@ -15,7 +15,7 @@ module AMQP
15
15
  # to AMQP broker using {AMQP.connect}. It is generally a good idea to
16
16
  # start EventMachine event loop in a separate thread and use {AMQP.connect}.
17
17
  # That said, for applications that do not publish or handle large volumes of
18
- # data {AMQP.start} works very well and it's use is not discouraged.
18
+ # data {AMQP.start} works very well and its use is not discouraged.
19
19
  #
20
20
  # See {AMQP.connect} for information about arguments this method takes and
21
21
  # information about relevant topics such as authentication failure handling.
@@ -37,7 +37,9 @@ module AMQP
37
37
  # @api public
38
38
  def self.start(connection_options_or_string = {}, other_options = {}, &block)
39
39
  EM.run do
40
- @connection ||= connect(connection_options_or_string, other_options, &block)
40
+ if !@connection || @connection.closed? || @connection.closing?
41
+ @connection = connect(connection_options_or_string, other_options, &block)
42
+ end
41
43
  @channel = Channel.new(@connection)
42
44
  @connection
43
45
  end
@@ -169,7 +171,7 @@ module AMQP
169
171
  #
170
172
  # @example Using AMQP.connect to connect to a public RabbitMQ instance with connection settings given as a URI
171
173
  #
172
- # AMQP.connect "amqp://guest:guest@dev.rabbitmq.com:5672/", :on_possible_authentication_failure => Proc.new { puts("Looks like authentication has failed") } do |connection|
174
+ # AMQP.connect "amqp://guest:guest@dev.rabbitmq.com:5672", :on_possible_authentication_failure => Proc.new { puts("Looks like authentication has failed") } do |connection|
173
175
  # AMQP::Channel.new(connection) do |channel|
174
176
  # # ...
175
177
  # end
@@ -191,6 +193,7 @@ module AMQP
191
193
  # @option connection_options_or_string [String] :username ("guest") Username to use. Also can be specified as :user.
192
194
  # @option connection_options_or_string [String] :password ("guest") Password to use. Also can be specified as :pass.
193
195
  # @option connection_options_or_string [Hash] :ssl TLS (SSL) parameters to use.
196
+ # @option connection_options_or_string [#call] :on_tcp_connection_failure A callable object that will be run if connection to server fails
194
197
  # @option connection_options_or_string [#call] :on_possible_authentication_failure A callable object that will be run if authentication fails (see Authentication failure section)
195
198
  #
196
199
  #
@@ -17,26 +17,4 @@ class MQ
17
17
  # @note This class will be removed before 1.0 release.
18
18
  # @deprecated
19
19
  class Queue < ::AMQP::Queue; end
20
-
21
-
22
- #
23
- # Backwards compatibility with 0.6.x
24
- #
25
-
26
- # unique identifier
27
- def MQ.id
28
- Thread.current[:mq_id] ||= "#{`hostname`.strip}-#{Process.pid}-#{Thread.current.object_id}"
29
- end
30
-
31
- # @private
32
- def MQ.default
33
- # TODO: clear this when connection is closed
34
- Thread.current[:mq] ||= MQ.new
35
- end
36
-
37
- # Allows for calls to all MQ instance methods. This implicitly calls
38
- # MQ.new so that a new channel is allocated for subsequent operations.
39
- def MQ.method_missing(meth, *args, &blk)
40
- MQ.default.__send__(meth, *args, &blk)
41
- end
42
20
  end
@@ -219,27 +219,33 @@ module AMQP
219
219
  end # server_named?
220
220
 
221
221
 
222
- # This method binds a queue to an exchange. Until a queue is
223
- # bound it will not receive any messages. In a classic messaging
222
+ # This method binds a queue to an exchange. Until a queue is
223
+ # bound it will not receive any messages. In a classic messaging
224
224
  # model, store-and-forward queues are bound to a dest exchange
225
225
  # and subscription queues are bound to a dest_wild exchange.
226
226
  #
227
227
  # A valid exchange name (or reference) must be passed as the first
228
228
  # parameter.
229
- # @example Both of these are valid
230
- # exch = AMQP::Channel.direct('foo exchange')
231
- # queue = AMQP::Channel.queue('bar queue')
232
- # queue.bind('foo.exchange') # OR
233
- # queue.bind(exch)
229
+ # @example Binding a queue to exchange using AMQP::Exchange instance
234
230
  #
235
- # It is not valid to call #bind without the +exchange+ parameter.
231
+ # ch = AMQP::Channel.new(connection)
232
+ # exchange = ch.direct('backlog.events')
233
+ # queue = ch.queue('', :exclusive => true)
234
+ # queue.bind(exchange)
236
235
  #
237
- # It is unnecessary to call #bind when the exchange name and queue
238
- # name match exactly (for :direct and :fanout exchanges only).
239
- # There is an implicit bind which will deliver the messages from
240
- # the exchange to the queue.
241
236
  #
242
- # @param [Exchange] Exchange to bind to.
237
+ # @example Binding a queue to exchange using exchange name
238
+ #
239
+ # ch = AMQP::Channel.new(connection)
240
+ # queue = ch.queue('', :exclusive => true)
241
+ # queue.bind('backlog.events')
242
+ #
243
+ #
244
+ # Note that if your producer application knows consumer queue name and wants to deliver
245
+ # a message there, direct exchange may be sufficient (in other words, if your code declares an exchange with
246
+ # the same name as a queue and binds it to that queue, consider using the default exchange and routing key on publishing).
247
+ #
248
+ # @param [Exchange] Exchange to bind to. May also be a string or any object that responds to #name.
243
249
  #
244
250
  # @option opts [String] :routing_key Specifies the routing key for the binding. The routing key is
245
251
  # used for routing messages depending on the exchange configuration.
@@ -6,5 +6,5 @@ module AMQP
6
6
  #
7
7
  # @see AMQ::Protocol::VERSION
8
8
  # @return [String] AMQP gem version
9
- VERSION = '0.8.0.rc11'
9
+ VERSION = '0.8.0.rc12'
10
10
  end
@@ -10,6 +10,8 @@ describe "Authentication attempt" do
10
10
  include EventedSpec::EMSpec
11
11
  include EventedSpec::SpecHelper
12
12
 
13
+ default_timeout 1.0
14
+
13
15
 
14
16
  describe "with default connection parameters" do
15
17
 
@@ -45,12 +47,12 @@ describe "Authentication attempt" do
45
47
 
46
48
  # assuming there is an account amqp_gem with password of "amqp_gem_password" that has
47
49
  # access to /amqp_gem_testbed
48
- context "when amqp_gem/amqp_gem_testbed has access to /amqp_gem_testbed" do
50
+ context "when amqp_gem/amqp_gem_testbed has access to amqp_gem_testbed" do
49
51
  context "and provided credentials are correct" do
50
52
  it "succeeds" do
51
- connection = AMQP.connect :username => "amqp_gem", :password => "amqp_gem_password", :vhost => "/amqp_gem_testbed"
53
+ connection = AMQP.connect(AMQP_OPTS.merge(:username => "amqp_gem", :password => "amqp_gem_password", :vhost => "/amqp_gem_testbed"))
52
54
 
53
- done(0.5) {
55
+ done(0.4) {
54
56
  connection.should be_connected
55
57
  connection.close
56
58
  }
@@ -99,10 +101,10 @@ describe "Authentication attempt" do
99
101
 
100
102
  # assuming there is an account amqp_gem with password of "amqp_gem_password" that has
101
103
  # access to /amqp_gem_testbed
102
- context "when amqp_gem/amqp_gem_testbed has access to /amqp_gem_testbed" do
104
+ context "when amqp_gem/amqp_gem_testbed has access to amqp_gem_testbed" do
103
105
  context "and provided credentials are correct" do
104
106
  it "succeeds" do
105
- connection = AMQP.connect "amqp://amqp_gem:amqp_gem_password@localhost/amqp_gem_testbed"
107
+ connection = AMQP.connect "amqp://amqp_gem:amqp_gem_password@localhost/%2Famqp_gem_testbed"
106
108
 
107
109
  done(0.3) {
108
110
  connection.should be_connected
@@ -93,6 +93,7 @@ else
93
93
  AMQP_OPTS = {:host => 'localhost', :port => 5672}
94
94
  end
95
95
 
96
+ puts "AMQP_OPTS = #{AMQP_OPTS.inspect}"
96
97
 
97
98
  #
98
99
  # Ruby version-specific
@@ -0,0 +1,149 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe AMQP::Client do
6
+
7
+ #
8
+ # Examples
9
+ #
10
+
11
+
12
+ describe ".parse_connection_uri(connection_string)" do
13
+ context "when schema is not one of [amqp, amqps]" do
14
+ it "raises ArgumentError" do
15
+ expect {
16
+ described_class.parse_connection_uri("http://dev.rabbitmq.com")
17
+ }.to raise_error(ArgumentError, /amqp or amqps schema/)
18
+ end
19
+ end
20
+
21
+
22
+ it "handles amqp:// URIs w/o path part" do
23
+ val = described_class.parse_connection_uri("amqp://dev.rabbitmq.com")
24
+
25
+ val[:vhost].should be_nil # in this case, default / will be used
26
+ val[:host].should == "dev.rabbitmq.com"
27
+ val[:port].should == 5672
28
+ val[:scheme].should == "amqp"
29
+ val[:ssl].should be_false
30
+ end
31
+
32
+ it "handles amqps:// URIs w/o path part" do
33
+ val = described_class.parse_connection_uri("amqps://dev.rabbitmq.com")
34
+
35
+ val[:vhost].should be_nil
36
+ val[:host].should == "dev.rabbitmq.com"
37
+ val[:port].should == 5671
38
+ val[:scheme].should == "amqps"
39
+ val[:ssl].should be_true
40
+ end
41
+
42
+
43
+ context "when URI ends in a slash" do
44
+ it "parses vhost as an empty string" do
45
+ val = described_class.parse_connection_uri("amqp://dev.rabbitmq.com/")
46
+
47
+ val[:host].should == "dev.rabbitmq.com"
48
+ val[:port].should == 5672
49
+ val[:scheme].should == "amqp"
50
+ val[:ssl].should be_false
51
+ val[:vhost].should == ""
52
+ end
53
+ end
54
+
55
+
56
+ context "when URI ends in two consecutive slashes (//)" do
57
+ it "parses vhost as /" do
58
+ val = described_class.parse_connection_uri("amqp://dev.rabbitmq.com//")
59
+
60
+ val[:host].should == "dev.rabbitmq.com"
61
+ val[:port].should == 5672
62
+ val[:scheme].should == "amqp"
63
+ val[:ssl].should be_false
64
+ val[:vhost].should == "/"
65
+ end
66
+ end
67
+
68
+
69
+ context "when URI ends in //vault" do
70
+ it "parses vhost as /vault" do
71
+ val = described_class.parse_connection_uri("amqp://dev.rabbitmq.com//vault")
72
+
73
+ val[:host].should == "dev.rabbitmq.com"
74
+ val[:port].should == 5672
75
+ val[:scheme].should == "amqp"
76
+ val[:ssl].should be_false
77
+ val[:vhost].should == "/vault"
78
+ end
79
+ end
80
+
81
+
82
+
83
+ context "when URI ends in /%2Fvault" do
84
+ it "parses vhost as /vault" do
85
+ val = described_class.parse_connection_uri("amqp://dev.rabbitmq.com/%2Fvault")
86
+
87
+ val[:host].should == "dev.rabbitmq.com"
88
+ val[:port].should == 5672
89
+ val[:scheme].should == "amqp"
90
+ val[:ssl].should be_false
91
+ val[:vhost].should == "/vault"
92
+ end
93
+ end
94
+
95
+
96
+ context "when URI is amqp://dev.rabbitmq.com/i.am.a.vhost.without.slashes" do
97
+ it "parses vhost as i.am.a.vhost.without.slashes" do
98
+ val = described_class.parse_connection_uri("amqp://dev.rabbitmq.com/i.am.a.vhost.without.slashes")
99
+
100
+ val[:host].should == "dev.rabbitmq.com"
101
+ val[:port].should == 5672
102
+ val[:scheme].should == "amqp"
103
+ val[:ssl].should be_false
104
+ val[:vhost].should == "i.am.a.vhost.without.slashes"
105
+ end
106
+ end
107
+
108
+
109
+ context "when URI is amqp://dev.rabbitmq.com/production" do
110
+ it "parses vhost as production" do
111
+ val = described_class.parse_connection_uri("amqp://dev.rabbitmq.com/production")
112
+
113
+ val[:host].should == "dev.rabbitmq.com"
114
+ val[:port].should == 5672
115
+ val[:scheme].should == "amqp"
116
+ val[:ssl].should be_false
117
+ val[:vhost].should == "production"
118
+ end
119
+ end
120
+
121
+
122
+ context "when URI is amqp://dev.rabbitmq.com///a/b/c/d" do
123
+ it "parses vhost as ///a/b/c/d" do
124
+ val = described_class.parse_connection_uri("amqp://dev.rabbitmq.com///a/b/c/d")
125
+
126
+ val[:host].should == "dev.rabbitmq.com"
127
+ val[:port].should == 5672
128
+ val[:scheme].should == "amqp"
129
+ val[:ssl].should be_false
130
+ val[:vhost].should == "//a/b/c/d"
131
+ end
132
+ end
133
+
134
+
135
+ context "when URI has username:password, for instance, amqp://hedgehog:t0ps3kr3t@hub.megacorp.internal" do
136
+ it "parses them out" do
137
+ val = described_class.parse_connection_uri("amqp://hedgehog:t0ps3kr3t@hub.megacorp.internal")
138
+
139
+ val[:host].should == "hub.megacorp.internal"
140
+ val[:port].should == 5672
141
+ val[:scheme].should == "amqp"
142
+ val[:ssl].should be_false
143
+ val[:user].should == "hedgehog"
144
+ val[:pass].should == "t0ps3kr3t"
145
+ val[:vhost].should be_nil # in this case, default / will be used
146
+ end
147
+ end
148
+ end
149
+ end