Initial ReplSetConnection checking. Refactoring.
This commit is contained in:
parent
a17455da27
commit
08b7cddc81
|
@ -42,9 +42,11 @@ require 'mongo/util/support'
|
|||
require 'mongo/util/core_ext'
|
||||
require 'mongo/util/pool'
|
||||
require 'mongo/util/server_version'
|
||||
require 'mongo/util/uri_parser'
|
||||
|
||||
require 'mongo/collection'
|
||||
require 'mongo/connection'
|
||||
require 'mongo/repl_set_connection'
|
||||
require 'mongo/cursor'
|
||||
require 'mongo/db'
|
||||
require 'mongo/exceptions'
|
||||
|
|
|
@ -39,7 +39,7 @@ module Mongo
|
|||
MONGODB_URI_SPEC = "mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/database]"
|
||||
|
||||
attr_reader :logger, :size, :nodes, :auths, :primary, :secondaries, :arbiters,
|
||||
:safe, :primary_pool, :read_pool, :secondary_pools
|
||||
:safe, :primary_pool, :read_pool, :secondary_pools, :host_to_try
|
||||
|
||||
# Counter for generating unique request ids.
|
||||
@@current_request_id = 0
|
||||
|
@ -92,20 +92,13 @@ module Mongo
|
|||
#
|
||||
# @core connections
|
||||
def initialize(host=nil, port=nil, options={})
|
||||
@auths = []
|
||||
@auths = options.fetch(:auths, [])
|
||||
|
||||
if block_given?
|
||||
@nodes = yield self
|
||||
else
|
||||
@nodes = format_pair(host, port)
|
||||
end
|
||||
@host_to_try = format_pair(host, port)
|
||||
|
||||
# Host and port of current master.
|
||||
@host = @port = nil
|
||||
|
||||
# Replica set name
|
||||
@replica_set_name = options[:rs_name]
|
||||
|
||||
# Lock for request ids.
|
||||
@id_lock = Mutex.new
|
||||
|
||||
|
@ -129,25 +122,19 @@ module Mongo
|
|||
# slave_ok can be true only if one node is specified
|
||||
@slave_ok = options[:slave_ok]
|
||||
|
||||
# Cache the various node types
|
||||
# when connecting to a replica set.
|
||||
@primary = nil
|
||||
@secondaries = []
|
||||
@arbiters = []
|
||||
|
||||
# Connection pool for primay node
|
||||
@primary_pool = nil
|
||||
|
||||
# Connection pools for each secondary node
|
||||
@secondary_pools = []
|
||||
@read_pool = nil
|
||||
|
||||
@logger = options[:logger] || nil
|
||||
|
||||
should_connect = options.fetch(:connect, true)
|
||||
connect if should_connect
|
||||
end
|
||||
|
||||
# DEPRECATED
|
||||
#
|
||||
# Initialize a connection to a MongoDB replica set using an array of seed nodes.
|
||||
#
|
||||
# The seed nodes specified will be used on the initial connection to the replica set, but note
|
||||
|
@ -170,6 +157,8 @@ module Mongo
|
|||
# :read_secondary => true)
|
||||
#
|
||||
# @return [Mongo::Connection]
|
||||
#
|
||||
# @deprecated
|
||||
def self.multi(nodes, opts={})
|
||||
unless nodes.length > 0 && nodes.all? {|n| n.is_a? Array}
|
||||
raise MongoArgumentError, "Connection.multi requires at least one node to be specified."
|
||||
|
@ -195,8 +184,13 @@ module Mongo
|
|||
#
|
||||
# @return [Mongo::Connection]
|
||||
def self.from_uri(uri, opts={})
|
||||
new(nil, nil, opts) do |con|
|
||||
con.parse_uri(uri)
|
||||
nodes, auths = Mongo::URIParser.parse(uri)
|
||||
opts.merge!({:auths => auths})
|
||||
if nodes.length == 1
|
||||
Connection.new(nodes[0][0], nodes[0][1], opts)
|
||||
elsif nodes.length > 1
|
||||
nodes << opts
|
||||
ReplSetConnection.new(*nodes)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -480,21 +474,12 @@ module Mongo
|
|||
# @raise [ConnectionFailure] if unable to connect to any host or port.
|
||||
def connect
|
||||
reset_connection
|
||||
@nodes_to_try = @nodes.clone
|
||||
|
||||
while connecting?
|
||||
node = @nodes_to_try.shift
|
||||
config = check_is_master(node)
|
||||
|
||||
if is_primary?(config)
|
||||
set_primary(node)
|
||||
else
|
||||
set_auxillary(node, config)
|
||||
end
|
||||
config = check_is_master(@host_to_try)
|
||||
if is_primary?(config)
|
||||
set_primary(@host_to_try)
|
||||
end
|
||||
|
||||
pick_secondary_for_read if @read_secondary
|
||||
|
||||
raise ConnectionFailure, "failed to connect to any given host:port" unless connected?
|
||||
end
|
||||
|
||||
|
@ -513,23 +498,21 @@ module Mongo
|
|||
def close
|
||||
@primary_pool.close if @primary_pool
|
||||
@primary_pool = nil
|
||||
@read_pool = nil
|
||||
@secondary_pools.each do |pool|
|
||||
pool.close
|
||||
end
|
||||
end
|
||||
|
||||
## Configuration helper methods
|
||||
|
||||
# Returns an array of host-port pairs.
|
||||
# Returns a host-port pair.
|
||||
#
|
||||
# @return [Array]
|
||||
#
|
||||
# @private
|
||||
def format_pair(pair_or_host, port)
|
||||
case pair_or_host
|
||||
def format_pair(host, port)
|
||||
case host
|
||||
when String
|
||||
[[pair_or_host, port ? port.to_i : DEFAULT_PORT]]
|
||||
[host, port ? port.to_i : DEFAULT_PORT]
|
||||
when nil
|
||||
[['localhost', DEFAULT_PORT]]
|
||||
['localhost', DEFAULT_PORT]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -550,50 +533,7 @@ module Mongo
|
|||
end
|
||||
end
|
||||
|
||||
# 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.
|
||||
#
|
||||
# @private
|
||||
def parse_uri(string)
|
||||
if string =~ /^mongodb:\/\//
|
||||
string = string[10..-1]
|
||||
else
|
||||
raise MongoArgumentError, "MongoDB URI must match this spec: #{MONGODB_URI_SPEC}"
|
||||
end
|
||||
|
||||
nodes = []
|
||||
auths = []
|
||||
specs = string.split(',')
|
||||
specs.each do |spec|
|
||||
matches = MONGODB_URI_MATCHER.match(spec)
|
||||
if !matches
|
||||
raise MongoArgumentError, "MongoDB URI must match this spec: #{MONGODB_URI_SPEC}"
|
||||
end
|
||||
|
||||
uname = matches[2]
|
||||
pwd = matches[3]
|
||||
host = matches[4]
|
||||
port = matches[6] || DEFAULT_PORT
|
||||
if !(port.to_s =~ /^\d+$/)
|
||||
raise MongoArgumentError, "Invalid port #{port}; port must be specified as digits."
|
||||
end
|
||||
port = port.to_i
|
||||
db = matches[8]
|
||||
|
||||
if uname && pwd && db
|
||||
add_auth(db, uname, pwd)
|
||||
elsif uname || pwd || db
|
||||
raise MongoArgumentError, "MongoDB URI must include all three of username, password, " +
|
||||
"and db if any one of these is specified."
|
||||
end
|
||||
|
||||
nodes << [host, port]
|
||||
end
|
||||
|
||||
nodes
|
||||
end
|
||||
|
||||
# Checkout a socket for reading (i.e., a secondary node).
|
||||
# Checkout a socket for reading (i.e., a secondary node).
|
||||
def checkout_reader
|
||||
connect unless connected?
|
||||
|
||||
|
@ -629,23 +569,12 @@ module Mongo
|
|||
|
||||
private
|
||||
|
||||
# Pick a node randomly from the set of possible secondaries.
|
||||
def pick_secondary_for_read
|
||||
if (size = @secondary_pools.size) > 0
|
||||
@read_pool = @secondary_pools[rand(size)]
|
||||
end
|
||||
end
|
||||
|
||||
# If a ConnectionFailure is raised, this method will be called
|
||||
# to close the connection and reset connection values.
|
||||
# TODO: evaluate whether this method is actually necessary
|
||||
def reset_connection
|
||||
close
|
||||
@primary = nil
|
||||
@secondaries = []
|
||||
@secondary_pools = []
|
||||
@arbiters = []
|
||||
@nodes_tried = []
|
||||
@nodes_to_try = []
|
||||
end
|
||||
|
||||
# Primary is defined as either a master node or a slave if
|
||||
|
@ -653,6 +582,7 @@ module Mongo
|
|||
#
|
||||
# If a primary node is discovered, we set the the @host and @port and
|
||||
# apply any saved authentication.
|
||||
# TODO: simplify
|
||||
def is_primary?(config)
|
||||
config && (config['ismaster'] == 1 || config['ismaster'] == true) || !@replica_set && @slave_ok
|
||||
end
|
||||
|
@ -665,18 +595,17 @@ module Mongo
|
|||
|
||||
config = self['admin'].command({:ismaster => 1}, :sock => socket)
|
||||
|
||||
check_set_name(config, socket)
|
||||
rescue OperationFailure, SocketError, SystemCallError, IOError => ex
|
||||
close unless connected?
|
||||
close# unless connected?
|
||||
ensure
|
||||
@nodes_tried << node
|
||||
if config
|
||||
update_node_list(config['hosts']) if config['hosts']
|
||||
# @nodes_tried << node
|
||||
# if config
|
||||
# update_node_list(config['hosts']) if config['hosts']
|
||||
|
||||
if config['msg'] && @logger
|
||||
@logger.warn("MONGODB #{config['msg']}")
|
||||
end
|
||||
end
|
||||
# if config['msg'] && @logger
|
||||
# @logger.warn("MONGODB #{config['msg']}")
|
||||
# end
|
||||
# end
|
||||
|
||||
socket.close if socket
|
||||
end
|
||||
|
@ -684,21 +613,6 @@ module Mongo
|
|||
config
|
||||
end
|
||||
|
||||
# Make sure that we're connected to the expected replica set.
|
||||
def check_set_name(config, socket)
|
||||
if @replica_set_name
|
||||
config = self['admin'].command({:replSetGetStatus => 1},
|
||||
:sock => socket, :check_response => false)
|
||||
|
||||
if !Mongo::Support.ok?(config)
|
||||
raise ReplicaSetConnectionError, config['errmsg']
|
||||
elsif config['set'] != @replica_set_name
|
||||
raise ReplicaSetConnectionError,
|
||||
"Attempting to connect to replica set '#{config['set']}' but expected '#{@replica_set_name}'"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Set the specified node as primary, and
|
||||
# apply any saved authentication credentials.
|
||||
def set_primary(node)
|
||||
|
@ -708,45 +622,6 @@ module Mongo
|
|||
apply_saved_authentication
|
||||
end
|
||||
|
||||
# Determines what kind of node we have and caches its host
|
||||
# and port so that users can easily connect manually.
|
||||
def set_auxillary(node, config)
|
||||
if config
|
||||
if config['secondary']
|
||||
host, port = *node
|
||||
@secondaries << node unless @secondaries.include?(node)
|
||||
@secondary_pools << Pool.new(self, host, port, :size => @pool_size, :timeout => @timeout)
|
||||
elsif config['arbiterOnly']
|
||||
@arbiters << node unless @arbiters.include?(node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Update the list of known nodes. Only applies to replica sets,
|
||||
# where the response to the ismaster command will return a list
|
||||
# of known hosts.
|
||||
#
|
||||
# @param hosts [Array] a list of hosts, specified as string-encoded
|
||||
# host-port values. Example: ["myserver-1.org:27017", "myserver-1.org:27017"]
|
||||
#
|
||||
# @return [Array] the updated list of nodes
|
||||
def update_node_list(hosts)
|
||||
new_nodes = hosts.map do |host|
|
||||
if !host.respond_to?(:split)
|
||||
warn "Could not parse host #{host.inspect}."
|
||||
next
|
||||
end
|
||||
|
||||
host, port = host.split(':')
|
||||
[host, port.to_i]
|
||||
end
|
||||
|
||||
# Replace the list of seed nodes with the canonical list.
|
||||
@nodes = new_nodes.clone
|
||||
|
||||
@nodes_to_try = new_nodes - @nodes_tried
|
||||
end
|
||||
|
||||
def receive(sock)
|
||||
receive_and_discard_header(sock)
|
||||
number_received, cursor_id = receive_response_header(sock)
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
# encoding: UTF-8
|
||||
|
||||
# --
|
||||
# Copyright (C) 2008-2010 10gen Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ++
|
||||
|
||||
module Mongo
|
||||
|
||||
# Instantiates and manages connections to MongoDB.
|
||||
class ReplSetConnection
|
||||
attr_reader :nodes, :secondaries, :arbiters, :read_pool, :secondary_pools
|
||||
|
||||
def initialize(*args)
|
||||
|
||||
if args.last.is_a?(Hash)
|
||||
options = args.pop
|
||||
end
|
||||
|
||||
@nodes = args
|
||||
|
||||
# Replica set name
|
||||
@replica_set_name = options[:rs_name]
|
||||
|
||||
# Cache the various node types when connecting to a replica set.
|
||||
@secondaries = []
|
||||
@arbiters = []
|
||||
|
||||
# Connection pools for each secondary node
|
||||
@secondary_pools = []
|
||||
@read_pool = nil
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
# Create a new socket and attempt to connect to master.
|
||||
# If successful, sets host and port to master and returns the socket.
|
||||
#
|
||||
# If connecting to a replica set, this method will replace the
|
||||
# initially-provided seed list with any nodes known to the set.
|
||||
#
|
||||
# @raise [ConnectionFailure] if unable to connect to any host or port.
|
||||
def connect
|
||||
reset_connection
|
||||
@nodes_to_try = @nodes.clone
|
||||
|
||||
while connecting?
|
||||
node = @nodes_to_try.shift
|
||||
config = check_is_master(node)
|
||||
|
||||
if is_primary?(config)
|
||||
set_primary(node)
|
||||
else
|
||||
set_auxillary(node, config)
|
||||
end
|
||||
end
|
||||
|
||||
pick_secondary_for_read if @read_secondary
|
||||
|
||||
raise ConnectionFailure, "failed to connect to any given host:port" unless connected?
|
||||
end
|
||||
|
||||
def connecting?
|
||||
@nodes_to_try.length > 0
|
||||
end
|
||||
|
||||
# Close the connection to the database.
|
||||
def close
|
||||
super
|
||||
@read_pool = nil
|
||||
@secondary_pools.each do |pool|
|
||||
pool.close
|
||||
end
|
||||
end
|
||||
|
||||
# If a ConnectionFailure is raised, this method will be called
|
||||
# to close the connection and reset connection values.
|
||||
def reset_connection
|
||||
super
|
||||
@secondaries = []
|
||||
@secondary_pools = []
|
||||
@arbiters = []
|
||||
@nodes_tried = []
|
||||
@nodes_to_try = []
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_is_master(node)
|
||||
begin
|
||||
host, port = *node
|
||||
socket = TCPSocket.new(host, port)
|
||||
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
||||
|
||||
config = self['admin'].command({:ismaster => 1}, :sock => socket)
|
||||
|
||||
check_set_name(config, socket)
|
||||
rescue OperationFailure, SocketError, SystemCallError, IOError => ex
|
||||
close unless connected?
|
||||
ensure
|
||||
@nodes_tried << node
|
||||
if config
|
||||
update_node_list(config['hosts']) if config['hosts']
|
||||
|
||||
if config['msg'] && @logger
|
||||
@logger.warn("MONGODB #{config['msg']}")
|
||||
end
|
||||
end
|
||||
|
||||
socket.close if socket
|
||||
end
|
||||
|
||||
config
|
||||
end
|
||||
|
||||
|
||||
|
||||
# Pick a node randomly from the set of possible secondaries.
|
||||
def pick_secondary_for_read
|
||||
if (size = @secondary_pools.size) > 0
|
||||
@read_pool = @secondary_pools[rand(size)]
|
||||
end
|
||||
end
|
||||
|
||||
# Make sure that we're connected to the expected replica set.
|
||||
def check_set_name(config, socket)
|
||||
if @replica_set_name
|
||||
config = self['admin'].command({:replSetGetStatus => 1},
|
||||
:sock => socket, :check_response => false)
|
||||
|
||||
if !Mongo::Support.ok?(config)
|
||||
raise ReplicaSetConnectionError, config['errmsg']
|
||||
elsif config['set'] != @replica_set_name
|
||||
raise ReplicaSetConnectionError,
|
||||
"Attempting to connect to replica set '#{config['set']}' but expected '#{@replica_set_name}'"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Determines what kind of node we have and caches its host
|
||||
# and port so that users can easily connect manually.
|
||||
def set_auxillary(node, config)
|
||||
if config
|
||||
if config['secondary']
|
||||
host, port = *node
|
||||
@secondaries << node unless @secondaries.include?(node)
|
||||
@secondary_pools << Pool.new(self, host, port, :size => @pool_size, :timeout => @timeout)
|
||||
elsif config['arbiterOnly']
|
||||
@arbiters << node unless @arbiters.include?(node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Update the list of known nodes. Only applies to replica sets,
|
||||
# where the response to the ismaster command will return a list
|
||||
# of known hosts.
|
||||
#
|
||||
# @param hosts [Array] a list of hosts, specified as string-encoded
|
||||
# host-port values. Example: ["myserver-1.org:27017", "myserver-1.org:27017"]
|
||||
#
|
||||
# @return [Array] the updated list of nodes
|
||||
def update_node_list(hosts)
|
||||
new_nodes = hosts.map do |host|
|
||||
if !host.respond_to?(:split)
|
||||
warn "Could not parse host #{host.inspect}."
|
||||
next
|
||||
end
|
||||
|
||||
host, port = host.split(':')
|
||||
[host, port.to_i]
|
||||
end
|
||||
|
||||
# Replace the list of seed nodes with the canonical list.
|
||||
@nodes = new_nodes.clone
|
||||
|
||||
@nodes_to_try = new_nodes - @nodes_tried
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,71 @@
|
|||
# encoding: UTF-8
|
||||
|
||||
# --
|
||||
# Copyright (C) 2008-2010 10gen Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ++
|
||||
|
||||
module Mongo
|
||||
module URIParser
|
||||
|
||||
DEFAULT_PORT = 27017
|
||||
MONGODB_URI_MATCHER = /(([-_.\w\d]+):([-_\w\d]+)@)?([-.\w\d]+)(:([\w\d]+))?(\/([-\d\w]+))?/
|
||||
MONGODB_URI_SPEC = "mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/database]"
|
||||
|
||||
extend self
|
||||
|
||||
# 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.
|
||||
#
|
||||
# @private
|
||||
def parse(string)
|
||||
if string =~ /^mongodb:\/\//
|
||||
string = string[10..-1]
|
||||
else
|
||||
raise MongoArgumentError, "MongoDB URI must match this spec: #{MONGODB_URI_SPEC}"
|
||||
end
|
||||
|
||||
nodes = []
|
||||
auths = []
|
||||
specs = string.split(',')
|
||||
specs.each do |spec|
|
||||
matches = MONGODB_URI_MATCHER.match(spec)
|
||||
if !matches
|
||||
raise MongoArgumentError, "MongoDB URI must match this spec: #{MONGODB_URI_SPEC}"
|
||||
end
|
||||
|
||||
uname = matches[2]
|
||||
pwd = matches[3]
|
||||
host = matches[4]
|
||||
port = matches[6] || DEFAULT_PORT
|
||||
if !(port.to_s =~ /^\d+$/)
|
||||
raise MongoArgumentError, "Invalid port #{port}; port must be specified as digits."
|
||||
end
|
||||
port = port.to_i
|
||||
db = matches[8]
|
||||
|
||||
if uname && pwd && db
|
||||
auths << {'db_name' => db, 'username' => uname, 'password' => pwd}
|
||||
elsif uname || pwd || db
|
||||
raise MongoArgumentError, "MongoDB URI must include all three of username, password, " +
|
||||
"and db if any one of these is specified."
|
||||
end
|
||||
|
||||
nodes << [host, port]
|
||||
end
|
||||
|
||||
[nodes, auths]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -26,7 +26,7 @@ unless defined? MONGO_TEST_DB
|
|||
end
|
||||
|
||||
unless defined? TEST_PORT
|
||||
TEST_PORT = ENV['MONGO_RUBY_DRIVER_PORT'].to_i || Connection::DEFAULT_PORT
|
||||
TEST_PORT = ENV['MONGO_RUBY_DRIVER_PORT'] ? ENV['MONGO_RUBY_DRIVER_PORT'].to_i : Mongo::Connection::DEFAULT_PORT
|
||||
end
|
||||
|
||||
unless defined? TEST_HOST
|
||||
|
|
|
@ -41,103 +41,21 @@ class ConnectionTest < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
context "connecting to a replica set" do
|
||||
setup do
|
||||
TCPSocket.stubs(:new).returns(new_mock_socket('localhost', 27017))
|
||||
@conn = Connection.multi([['localhost', 27017]], :connect => false, :read_secondary => true)
|
||||
|
||||
admin_db = new_mock_db
|
||||
@hosts = ['localhost:27018', 'localhost:27019', 'localhost:27020']
|
||||
|
||||
admin_db.stubs(:command).returns({'ok' => 1, 'ismaster' => 1, 'hosts' => @hosts}).
|
||||
then.returns({'ok' => 1, 'ismaster' => 0, 'hosts' => @hosts, 'secondary' => 1}).
|
||||
then.returns({'ok' => 1, 'ismaster' => 0, 'hosts' => @hosts, 'secondary' => 1}).
|
||||
then.returns({'ok' => 1, 'ismaster' => 0, 'arbiterOnly' => 1})
|
||||
|
||||
@conn.stubs(:[]).with('admin').returns(admin_db)
|
||||
@conn.connect
|
||||
end
|
||||
|
||||
should "store the hosts returned from the ismaster command" do
|
||||
assert_equal 'localhost', @conn.primary_pool.host
|
||||
assert_equal 27017, @conn.primary_pool.port
|
||||
|
||||
assert_equal 'localhost', @conn.secondary_pools[0].host
|
||||
assert_equal 27018, @conn.secondary_pools[0].port
|
||||
|
||||
assert_equal 'localhost', @conn.secondary_pools[1].host
|
||||
assert_equal 27019, @conn.secondary_pools[1].port
|
||||
|
||||
assert_equal 2, @conn.secondary_pools.length
|
||||
end
|
||||
end
|
||||
|
||||
context "connecting to a replica set and providing seed nodes" do
|
||||
setup do
|
||||
TCPSocket.stubs(:new).returns(new_mock_socket)
|
||||
@conn = Connection.multi([['localhost', 27017], ['localhost', 27019]], :connect => false)
|
||||
|
||||
admin_db = new_mock_db
|
||||
@hosts = ['localhost:27017', 'localhost:27018', 'localhost:27019']
|
||||
admin_db.stubs(:command).returns({'ok' => 1, 'ismaster' => 1, 'hosts' => @hosts})
|
||||
@conn.stubs(:[]).with('admin').returns(admin_db)
|
||||
@conn.connect
|
||||
end
|
||||
|
||||
should "not store any hosts redundantly" do
|
||||
end
|
||||
end
|
||||
|
||||
context "initializing a paired connection" do
|
||||
should "require left and right nodes" do
|
||||
assert_raise MongoArgumentError do
|
||||
Connection.multi(['localhost', 27018], :connect => false)
|
||||
end
|
||||
|
||||
assert_raise MongoArgumentError do
|
||||
Connection.multi(['localhost', 27018], :connect => false)
|
||||
end
|
||||
end
|
||||
|
||||
should "store both nodes" do
|
||||
@conn = Connection.multi([['localhost', 27017], ['localhost', 27018]], :connect => false)
|
||||
|
||||
assert_equal ['localhost', 27017], @conn.nodes[0]
|
||||
assert_equal ['localhost', 27018], @conn.nodes[1]
|
||||
end
|
||||
end
|
||||
|
||||
context "initializing with a mongodb uri" do
|
||||
should "parse a simple uri" do
|
||||
@conn = Connection.from_uri("mongodb://localhost", :connect => false)
|
||||
assert_equal ['localhost', 27017], @conn.nodes[0]
|
||||
assert_equal ['localhost', 27017], @conn.host_to_try
|
||||
end
|
||||
|
||||
should "allow a complex host names" do
|
||||
host_name = "foo.bar-12345.org"
|
||||
@conn = Connection.from_uri("mongodb://#{host_name}", :connect => false)
|
||||
assert_equal [host_name, 27017], @conn.nodes[0]
|
||||
end
|
||||
|
||||
should "parse a uri specifying multiple nodes" do
|
||||
@conn = Connection.from_uri("mongodb://localhost:27017,mydb.com:27018", :connect => false)
|
||||
assert_equal ['localhost', 27017], @conn.nodes[0]
|
||||
assert_equal ['mydb.com', 27018], @conn.nodes[1]
|
||||
end
|
||||
|
||||
should "parse a uri specifying multiple nodes with auth" do
|
||||
@conn = Connection.from_uri("mongodb://kyle:s3cr3t@localhost:27017/app,mickey:m0u5e@mydb.com:27018/dsny", :connect => false)
|
||||
assert_equal ['localhost', 27017], @conn.nodes[0]
|
||||
assert_equal ['mydb.com', 27018], @conn.nodes[1]
|
||||
auth_hash = {'username' => 'kyle', 'password' => 's3cr3t', 'db_name' => 'app'}
|
||||
assert_equal auth_hash, @conn.auths[0]
|
||||
auth_hash = {'username' => 'mickey', 'password' => 'm0u5e', 'db_name' => 'dsny'}
|
||||
assert_equal auth_hash, @conn.auths[1]
|
||||
assert_equal [host_name, 27017], @conn.host_to_try
|
||||
end
|
||||
|
||||
should "parse a uri with a hyphen & underscore in the username or password" do
|
||||
@conn = Connection.from_uri("mongodb://hyphen-user_name:p-s_s@localhost:27017/db", :connect => false)
|
||||
assert_equal ['localhost', 27017], @conn.nodes[0]
|
||||
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
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
require './test/test_helper'
|
||||
include Mongo
|
||||
|
||||
#class ConnectionTest < Test::Unit::TestCase
|
||||
# context "Initialization: " do
|
||||
# setup do
|
||||
# def new_mock_socket(host='localhost', port=27017)
|
||||
# socket = Object.new
|
||||
# socket.stubs(:setsockopt).with(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
||||
# socket.stubs(:close)
|
||||
# socket
|
||||
# end
|
||||
#
|
||||
# def new_mock_db
|
||||
# db = Object.new
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# context "given a single node" do
|
||||
# setup do
|
||||
# @conn = Connection.new('localhost', 27017, :connect => false)
|
||||
# TCPSocket.stubs(:new).returns(new_mock_socket)
|
||||
#
|
||||
# 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 "set localhost and port to master" do
|
||||
# assert_equal 'localhost', @conn.primary_pool.host
|
||||
# assert_equal 27017, @conn.primary_pool.port
|
||||
# end
|
||||
#
|
||||
# should "set connection pool to 1" do
|
||||
# assert_equal 1, @conn.primary_pool.size
|
||||
# end
|
||||
#
|
||||
# should "default slave_ok to false" do
|
||||
# assert !@conn.slave_ok?
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# context "connecting to a replica set" do
|
||||
# setup do
|
||||
# TCPSocket.stubs(:new).returns(new_mock_socket('localhost', 27017))
|
||||
# @conn = Connection.multi([['localhost', 27017]], :connect => false, :read_secondary => true)
|
||||
#
|
||||
# admin_db = new_mock_db
|
||||
# @hosts = ['localhost:27018', 'localhost:27019', 'localhost:27020']
|
||||
#
|
||||
# admin_db.stubs(:command).returns({'ok' => 1, 'ismaster' => 1, 'hosts' => @hosts}).
|
||||
# then.returns({'ok' => 1, 'ismaster' => 0, 'hosts' => @hosts, 'secondary' => 1}).
|
||||
# then.returns({'ok' => 1, 'ismaster' => 0, 'hosts' => @hosts, 'secondary' => 1}).
|
||||
# then.returns({'ok' => 1, 'ismaster' => 0, 'arbiterOnly' => 1})
|
||||
#
|
||||
# @conn.stubs(:[]).with('admin').returns(admin_db)
|
||||
# @conn.connect
|
||||
# end
|
||||
#
|
||||
# should "store the hosts returned from the ismaster command" do
|
||||
# assert_equal 'localhost', @conn.primary_pool.host
|
||||
# assert_equal 27017, @conn.primary_pool.port
|
||||
#
|
||||
# assert_equal 'localhost', @conn.secondary_pools[0].host
|
||||
# assert_equal 27018, @conn.secondary_pools[0].port
|
||||
#
|
||||
# assert_equal 'localhost', @conn.secondary_pools[1].host
|
||||
# assert_equal 27019, @conn.secondary_pools[1].port
|
||||
#
|
||||
# assert_equal 2, @conn.secondary_pools.length
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# context "connecting to a replica set and providing seed nodes" do
|
||||
# setup do
|
||||
# TCPSocket.stubs(:new).returns(new_mock_socket)
|
||||
# @conn = Connection.multi([['localhost', 27017], ['localhost', 27019]], :connect => false)
|
||||
#
|
||||
# admin_db = new_mock_db
|
||||
# @hosts = ['localhost:27017', 'localhost:27018', 'localhost:27019']
|
||||
# admin_db.stubs(:command).returns({'ok' => 1, 'ismaster' => 1, 'hosts' => @hosts})
|
||||
# @conn.stubs(:[]).with('admin').returns(admin_db)
|
||||
# @conn.connect
|
||||
# end
|
||||
#
|
||||
# should "not store any hosts redundantly" do
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# context "initializing a paired connection" do
|
||||
# should "require left and right nodes" do
|
||||
# assert_raise MongoArgumentError do
|
||||
# Connection.multi(['localhost', 27018], :connect => false)
|
||||
# end
|
||||
#
|
||||
# assert_raise MongoArgumentError do
|
||||
# Connection.multi(['localhost', 27018], :connect => false)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# should "store both nodes" do
|
||||
# @conn = Connection.multi([['localhost', 27017], ['localhost', 27018]], :connect => false)
|
||||
#
|
||||
# assert_equal ['localhost', 27017], @conn.nodes[0]
|
||||
# assert_equal ['localhost', 27018], @conn.nodes[1]
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# context "initializing with a mongodb uri" do
|
||||
# should "parse a simple uri" do
|
||||
# @conn = Connection.from_uri("mongodb://localhost", :connect => false)
|
||||
# assert_equal ['localhost', 27017], @conn.primary
|
||||
# end
|
||||
#
|
||||
# should "allow a complex host names" do
|
||||
# host_name = "foo.bar-12345.org"
|
||||
# @conn = Connection.from_uri("mongodb://#{host_name}", :connect => false)
|
||||
# assert_equal [host_name, 27017], @conn.primary
|
||||
# end
|
||||
#
|
||||
# should "parse a uri specifying multiple nodes" do
|
||||
# #@conn = Connection.from_uri("mongodb://localhost:27017,mydb.com:27018", :connect => false)
|
||||
# #assert_equal ['localhost', 27017], @conn.nodes[0]
|
||||
# #assert_equal ['mydb.com', 27018], @conn.nodes[1]
|
||||
# end
|
||||
#
|
||||
# should "parse a uri specifying multiple nodes with auth" do
|
||||
# #@conn = Connection.from_uri("mongodb://kyle:s3cr3t@localhost:27017/app,mickey:m0u5e@mydb.com:27018/dsny", :connect => false)
|
||||
# #assert_equal ['localhost', 27017], @conn.nodes[0]
|
||||
# #assert_equal ['mydb.com', 27018], @conn.nodes[1]
|
||||
# #auth_hash = {'username' => 'kyle', 'password' => 's3cr3t', 'db_name' => 'app'}
|
||||
# #assert_equal auth_hash, @conn.auths[0]
|
||||
# #auth_hash = {'username' => 'mickey', 'password' => 'm0u5e', 'db_name' => 'dsny'}
|
||||
# #assert_equal auth_hash, @conn.auths[1]
|
||||
# end
|
||||
#
|
||||
# should "parse a uri with a hyphen & underscore in the username or password" do
|
||||
# @conn = Connection.from_uri("mongodb://hyphen-user_name:p-s_s@localhost:27017/db", :connect => false)
|
||||
# assert_equal ['localhost', 27017], @conn.nodes[0]
|
||||
# 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)
|
||||
# @conn = Connection.from_uri("mongodb://localhost", :connect => false)
|
||||
#
|
||||
# admin_db = new_mock_db
|
||||
# admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1})
|
||||
# @conn.expects(:[]).with('admin').returns(admin_db)
|
||||
# @conn.expects(:apply_saved_authentication)
|
||||
# @conn.connect
|
||||
# end
|
||||
#
|
||||
# should "raise an error on invalid uris" do
|
||||
# assert_raise MongoArgumentError do
|
||||
# Connection.from_uri("mongo://localhost", :connect => false)
|
||||
# end
|
||||
#
|
||||
# assert_raise MongoArgumentError do
|
||||
# Connection.from_uri("mongodb://localhost:abc", :connect => false)
|
||||
# end
|
||||
#
|
||||
# assert_raise MongoArgumentError do
|
||||
# Connection.from_uri("mongodb://localhost:27017, my.db.com:27018, ", :connect => false)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# should "require all of username, password, and database if any one is specified" do
|
||||
# assert_raise MongoArgumentError do
|
||||
# Connection.from_uri("mongodb://localhost/db", :connect => false)
|
||||
# end
|
||||
#
|
||||
# assert_raise MongoArgumentError do
|
||||
# Connection.from_uri("mongodb://kyle:password@localhost", :connect => false)
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#end
|
Loading…
Reference in New Issue