Use ENV["MONGODB_URI"] if available.

This commit is contained in:
Seamus Abshere 2012-05-18 11:17:21 -05:00 committed by Tyler Brock
parent 351eeb65a2
commit 1454210d9f
8 changed files with 296 additions and 84 deletions

View File

@ -173,6 +173,14 @@ Certain Ruby application servers work by forking, and it has long been necessary
re-establish the child process's connection to the database after fork. But with the release re-establish the child process's connection to the database after fork. But with the release
of v1.3.0, the Ruby driver detects forking and reconnects automatically. of v1.3.0, the Ruby driver detects forking and reconnects automatically.
## Environment variable `MONGODB_URI`
`Mongo::Connection.new` and `Mongo::ReplSetConnection.new` will use <code>ENV["MONGODB_URI"]</code> if no other args are provided.
The URI must fit this specification:
mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
## String Encoding ## String Encoding
The BSON ("Binary JSON") format used to communicate with Mongo requires that The BSON ("Binary JSON") format used to communicate with Mongo requires that

View File

@ -32,6 +32,7 @@ module Mongo
Thread.abort_on_exception = true Thread.abort_on_exception = true
DEFAULT_HOST = 'localhost'
DEFAULT_PORT = 27017 DEFAULT_PORT = 27017
GENERIC_OPTS = [:ssl, :auths, :pool_size, :pool_timeout, :timeout, :op_timeout, :connect_timeout, :safe, :logger, :connect] GENERIC_OPTS = [:ssl, :auths, :pool_size, :pool_timeout, :timeout, :op_timeout, :connect_timeout, :safe, :logger, :connect]
CONNECTION_OPTS = [:slave_ok] CONNECTION_OPTS = [:slave_ok]
@ -44,6 +45,8 @@ module Mongo
# Create a connection to single MongoDB instance. # Create a connection to single MongoDB instance.
# #
# If no args are provided, it will check <code>ENV["MONGODB_URI"]</code>.
#
# You may specify whether connection to slave is permitted. # You may specify whether connection to slave is permitted.
# In all cases, the default host is "localhost" and the default port is 27017. # In all cases, the default host is "localhost" and the default port is 27017.
# #
@ -76,7 +79,7 @@ module Mongo
# connection attempt. # connection attempt.
# @option opts [Boolean] :ssl (false) If true, create the connection to the server using SSL. # @option opts [Boolean] :ssl (false) If true, create the connection to the server using SSL.
# #
# @example localhost, 27017 # @example localhost, 27017 (or <code>ENV["MONGODB_URI"]</code> if available)
# Mongo::Connection.new # Mongo::Connection.new
# #
# @example localhost, 27017 # @example localhost, 27017
@ -93,9 +96,22 @@ module Mongo
# @raise [ReplicaSetConnectionError] This is raised if a replica set name is specified and the # @raise [ReplicaSetConnectionError] This is raised if a replica set name is specified and the
# driver fails to connect to a replica set with that name. # driver fails to connect to a replica set with that name.
# #
# @raise [MongoArgumentError] If called with no arguments and <code>ENV["MONGODB_URI"]</code> implies a replica set.
#
# @core self.connections # @core self.connections
def initialize(host=nil, port=nil, opts={}) def initialize(host=nil, port=nil, opts={})
@host_to_try = format_pair(host, port) if host.nil? and ENV.has_key?('MONGODB_URI')
parser = URIParser.new ENV['MONGODB_URI'], opts
if parser.replicaset?
raise MongoArgumentError, "Mongo::Connection.new called with no arguments, but ENV['MONGODB_URI'] implies a replica set."
end
opts = parser.connection_options
@host_to_try = [parser.host, parser.port]
elsif host.is_a?(String)
@host_to_try = [host, (port || DEFAULT_PORT).to_i]
else
@host_to_try = [DEFAULT_HOST, DEFAULT_PORT]
end
# Host and port of current master. # Host and port of current master.
@host = @port = nil @host = @port = nil
@ -143,8 +159,7 @@ module Mongo
def self.multi(nodes, opts={}) def self.multi(nodes, opts={})
warn "Connection.multi is now deprecated and will be removed in v2.0. Please use ReplSetConnection.new instead." warn "Connection.multi is now deprecated and will be removed in v2.0. Please use ReplSetConnection.new instead."
nodes << opts ReplSetConnection.new(*(nodes+[opts]))
ReplSetConnection.new(*nodes)
end end
# Initialize a connection to MongoDB using the MongoDB URI spec: # Initialize a connection to MongoDB using the MongoDB URI spec:
@ -155,21 +170,9 @@ module Mongo
# @param opts Any of the options available for Connection.new # @param opts Any of the options available for Connection.new
# #
# @return [Mongo::Connection, Mongo::ReplSetConnection] # @return [Mongo::Connection, Mongo::ReplSetConnection]
def self.from_uri(string, extra_opts={}) def self.from_uri(uri, extra_opts={})
uri = URIParser.new(string) parser = URIParser.new uri, extra_opts
opts = uri.connection_options parser.connection
opts.merge!(extra_opts)
if uri.nodes.length == 1
opts.merge!({:auths => uri.auths})
Connection.new(uri.nodes[0][0], uri.nodes[0][1], opts)
elsif uri.nodes.length > 1
nodes = uri.nodes.clone
nodes_with_opts = nodes << opts
ReplSetConnection.new(*nodes_with_opts)
else
raise MongoArgumentError, "No nodes specified. Please ensure that you've provided at least one node."
end
end end
# The host name used for this connection. # The host name used for this connection.
@ -337,7 +340,7 @@ module Mongo
# @param [String] from_host host of the 'from' database. # @param [String] from_host host of the 'from' database.
# @param [String] username username for authentication against from_db (>=1.3.x). # @param [String] username username for authentication against from_db (>=1.3.x).
# @param [String] password password for authentication against from_db (>=1.3.x). # @param [String] password password for authentication against from_db (>=1.3.x).
def copy_database(from, to, from_host="localhost", username=nil, password=nil) def copy_database(from, to, from_host=DEFAULT_HOST, username=nil, password=nil)
oh = BSON::OrderedHash.new oh = BSON::OrderedHash.new
oh[:copydb] = 1 oh[:copydb] = 1
oh[:fromhost] = from_host oh[:fromhost] = from_host
@ -585,23 +588,8 @@ module Mongo
write_logging_startup_message write_logging_startup_message
end end
should_connect = opts.fetch(:connect, true) if opts.fetch(:connect, true)
connect if should_connect connect
end
## Configuration helper methods
# Returns a host-port pair.
#
# @return [Array]
#
# @private
def format_pair(host, port)
case host
when String
[host, port ? port.to_i : DEFAULT_PORT]
when nil
['localhost', DEFAULT_PORT]
end end
end end

View File

@ -29,6 +29,8 @@ module Mongo
# Create a connection to a MongoDB replica set. # Create a connection to a MongoDB replica set.
# #
# If no args are provided, it will check <code>ENV["MONGODB_URI"]</code>.
#
# Once connected to a replica set, you can find out which nodes are primary, secondary, and # Once connected to a replica set, you can find out which nodes are primary, secondary, and
# arbiters with the corresponding accessors: Connection#primary, Connection#secondaries, and # arbiters with the corresponding accessors: Connection#primary, Connection#secondaries, and
# Connection#arbiters. This is useful if your application needs to connect manually to nodes other # Connection#arbiters. This is useful if your application needs to connect manually to nodes other
@ -78,6 +80,8 @@ module Mongo
# #
# @see http://api.mongodb.org/ruby/current/file.REPLICA_SETS.html Replica sets in Ruby # @see http://api.mongodb.org/ruby/current/file.REPLICA_SETS.html Replica sets in Ruby
# #
# @raise [MongoArgumentError] If called with no arguments and <code>ENV["MONGODB_URI"]</code> implies a direct connection.
#
# @raise [ReplicaSetConnectionError] This is raised if a replica set name is specified and the # @raise [ReplicaSetConnectionError] This is raised if a replica set name is specified and the
# driver fails to connect to a replica set with that name. # driver fails to connect to a replica set with that name.
def initialize(*args) def initialize(*args)
@ -87,21 +91,30 @@ module Mongo
opts = {} opts = {}
end end
unless args.length > 0 nodes = args
if nodes.empty? and ENV.has_key?('MONGODB_URI')
parser = URIParser.new ENV['MONGODB_URI'], opts
if parser.direct?
raise MongoArgumentError, "Mongo::ReplSetConnection.new called with no arguments, but ENV['MONGODB_URI'] implies a direct connection."
end
opts = parser.connection_options
nodes = parser.nodes
end
unless nodes.length > 0
raise MongoArgumentError, "A ReplSetConnection requires at least one seed node." raise MongoArgumentError, "A ReplSetConnection requires at least one seed node."
end end
# This is temporary until support for the old format is dropped # This is temporary until support for the old format is dropped
@seeds = [] if nodes.first.last.is_a?(Integer)
if args.first.last.is_a?(Integer)
warn "Initiating a ReplSetConnection with seeds passed as individual [host, port] array arguments is deprecated." warn "Initiating a ReplSetConnection with seeds passed as individual [host, port] array arguments is deprecated."
warn "Please specify hosts as an array of 'host:port' strings; the old format will be removed in v2.0" warn "Please specify hosts as an array of 'host:port' strings; the old format will be removed in v2.0"
@seeds = args @seeds = nodes
else else
args.first.map do |host_port| @seeds = nodes.first.map do |host_port|
seed = host_port.split(":") host, port = host_port.split(":")
seed[1] = seed[1].to_i [ host, port.to_i ]
seeds << seed
end end
end end

View File

@ -16,11 +16,11 @@
# limitations under the License. # limitations under the License.
# ++ # ++
require 'uri'
module Mongo module Mongo
class URIParser class URIParser
DEFAULT_PORT = 27017
USER_REGEX = /([-.\w:]+)/ USER_REGEX = /([-.\w:]+)/
PASS_REGEX = /([^@,]+)/ PASS_REGEX = /([^@,]+)/
AUTH_REGEX = /(#{USER_REGEX}:#{PASS_REGEX}@)?/ AUTH_REGEX = /(#{USER_REGEX}:#{PASS_REGEX}@)?/
@ -37,7 +37,7 @@ module Mongo
SPEC_ATTRS = [:nodes, :auths] SPEC_ATTRS = [:nodes, :auths]
OPT_ATTRS = [:connect, :replicaset, :slaveok, :safe, :w, :wtimeout, :fsync, :journal, :connecttimeoutms, :sockettimeoutms, :wtimeoutms] OPT_ATTRS = [:connect, :replicaset, :slaveok, :safe, :w, :wtimeout, :fsync, :journal, :connecttimeoutms, :sockettimeoutms, :wtimeoutms]
OPT_VALID = {:connect => lambda {|arg| ['direct', 'replicaset'].include?(arg)}, OPT_VALID = {:connect => lambda {|arg| ['direct', 'replicaset', 'true', 'false', true, false].include?(arg)},
:replicaset => lambda {|arg| arg.length > 0}, :replicaset => lambda {|arg| arg.length > 0},
:slaveok => lambda {|arg| ['true', 'false'].include?(arg)}, :slaveok => lambda {|arg| ['true', 'false'].include?(arg)},
:safe => lambda {|arg| ['true', 'false'].include?(arg)}, :safe => lambda {|arg| ['true', 'false'].include?(arg)},
@ -50,7 +50,7 @@ module Mongo
:wtimeoutms => lambda {|arg| arg =~ /^\d+$/ } :wtimeoutms => lambda {|arg| arg =~ /^\d+$/ }
} }
OPT_ERR = {:connect => "must be 'direct' or 'replicaset'", OPT_ERR = {:connect => "must be 'direct', 'replicaset', 'true', or 'false'",
:replicaset => "must be a string containing the name of the replica set to connect to", :replicaset => "must be a string containing the name of the replica set to connect to",
:slaveok => "must be 'true' or 'false'", :slaveok => "must be 'true' or 'false'",
:safe => "must be 'true' or 'false'", :safe => "must be 'true' or 'false'",
@ -63,7 +63,7 @@ module Mongo
:wtimeoutms => "must be an integer specifying milliseconds" :wtimeoutms => "must be an integer specifying milliseconds"
} }
OPT_CONV = {:connect => lambda {|arg| arg}, OPT_CONV = {:connect => lambda {|arg| arg == 'false' ? false : arg}, # be sure to convert 'false' to FalseClass
:replicaset => lambda {|arg| arg}, :replicaset => lambda {|arg| arg},
:slaveok => lambda {|arg| arg == 'true' ? true : false}, :slaveok => lambda {|arg| arg == 'true' ? true : false},
:safe => lambda {|arg| arg == 'true' ? true : false}, :safe => lambda {|arg| arg == 'true' ? true : false},
@ -81,22 +81,73 @@ module Mongo
# Parse a MongoDB URI. This method is used by Connection.from_uri. # Parse a MongoDB URI. This method is used by Connection.from_uri.
# Returns an array of nodes and an array of db authorizations, if applicable. # Returns an array of nodes and an array of db authorizations, if applicable.
# #
# Note: passwords can contain any character except for a ','. # @note Passwords can contain any character except for ','
#
# @param [String] uri The MongoDB URI string.
# @param [Hash,nil] extra_opts Extra options. Will override anything already specified in the URI.
# #
# @core connections # @core connections
def initialize(string) def initialize(uri, extra_opts={})
if string =~ /^mongodb:\/\// if uri.start_with?('mongodb://')
string = string[10..-1] uri = uri[10..-1]
else else
raise MongoArgumentError, "MongoDB URI must match this spec: #{MONGODB_URI_SPEC}" raise MongoArgumentError, "MongoDB URI must match this spec: #{MONGODB_URI_SPEC}"
end end
hosts, opts = string.split('?') hosts, opts = uri.split('?')
parse_hosts(hosts) parse_hosts(hosts)
parse_options(opts) parse_options(opts, extra_opts)
configure_connect validate_connect
end end
# Create a Mongo::Connection or a Mongo::ReplSetConnection based on the URI.
#
# @note Don't confuse this with attribute getter method #connect.
#
# @return [Connection,ReplSetConnection]
def connection
if replicaset?
ReplSetConnection.new(*(nodes+[connection_options]))
else
Connection.new(host, port, connection_options)
end
end
# Whether this represents a replica set.
# @return [true,false]
def replicaset?
replicaset.is_a?(String) || nodes.length > 1
end
# Whether to immediately connect to the MongoDB node[s]. Defaults to true.
# @return [true, false]
def connect?
connect != false
end
# Whether this represents a direct connection.
#
# @note Specifying :connect => 'direct' has no effect... other than to raise an exception if other variables suggest a replicaset.
#
# @return [true,false]
def direct?
!replicaset?
end
# For direct connections, the host of the (only) node.
# @return [String]
def host
nodes[0][0]
end
# For direct connections, the port of the (only) node.
# @return [Integer]
def port
nodes[0][1].to_i
end
# Options that can be passed to Mongo::Connection.new or Mongo::ReplSetConnection.new
# @return [Hash]
def connection_options def connection_options
opts = {} opts = {}
@ -136,14 +187,22 @@ module Mongo
end end
if @slaveok if @slaveok
if @connect == 'direct' if direct?
opts[:slave_ok] = true opts[:slave_ok] = true
else else
opts[:read] = :secondary opts[:read] = :secondary
end end
end end
opts[:name] = @replicaset if @replicaset if direct?
opts[:auths] = auths
end
if replicaset.is_a?(String)
opts[:name] = replicaset
end
opts[:connect] = connect?
opts opts
end end
@ -167,7 +226,7 @@ module Mongo
hosturis.each do |hosturi| hosturis.each do |hosturi|
# If port is present, use it, otherwise use default port # If port is present, use it, otherwise use default port
host, port = hosturi.split(':') + [DEFAULT_PORT] host, port = hosturi.split(':') + [Connection::DEFAULT_PORT]
if !(port.to_s =~ /^\d+$/) if !(port.to_s =~ /^\d+$/)
raise MongoArgumentError, "Invalid port #{port}; port must be specified as digits." raise MongoArgumentError, "Invalid port #{port}; port must be specified as digits."
@ -178,6 +237,10 @@ module Mongo
@nodes << [host, port] @nodes << [host, port]
end end
if @nodes.empty?
raise MongoArgumentError, "No nodes specified. Please ensure that you've provided at least one node."
end
if uname && pwd && db if uname && pwd && db
auths << {'db_name' => db, 'username' => uname, 'password' => pwd} auths << {'db_name' => db, 'username' => uname, 'password' => pwd}
elsif uname || pwd elsif uname || pwd
@ -191,40 +254,37 @@ module Mongo
# This method uses the lambdas defined in OPT_VALID and OPT_CONV to validate # This method uses the lambdas defined in OPT_VALID and OPT_CONV to validate
# and convert the given options. # and convert the given options.
def parse_options(opts) def parse_options(string_opts, extra_opts={})
# initialize instance variables for available options # initialize instance variables for available options
OPT_VALID.keys.each { |k| instance_variable_set("@#{k}", nil) } OPT_VALID.keys.each { |k| instance_variable_set("@#{k}", nil) }
return unless opts string_opts ||= ''
separator = opts.include?('&') ? '&' : ';' return if string_opts.empty? && extra_opts.empty?
opts.split(separator).each do |attr|
key, value = attr.split('=') opts = URI.decode_www_form(string_opts).inject({}) do |memo, (key, value)|
key = key.downcase.to_sym memo[key.downcase.to_sym] = value.strip.downcase
value = value.strip.downcase memo
end
opts.merge! extra_opts
opts.each do |key, value|
if !OPT_ATTRS.include?(key) if !OPT_ATTRS.include?(key)
raise MongoArgumentError, "Invalid Mongo URI option #{key}" raise MongoArgumentError, "Invalid Mongo URI option #{key}"
end end
if OPT_VALID[key].call(value) if OPT_VALID[key].call(value)
instance_variable_set("@#{key}", OPT_CONV[key].call(value)) instance_variable_set("@#{key}", OPT_CONV[key].call(value))
else else
raise MongoArgumentError, "Invalid value for #{key}: #{OPT_ERR[key]}" raise MongoArgumentError, "Invalid value #{value.inspect} for #{key}: #{OPT_ERR[key]}"
end end
end end
end end
def configure_connect def validate_connect
if !@connect if replicaset? and @connect == 'direct'
if @nodes.length > 1 # Make sure the user doesn't specify something contradictory
@connect = 'replicaset' raise MongoArgumentError, "connect=direct conflicts with setting a replicaset name"
else
@connect = 'direct'
end
end
if @connect == 'direct' && @replicaset
raise MongoArgumentError, "If specifying a replica set name, please also specify that connect=replicaset"
end end
end end
end end

View File

@ -58,6 +58,18 @@ class TestConnection < Test::Unit::TestCase
assert_equal mongo_port, con.primary_pool.port assert_equal mongo_port, con.primary_pool.port
end end
def test_env_mongodb_uri
begin
old_mongodb_uri = ENV['MONGODB_URI']
ENV['MONGODB_URI'] = "mongodb://#{host_port}"
con = Connection.new
assert_equal mongo_host, con.primary_pool.host
assert_equal mongo_port, con.primary_pool.port
ensure
ENV['MONGODB_URI'] = old_mongodb_uri
end
end
def test_server_version def test_server_version
assert_match(/\d\.\d+(\.\d+)?/, @conn.server_version.to_s) assert_match(/\d\.\d+(\.\d+)?/, @conn.server_version.to_s)
end end

View File

@ -106,6 +106,20 @@ class ConnectTest < Test::Unit::TestCase
assert @conn.connected? assert @conn.connected?
end end
def test_connect_with_connection_string_in_env_var
begin
old_mongodb_uri = ENV['MONGODB_URI']
ENV['MONGODB_URI'] = "mongodb://#{@rs.host}:#{@rs.ports[0]},#{@rs.host}:#{@rs.ports[1]}?replicaset=#{@rs.name}"
silently do
@conn = ReplSetConnection.new
end
assert @conn.is_a?(ReplSetConnection)
assert @conn.connected?
ensure
ENV['MONGODB_URI'] = old_mongodb_uri
end
end
def test_connect_with_new_seed_format def test_connect_with_new_seed_format
@conn = ReplSetConnection.new build_seeds(3) @conn = ReplSetConnection.new build_seeds(3)
assert @conn.connected? assert @conn.connected?
@ -128,4 +142,21 @@ class ConnectTest < Test::Unit::TestCase
assert @conn.safe[:fsync] assert @conn.safe[:fsync]
assert @conn.read_pool assert @conn.read_pool
end end
def test_connect_with_full_connection_string_in_env_var
begin
old_mongodb_uri = ENV['MONGODB_URI']
ENV['MONGODB_URI'] = "mongodb://#{@rs.host}:#{@rs.ports[0]},#{@rs.host}:#{@rs.ports[1]}?replicaset=#{@rs.name};safe=true;w=2;fsync=true;slaveok=true"
silently do
@conn = ReplSetConnection.new
end
assert @conn.is_a?(ReplSetConnection)
assert @conn.connected?
assert_equal 2, @conn.safe[:w]
assert @conn.safe[:fsync]
assert @conn.read_pool
ensure
ENV['MONGODB_URI'] = old_mongodb_uri
end
end
end end

View File

@ -130,5 +130,93 @@ class ConnectionTest < Test::Unit::TestCase
end end
end end
end end
context "initializing with ENV['MONGODB_URI']" do
setup do
@old_mongodb_uri = ENV['MONGODB_URI']
end
teardown do
ENV['MONGODB_URI'] = @old_mongodb_uri
end
should "parse a simple uri" do
ENV['MONGODB_URI'] = "mongodb://localhost?connect=false"
@conn = Connection.new
assert_equal ['localhost', 27017], @conn.host_to_try
end
should "allow a complex host names" do
host_name = "foo.bar-12345.org"
ENV['MONGODB_URI'] = "mongodb://#{host_name}?connect=false"
@conn = Connection.new
assert_equal [host_name, 27017], @conn.host_to_try
end
should "allow db without username and password" do
host_name = "foo.bar-12345.org"
ENV['MONGODB_URI'] = "mongodb://#{host_name}/foo?connect=false"
@conn = Connection.new
assert_equal [host_name, 27017], @conn.host_to_try
end
should "set safe options on connection" do
host_name = "localhost"
opts = "safe=true&w=2&wtimeoutMS=1000&fsync=true&journal=true&connect=false"
ENV['MONGODB_URI'] = "mongodb://#{host_name}/foo?#{opts}"
@conn = Connection.new
assert_equal({:w => 2, :wtimeout => 1000, :fsync => true, :j => true}, @conn.safe)
end
should "set timeout options on connection" do
host_name = "localhost"
opts = "connectTimeoutMS=1000&socketTimeoutMS=5000&connect=false"
ENV['MONGODB_URI'] = "mongodb://#{host_name}/foo?#{opts}"
@conn = Connection.new
assert_equal 1, @conn.connect_timeout
assert_equal 5, @conn.op_timeout
end
should "parse a uri with a hyphen & underscore in the username or password" do
ENV['MONGODB_URI'] = "mongodb://hyphen-user_name:p-s_s@localhost:27017/db?connect=false"
@conn = Connection.new
assert_equal ['localhost', 27017], @conn.host_to_try
auth_hash = { 'db_name' => 'db', 'username' => 'hyphen-user_name', "password" => 'p-s_s' }
assert_equal auth_hash, @conn.auths[0]
end
should "attempt to connect" do
TCPSocket.stubs(:new).returns(new_mock_socket)
ENV['MONGODB_URI'] = "mongodb://localhost?connect=false" # connect=false ??
@conn = Connection.new
admin_db = new_mock_db
admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1})
@conn.expects(:[]).with('admin').returns(admin_db)
@conn.connect
end
should "raise an error on invalid uris" do
ENV['MONGODB_URI'] = "mongo://localhost"
assert_raise MongoArgumentError do
Connection.new
end
ENV['MONGODB_URI'] = "mongodb://localhost:abc"
assert_raise MongoArgumentError do
Connection.new
end
end
should "require all of username, if password and db are specified" do
ENV['MONGODB_URI'] = "mongodb://kyle:jones@localhost/db?connect=false"
assert Connection.new
ENV['MONGODB_URI'] = "mongodb://kyle:password@localhost"
assert_raise MongoArgumentError do
Connection.new
end
end
end
end end
end end

View File

@ -63,9 +63,10 @@ class URITest < Test::Unit::TestCase
assert_equal "test", parser.auths[1]["db_name"] assert_equal "test", parser.auths[1]["db_name"]
end end
def test_opts_basic def test_opts_with_semincolon_separator
parser = Mongo::URIParser.new('mongodb://localhost:27018?connect=direct;slaveok=true;safe=true') parser = Mongo::URIParser.new('mongodb://localhost:27018?connect=direct;slaveok=true;safe=true')
assert_equal 'direct', parser.connect assert_equal 'direct', parser.connect
assert parser.direct?
assert parser.slaveok assert parser.slaveok
assert parser.safe assert parser.safe
end end
@ -73,10 +74,17 @@ class URITest < Test::Unit::TestCase
def test_opts_with_amp_separator def test_opts_with_amp_separator
parser = Mongo::URIParser.new('mongodb://localhost:27018?connect=direct&slaveok=true&safe=true') parser = Mongo::URIParser.new('mongodb://localhost:27018?connect=direct&slaveok=true&safe=true')
assert_equal 'direct', parser.connect assert_equal 'direct', parser.connect
assert parser.direct?
assert parser.slaveok assert parser.slaveok
assert parser.safe assert parser.safe
end end
def test_opts_made_invalid_by_mixed_separators
assert_raise_error ArgumentError, "invalid data of application/x-www-form-urlencoded (replicaset=foo;bar&slaveok=true&safe=true)" do
Mongo::URIParser.new('mongodb://localhost:27018?replicaset=foo;bar&slaveok=true&safe=true')
end
end
def test_opts_safe def test_opts_safe
parser = Mongo::URIParser.new('mongodb://localhost:27018?safe=true;w=2;journal=true;fsync=true;wtimeoutMS=200') parser = Mongo::URIParser.new('mongodb://localhost:27018?safe=true;w=2;journal=true;fsync=true;wtimeoutMS=200')
assert parser.safe assert parser.safe
@ -93,12 +101,16 @@ class URITest < Test::Unit::TestCase
end end
def test_opts_replica_set def test_opts_replica_set
assert_raise_error MongoArgumentError, "specify that connect=replicaset" do
Mongo::URIParser.new('mongodb://localhost:27018?replicaset=foo')
end
parser = Mongo::URIParser.new('mongodb://localhost:27018?connect=replicaset;replicaset=foo') parser = Mongo::URIParser.new('mongodb://localhost:27018?connect=replicaset;replicaset=foo')
assert_equal 'foo', parser.replicaset assert_equal 'foo', parser.replicaset
assert_equal 'replicaset', parser.connect assert_equal 'replicaset', parser.connect
assert parser.replicaset?
end
def test_opts_conflicting_replica_set
assert_raise_error MongoArgumentError, "connect=direct conflicts with setting a replicaset name" do
Mongo::URIParser.new('mongodb://localhost:27018?connect=direct;replicaset=foo')
end
end end
def test_case_insensitivity def test_case_insensitivity