diff --git a/.gitignore b/.gitignore
index 22df448ccf..65424f0e99 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
docs
.yardoc
+coverage
*.gem
nbproject
*.bundle
diff --git a/.travis.yml b/.travis.yml
index 5151313a1e..016a755b4a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,7 +12,7 @@ script: bundle exec rake test:ruby
notifications:
email: false
- #TODO: flowdock: [api token]
+ flowdock: 1da4416b8ff98d1880986472428b1b1b
services:
- mongodb
diff --git a/Gemfile b/Gemfile
index 25c048faf6..23ddf41ba6 100644
--- a/Gemfile
+++ b/Gemfile
@@ -14,6 +14,7 @@ group :deploy do
end
group :testing do
+ gem 'simplecov'
gem 'test-unit'
gem 'mocha', '0.12.7'
gem 'shoulda'
diff --git a/README.md b/README.md
index e0c70c7c0b..b529e4173a 100644
--- a/README.md
+++ b/README.md
@@ -45,7 +45,7 @@ Here's a quick code sample. Again, see the [MongoDB Ruby Tutorial](https://githu
require 'rubygems'
require 'mongo'
-@client = Mongo::Client.new('localhost', 27017, :safe => true)
+@client = Mongo::Client.new('localhost', 27017)
@db = @client['sample-db']
@coll = @db['test']
diff --git a/bin/mongo_console b/bin/mongo_console
index b3953c4e3c..0549f0dece 100755
--- a/bin/mongo_console
+++ b/bin/mongo_console
@@ -14,7 +14,7 @@ port = org_argv[1] || ENV['MONGO_RUBY_DRIVER_PORT'] || Client::DEFAULT_PORT
dbnm = org_argv[2] || ENV['MONGO_RUBY_DRIVER_DB'] || 'ruby-mongo-console'
puts "Connecting to #{host}:#{port} (CLIENT) on with database #{dbnm} (DB)"
-CLIENT = Client.new(host, port, :safe => true)
+CLIENT = Client.new(host, port)
DB = CLIENT.db(dbnm)
puts "Starting IRB session..."
diff --git a/examples/admin.rb b/examples/admin.rb
index 10b6c3bc0f..8e11f32fac 100644
--- a/examples/admin.rb
+++ b/examples/admin.rb
@@ -9,7 +9,7 @@
port = ENV['MONGO_RUBY_DRIVER_PORT'] || Client::DEFAULT_PORT
puts "Connecting to #{host}:#{port}"
-client = Mongo::Client.new(host, port, :safe => true)
+client = Mongo::Client.new(host, port)
db = client.db('ruby-mongo-examples')
coll = db.create_collection('test')
diff --git a/examples/capped.rb b/examples/capped.rb
index be832a7345..c17809e4b3 100644
--- a/examples/capped.rb
+++ b/examples/capped.rb
@@ -7,7 +7,7 @@
port = ENV['MONGO_RUBY_DRIVER_PORT'] || Client::DEFAULT_PORT
puts "Connecting to #{host}:#{port}"
-db = Client.new(host, port, :safe => true).db('ruby-mongo-examples')
+db = Client.new(host, port).db('ruby-mongo-examples')
db.drop_collection('test')
# A capped collection has a max size and, optionally, a max number of records.
diff --git a/examples/cursor.rb b/examples/cursor.rb
index 59bdb101db..e82af392ab 100644
--- a/examples/cursor.rb
+++ b/examples/cursor.rb
@@ -9,7 +9,7 @@
port = ENV['MONGO_RUBY_DRIVER_PORT'] || Client::DEFAULT_PORT
puts "Connecting to #{host}:#{port}"
-db = Client.new(host, port, :safe => true).db('ruby-mongo-examples')
+db = Client.new(host, port).db('ruby-mongo-examples')
coll = db.collection('test')
# Erase all records from collection, if any
diff --git a/examples/gridfs.rb b/examples/gridfs.rb
index 4b1eb5f4c1..13b2768983 100644
--- a/examples/gridfs.rb
+++ b/examples/gridfs.rb
@@ -10,7 +10,7 @@ def assert
port = ENV['MONGO_RUBY_DRIVER_PORT'] || Client::DEFAULT_PORT
puts "Connecting to #{host}:#{port}"
-db = Client.new(host, port, :safe => true).db('ruby-mongo-examples')
+db = Client.new(host, port).db('ruby-mongo-examples')
data = "hello, world!"
diff --git a/examples/index_test.rb b/examples/index_test.rb
index 5a8795f98e..ab5612650f 100644
--- a/examples/index_test.rb
+++ b/examples/index_test.rb
@@ -8,7 +8,7 @@
port = ENV['MONGO_RUBY_DRIVER_PORT'] || Client::DEFAULT_PORT
puts ">> Connecting to #{host}:#{port}"
-db = Client.new(host, port, :safe => true).db('ruby-mongo-index_test')
+db = Client.new(host, port).db('ruby-mongo-index_test')
class Exception
def errmsg
diff --git a/examples/info.rb b/examples/info.rb
index 8393f656a1..a0b6b53516 100644
--- a/examples/info.rb
+++ b/examples/info.rb
@@ -8,7 +8,7 @@
port = ENV['MONGO_RUBY_DRIVER_PORT'] || Client::DEFAULT_PORT
puts "Connecting to #{host}:#{port}"
-db = Client.new(host, port, :safe => true).db('ruby-mongo-examples')
+db = Client.new(host, port).db('ruby-mongo-examples')
coll = db.collection('test')
# Erase all records from collection, if any
diff --git a/examples/queries.rb b/examples/queries.rb
index 5e185a0ee1..3c1ce6c222 100644
--- a/examples/queries.rb
+++ b/examples/queries.rb
@@ -9,7 +9,7 @@
port = ENV['MONGO_RUBY_DRIVER_PORT'] || Client::DEFAULT_PORT
puts "Connecting to #{host}:#{port}"
-db = Client.new(host, port, :safe => true).db('ruby-mongo-examples')
+db = Client.new(host, port).db('ruby-mongo-examples')
coll = db.collection('test')
# Remove all records, if any
diff --git a/examples/simple.rb b/examples/simple.rb
index f1de48197c..8dfdbb921f 100644
--- a/examples/simple.rb
+++ b/examples/simple.rb
@@ -9,7 +9,7 @@
port = ENV['MONGO_RUBY_DRIVER_PORT'] || Client::DEFAULT_PORT
puts "Connecting to #{host}:#{port}"
-db = Client.new(host, port, :safe => true).db('ruby-mongo-examples')
+db = Client.new(host, port).db('ruby-mongo-examples')
coll = db.collection('test')
# Erase all records from collection, if any
diff --git a/examples/strict.rb b/examples/strict.rb
index c58da4be73..76a7610fa3 100644
--- a/examples/strict.rb
+++ b/examples/strict.rb
@@ -8,7 +8,7 @@
port = ENV['MONGO_RUBY_DRIVER_PORT'] || Client::DEFAULT_PORT
puts "Connecting to #{host}:#{port}"
-db = Client.new(host, port, :safe => true).db('ruby-mongo-examples')
+db = Client.new(host, port).db('ruby-mongo-examples')
db.drop_collection('does-not-exist')
db.create_collection('test')
diff --git a/examples/types.rb b/examples/types.rb
index d09d8f6a24..a8ee1ce2a5 100644
--- a/examples/types.rb
+++ b/examples/types.rb
@@ -9,7 +9,7 @@
port = ENV['MONGO_RUBY_DRIVER_PORT'] || Client::DEFAULT_PORT
puts "Connecting to #{host}:#{port}"
-db = Client.new(host, port, :safe => true).db('ruby-mongo-examples')
+db = Client.new(host, port).db('ruby-mongo-examples')
coll = db.collection('test')
# Remove all records, if any
diff --git a/examples/web/thin/load.rb b/examples/web/thin/load.rb
index fbe5ca27f1..9f882d4da1 100644
--- a/examples/web/thin/load.rb
+++ b/examples/web/thin/load.rb
@@ -1,7 +1,7 @@
require File.join(File.dirname(__FILE__), '..', '..', '..', 'lib', 'mongo')
require 'logger'
-$con = Mongo::ReplSetClient.new(['localhost:30000', 'localhost:30001'], :safe => true, :read => :secondary, :refresh_mode => :sync, :refresh_interval => 30)
+$con = Mongo::ReplSetClient.new(['localhost:30000', 'localhost:30001'], :read => :secondary, :refresh_mode => :sync, :refresh_interval => 30)
$db = $con['foo']
class Load < Sinatra::Base
diff --git a/examples/web/unicorn/load.rb b/examples/web/unicorn/load.rb
index 0b675876b0..4e93cff4a6 100644
--- a/examples/web/unicorn/load.rb
+++ b/examples/web/unicorn/load.rb
@@ -1,6 +1,6 @@
require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'mongo')
-$client = Mongo::Client.new('localhost', 27017, :safe => true)
+$client = Mongo::Client.new('localhost', 27017)
$db = $client['foo']
class Load < Sinatra::Base
diff --git a/examples/web/unicorn/unicorn.rb.template b/examples/web/unicorn/unicorn.rb.template
index d832838652..6c0b2d162c 100644
--- a/examples/web/unicorn/unicorn.rb.template
+++ b/examples/web/unicorn/unicorn.rb.template
@@ -23,7 +23,7 @@ stdout_path "#{@dir}log/unicorn.stdout.log"
# NOTE: You need this when using forking web servers!
after_fork do |server, worker|
$client.close if $client
- $client = Mongo::Client.new('localhost', 27017, :safe => true)
+ $client = Mongo::Client.new('localhost', 27017)
$db = $client['foo']
STDERR << "FORKED #{server} #{worker}"
end
diff --git a/lib/bson/version.rb b/lib/bson/version.rb
deleted file mode 100644
index 8257562d8d..0000000000
--- a/lib/bson/version.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-module BSON
- VERSION = "1.7.1"
-end
diff --git a/lib/mongo.rb b/lib/mongo.rb
index 6dbc0a0b7c..7a266e9ab4 100644
--- a/lib/mongo.rb
+++ b/lib/mongo.rb
@@ -52,6 +52,7 @@ module Constants
require 'mongo/util/conversions'
require 'mongo/util/support'
+require 'mongo/util/write_concern'
require 'mongo/util/core_ext'
require 'mongo/util/logging'
require 'mongo/util/node'
@@ -63,15 +64,16 @@ module Constants
require 'mongo/util/tcp_socket'
require 'mongo/util/uri_parser'
-require 'mongo/collection'
+
require 'mongo/networking'
require 'mongo/client'
require 'mongo/repl_set_client'
require 'mongo/sharded_client'
+require 'mongo/legacy'
+require 'mongo/collection'
require 'mongo/cursor'
require 'mongo/db'
require 'mongo/exceptions'
-require 'mongo/legacy'
require 'mongo/gridfs/grid_ext'
require 'mongo/gridfs/grid'
require 'mongo/gridfs/grid_io'
diff --git a/lib/mongo/client.rb b/lib/mongo/client.rb
index 9b27e98314..a7ffafa8cd 100644
--- a/lib/mongo/client.rb
+++ b/lib/mongo/client.rb
@@ -19,28 +19,44 @@
require 'set'
require 'socket'
require 'thread'
+
module Mongo
# Instantiates and manages self.connections to MongoDB.
class Client
include Mongo::Logging
include Mongo::Networking
+ include Mongo::WriteConcern
- TCPSocket = Mongo::TCPSocket
- Mutex = ::Mutex
- ConditionVariable = ::ConditionVariable
+ TCPSocket = Mongo::TCPSocket
+ Mutex = ::Mutex
+ ConditionVariable = ::ConditionVariable
- DEFAULT_HOST = 'localhost'
- DEFAULT_PORT = 27017
- DEFAULT_DB_NAME = 'test'
- GENERIC_OPTS = [:ssl, :auths, :pool_size, :pool_timeout, :timeout, :op_timeout, :connect_timeout, :safe, :logger, :connect]
- CONNECTION_OPTS = [:slave_ok]
+ DEFAULT_HOST = 'localhost'
+ DEFAULT_PORT = 27017
+ DEFAULT_DB_NAME = 'test'
+ GENERIC_OPTS = [:ssl, :auths, :logger, :connect]
+ TIMEOUT_OPTS = [:timeout, :op_timeout, :connect_timeout]
+ POOL_OPTS = [:pool_size, :pool_timeout]
+ WRITE_CONCERN_OPTS = [:w, :j, :fsync, :wtimeout]
+ CLIENT_ONLY_OPTS = [:slave_ok]
mongo_thread_local_accessor :connections
- attr_reader :logger, :size, :auths, :primary, :safe, :host_to_try,
- :pool_size, :connect_timeout, :pool_timeout,
- :primary_pool, :socket_class, :op_timeout, :tag_sets, :acceptable_latency
+ attr_reader :logger,
+ :size,
+ :auths,
+ :primary,
+ :write_concern,
+ :host_to_try,
+ :pool_size,
+ :connect_timeout,
+ :pool_timeout,
+ :primary_pool,
+ :socket_class,
+ :op_timeout,
+ :tag_sets,
+ :acceptable_latency
# Create a connection to single MongoDB instance.
#
@@ -59,10 +75,10 @@ class Client
# @param [String, Hash] host
# @param [Integer] port specify a port number here if only one host is being specified.
#
- # @option opts [Boolean, Hash] :safe (false) Set the default safe-mode options
- # propagated to DB objects instantiated off of this Client. This
- # default can be overridden upon instantiation of any DB by explicitly setting a :safe value
- # on initialization.
+ # @option opts [Hash] :w (1), :j (false), :wtimeout (false), :fsync (false) Set the default write concern
+ # options propagated to DB objects instantiated off of this Client.
+ # This default can be overridden upon instantiation of any DB by explicitly setting an options hash
+ # on initialization. It can also be overridden at instantiation of a collection or at the time of a write operation.
# @option opts [Boolean] :slave_ok (false) Must be set to +true+ when connecting
# to a single, slave node.
# @option opts [Logger, #debug] :logger (nil) A Logger instance for debugging driver ops. Note that
@@ -104,7 +120,7 @@ def initialize(host=nil, port=nil, opts={})
if parser.replicaset?
raise MongoArgumentError, "Mongo::Client.new called with no arguments, but ENV['MONGODB_URI'] implies a replica set."
end
- opts = parser.connection_options.merge! opts
+ opts.merge!(parser.connection_options)
@host_to_try = [parser.host, parser.port]
elsif host.is_a?(String) && (port || DEFAULT_PORT).respond_to?(:to_i)
@host_to_try = [host, (port || DEFAULT_PORT).to_i]
@@ -169,7 +185,8 @@ def self.multi(nodes, opts={})
# Initialize a connection to MongoDB using the MongoDB URI spec.
#
- # Since Client.new cannot be used with any ENV["MONGODB_URI"]
that has multiple hosts (implying a replicaset), you may use this when the type of your connection varies by environment and should be determined solely from ENV["MONGODB_URI"]
.
+ # Since Client.new cannot be used with any ENV["MONGODB_URI"]
that has multiple hosts (implying a replicaset),
+ # you may use this when the type of your connection varies by environment and should be determined solely from ENV["MONGODB_URI"]
.
#
# @param uri [String]
# A string of the format mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/database]
@@ -530,7 +547,11 @@ def checkin(socket)
protected
def valid_opts
- GENERIC_OPTS + CONNECTION_OPTS
+ GENERIC_OPTS +
+ CLIENT_ONLY_OPTS +
+ POOL_OPTS +
+ WRITE_CONCERN_OPTS +
+ TIMEOUT_OPTS
end
def check_opts(opts)
@@ -544,10 +565,10 @@ def check_opts(opts)
# Parse option hash
def setup(opts)
# slave_ok can be true only if one node is specified
- @slave_ok = opts[:slave_ok]
+ @slave_ok = opts.delete(:slave_ok)
# Determine whether to use SSL.
- @ssl = opts.fetch(:ssl, false)
+ @ssl = opts.delete(:ssl)
if @ssl
@socket_class = Mongo::SSLSocket
else
@@ -555,27 +576,27 @@ def setup(opts)
end
# Authentication objects
- @auths = opts.fetch(:auths, [])
+ @auths = opts.delete(:auths) || []
# Pool size and timeout.
- @pool_size = opts[:pool_size] || 1
+ @pool_size = opts.delete(:pool_size) || 1
if opts[:timeout]
warn "The :timeout option has been deprecated " +
"and will be removed in the 2.0 release. Use :pool_timeout instead."
end
- @pool_timeout = opts[:pool_timeout] || opts[:timeout] || 5.0
+ @pool_timeout = opts.delete(:pool_timeout) || opts.delete(:timeout) || 5.0
# Timeout on socket read operation.
- @op_timeout = opts[:op_timeout] || nil
+ @op_timeout = opts.delete(:op_timeout) || nil
# Timeout on socket connect.
- @connect_timeout = opts[:connect_timeout] || nil
-
- # Global safe option. This is false by default.
- @safe = opts[:safe] || false
+ @connect_timeout = opts.delete(:connect_timeout) || nil
@logger = opts.fetch(:logger, nil)
+ # Connection level write concern options.
+ @write_concern = get_write_concern(opts)
+
if @logger
write_logging_startup_message
end
diff --git a/lib/mongo/collection.rb b/lib/mongo/collection.rb
index 5fee9258af..387e2b7fa9 100644
--- a/lib/mongo/collection.rb
+++ b/lib/mongo/collection.rb
@@ -20,11 +20,18 @@ module Mongo
# A named collection of documents in a database.
class Collection
include Mongo::Logging
+ include Mongo::WriteConcern
- attr_reader :db, :name, :pk_factory, :hint, :safe
+ attr_reader :db,
+ :name,
+ :pk_factory,
+ :hint,
+ :write_concern
# Read Preference
- attr_accessor :read_preference, :tag_sets, :acceptable_latency
+ attr_accessor :read_preference,
+ :tag_sets,
+ :acceptable_latency
# Initialize a collection object.
#
@@ -34,10 +41,10 @@ class Collection
# @option opts [:create_pk] :pk (BSON::ObjectId) A primary key factory to use
# other than the default BSON::ObjectId.
#
- # @option opts [Boolean, Hash] :safe (false) Set the default safe-mode options
+ # @option opts [Hash] :w, :j, :wtimeout, :fsync Set the default write concern
# for +insert+, +update+, and +remove+ method called on this Collection instance. If no
- # value is provided, the default value set on this instance's DB will be used. This
- # default can be overridden for any invocation of +insert+, +update+, or +remove+.
+ # value is provided, the default values set on this instance's DB will be used. These option
+ # values can be overridden for any invocation of +insert+, +update+, or +remove+.
# @option options [:primary, :secondary] :read The default read preference for queries
# initiates from this connection object. If +:secondary+ is chosen, reads will be sent
# to one of the closest available secondary nodes. If a secondary node cannot be located, the
@@ -93,7 +100,7 @@ def initialize(name, db, opts={})
@cache_time = @db.cache_time
@cache = Hash.new(0)
unless pk_factory
- @safe = opts.fetch(:safe, @db.safe)
+ @write_concern = get_write_concern(opts, db)
if value = opts[:read]
Mongo::Support.validate_read_preference(value)
else
@@ -312,22 +319,24 @@ def find_one(spec_or_object_id=nil, opts={})
#
# @return [ObjectId] the _id of the saved document.
#
- # @option opts [Boolean, Hash] :safe (+false+)
- # run the operation in safe mode, which runs a +getlasterror+ command on the
- # database to report any assertion. In addition, a hash can be provided to
- # run an fsync and/or wait for replication (>= 1.5.1). Safe
- # options provided here will override any safe options set on this collection,
+ # @option opts [Hash] :w, :j, :wtimeout, :fsync Set the write concern for this operation.
+ # :w > 0 will run a +getlasterror+ command on the database to report any assertion.
+ # :j will confirm a write has been committed to the journal
+ # :wtimeout specifies how long to wait for write confirmation
+ # :fsync will confirm that a write has been fsynced
+ # options provided here will override any write concern options set on this collection,
# its database object, or the current connection. See the options
# for +DB#get_last_error+.
#
- # @raise [Mongo::OperationFailure] will be raised iff safe mode is enabled and the operation fails.
+ # @raise [Mongo::OperationFailure] will be raised iff :w > 0 and the operation fails.
def save(doc, opts={})
+ write_concern = get_write_concern(opts, self)
if doc.has_key?(:_id) || doc.has_key?('_id')
id = doc[:_id] || doc['_id']
- update({:_id => id}, doc, :upsert => true, :safe => opts.fetch(:safe, @safe))
+ update({:_id => id}, doc, :upsert => true, :write_concern => write_concern)
id
else
- insert(doc, :safe => opts.fetch(:safe, @safe))
+ insert(doc, write_concern)
end
end
@@ -343,33 +352,34 @@ def save(doc, opts={})
# 2nd, a list of invalid documents.
# Return this result format only when :collect_on_error is true.
#
- # @option opts [Boolean, Hash] :safe (+false+)
- # run the operation in safe mode, which runs a +getlasterror+ command on the
- # database to report any assertion. In addition, a hash can be provided to
- # run an fsync and/or wait for replication of the insert (>= 1.5.1). Safe
- # options provided here will override any safe options set on this collection,
+ # @option opts [Hash] :w, :j, :wtimeout, :fsync Set the write concern for this operation.
+ # :w > 0 will run a +getlasterror+ command on the database to report any assertion.
+ # :j will confirm a write has been committed to the journal
+ # :wtimeout specifies how long to wait for write confirmation
+ # :fsync will confirm that a write has been fsynced
+ # options provided here will override any write concern options set on this collection,
# its database object, or the current connection. See the options
# for +DB#get_last_error+.
#
# @option opts [Boolean] :continue_on_error (+false+) If true, then
# continue a bulk insert even if one of the documents inserted
# triggers a database assertion (as in a duplicate insert, for instance).
- # If not using safe mode, the list of ids returned will
+ # If not acknowledging writes, the list of ids returned will
# include the object ids of all documents attempted on insert, even
- # if some are rejected on error. When safe mode is
- # enabled, any error will raise an OperationFailure exception.
+ # if some are rejected on error. When acknowledging writes, any error will raise an
+ # OperationFailure exception.
# MongoDB v2.0+.
# @option opts [Boolean] :collect_on_error (+false+) if true, then
# collects invalid documents as an array. Note that this option changes the result format.
#
- # @raise [Mongo::OperationFailure] will be raised iff safe mode is enabled and the operation fails.
+ # @raise [Mongo::OperationFailure] will be raised iff :w > 0 and the operation fails.
#
# @core insert insert-instance_method
def insert(doc_or_docs, opts={})
doc_or_docs = [doc_or_docs] unless doc_or_docs.is_a?(Array)
doc_or_docs.collect! { |doc| @pk_factory.create_pk(doc) }
- safe = opts.fetch(:safe, @safe)
- result = insert_documents(doc_or_docs, @name, true, safe, opts)
+ write_concern = get_write_concern(opts, self)
+ result = insert_documents(doc_or_docs, @name, true, write_concern, opts)
result.size > 1 ? result : result.first
end
alias_method :<<, :insert
@@ -379,13 +389,14 @@ def insert(doc_or_docs, opts={})
# @param [Hash] selector
# If specified, only matching documents will be removed.
#
- # @option opts [Boolean, Hash] :safe (+false+)
- # run the operation in safe mode, which runs a +getlasterror+ command on the
- # database to report any assertion. In addition, a hash can be provided to
- # run an fsync and/or wait for replication of the remove (>= 1.5.1). Safe
- # options provided here will override any safe options set on this collection,
+ # @option opts [Hash] :w, :j, :wtimeout, :fsync Set the write concern for this operation.
+ # :w > 0 will run a +getlasterror+ command on the database to report any assertion.
+ # :j will confirm a write has been committed to the journal
+ # :wtimeout specifies how long to wait for write confirmation
+ # :fsync will confirm that a write has been fsynced
+ # options provided here will override any write concern options set on this collection,
# its database object, or the current connection. See the options
- # for +DB#get_last_error+.
+ # for +DB#get_last_error+.
#
# @example remove all documents from the 'users' collection:
# users.remove
@@ -394,23 +405,22 @@ def insert(doc_or_docs, opts={})
# @example remove only documents that have expired:
# users.remove({:expire => {"$lte" => Time.now}})
#
- # @return [Hash, true] Returns a Hash containing the last error object if running in safe mode.
+ # @return [Hash, true] Returns a Hash containing the last error object if acknowledging writes
# Otherwise, returns true.
#
- # @raise [Mongo::OperationFailure] will be raised iff safe mode is enabled and the operation fails.
+ # @raise [Mongo::OperationFailure] will be raised iff :w > 0 and the operation fails.
#
# @core remove remove-instance_method
def remove(selector={}, opts={})
- # Initial byte is 0.
- safe = opts.fetch(:safe, @safe)
+ write_concern = get_write_concern(opts, self)
message = BSON::ByteBuffer.new("\0\0\0\0")
BSON::BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{@name}")
message.put_int(0)
message.put_binary(BSON::BSON_CODER.serialize(selector, false, true, @connection.max_bson_size).to_s)
instrument(:remove, :database => @db.name, :collection => @name, :selector => selector) do
- if safe
- @connection.send_message_with_safe_check(Mongo::Constants::OP_DELETE, message, @db.name, nil, safe)
+ if Mongo::WriteConcern.gle?(write_concern)
+ @connection.send_message_with_acknowledge(Mongo::Constants::OP_DELETE, message, @db.name, nil, write_concern)
else
@connection.send_message(Mongo::Constants::OP_DELETE, message)
true
@@ -432,23 +442,24 @@ def remove(selector={}, opts={})
# @option opts [Boolean] :upsert (+false+) if true, performs an upsert (update or insert)
# @option opts [Boolean] :multi (+false+) update all documents matching the selector, as opposed to
# just the first matching document. Note: only works in MongoDB 1.1.3 or later.
- # @option opts [Boolean, Hash] :safe (+false+)
- # run the operation in safe mode, which runs a +getlasterror+ command on the
- # database to report any assertion. In addition, a hash can be provided to
- # run an fsync and/or wait for replication of the update (>= 1.5.1). Safe
- # options provided here will override any safe options set on this collection,
+ # @option opts [Hash] :w, :j, :wtimeout, :fsync Set the write concern for this operation.
+ # :w > 0 will run a +getlasterror+ command on the database to report any assertion.
+ # :j will confirm a write has been committed to the journal
+ # :wtimeout specifies how long to wait for write confirmation
+ # :fsync will confirm that a write has been fsynced
+ # options provided here will override any write concern options set on this collection,
# its database object, or the current connection. See the options
- # for +DB#get_last_error+.
+ # for +DB#get_last_error+.
#
- # @return [Hash, true] Returns a Hash containing the last error object if running in safe mode.
+ # @return [Hash, true] Returns a Hash containing the last error object if acknowledging writes.
# Otherwise, returns true.
#
- # @raise [Mongo::OperationFailure] will be raised iff safe mode is enabled and the operation fails.
+ # @raise [Mongo::OperationFailure] will be raised iff :w > 0 and the operation fails.
#
# @core update update-instance_method
def update(selector, document, opts={})
# Initial byte is 0.
- safe = opts.fetch(:safe, @safe)
+ write_concern = get_write_concern(opts, self)
message = BSON::ByteBuffer.new("\0\0\0\0")
BSON::BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{@name}")
update_options = 0
@@ -463,8 +474,8 @@ def update(selector, document, opts={})
message.put_binary(BSON::BSON_CODER.serialize(document, check_keys, true, @connection.max_bson_size).to_s)
instrument(:update, :database => @db.name, :collection => @name, :selector => selector, :document => document) do
- if safe
- @connection.send_message_with_safe_check(Mongo::Constants::OP_UPDATE, message, @db.name, nil, safe)
+ if Mongo::WriteConcern.gle?(write_concern)
+ @connection.send_message_with_acknowledge(Mongo::Constants::OP_UPDATE, message, @db.name, nil, write_concern)
else
@connection.send_message(Mongo::Constants::OP_UPDATE, message)
end
@@ -987,7 +998,7 @@ def generate_indexes(field_spec, name, opts)
selector.merge!(opts)
begin
- insert_documents([selector], Mongo::DB::SYSTEM_INDEX_COLLECTION, false, true)
+ insert_documents([selector], Mongo::DB::SYSTEM_INDEX_COLLECTION, false, {:w => 1})
rescue Mongo::OperationFailure => e
if selector[:dropDups] && e.message =~ /^11000/
@@ -1004,7 +1015,7 @@ def generate_indexes(field_spec, name, opts)
# Sends a Mongo::Constants::OP_INSERT message to the database.
# Takes an array of +documents+, an optional +collection_name+, and a
# +check_keys+ setting.
- def insert_documents(documents, collection_name=@name, check_keys=true, safe=false, flags={})
+ def insert_documents(documents, collection_name=@name, check_keys=true, write_concern={}, flags={})
if flags[:continue_on_error]
message = BSON::ByteBuffer.new
message.put_int(1)
@@ -1036,8 +1047,8 @@ def insert_documents(documents, collection_name=@name, check_keys=true, safe=fal
raise InvalidOperation, "Exceded maximum insert size of 16,777,216 bytes" if message.size > @connection.max_bson_size
instrument(:insert, :database => @db.name, :collection => collection_name, :documents => documents) do
- if safe
- @connection.send_message_with_safe_check(Mongo::Constants::OP_INSERT, message, @db.name, nil, safe)
+ if Mongo::WriteConcern.gle?(write_concern)
+ @connection.send_message_with_acknowledge(Mongo::Constants::OP_INSERT, message, @db.name, nil, write_concern)
else
@connection.send_message(Mongo::Constants::OP_INSERT, message)
end
diff --git a/lib/mongo/db.rb b/lib/mongo/db.rb
index 49dfff3174..5e8207b095 100644
--- a/lib/mongo/db.rb
+++ b/lib/mongo/db.rb
@@ -23,13 +23,14 @@ module Mongo
# A MongoDB database.
class DB
+ include Mongo::WriteConcern
- SYSTEM_NAMESPACE_COLLECTION = "system.namespaces"
- SYSTEM_INDEX_COLLECTION = "system.indexes"
- SYSTEM_PROFILE_COLLECTION = "system.profile"
- SYSTEM_USER_COLLECTION = "system.users"
- SYSTEM_JS_COLLECTION = "system.js"
- SYSTEM_COMMAND_COLLECTION = "$cmd"
+ SYSTEM_NAMESPACE_COLLECTION = 'system.namespaces'
+ SYSTEM_INDEX_COLLECTION = 'system.indexes'
+ SYSTEM_PROFILE_COLLECTION = 'system.profile'
+ SYSTEM_USER_COLLECTION = 'system.users'
+ SYSTEM_JS_COLLECTION = 'system.js'
+ SYSTEM_COMMAND_COLLECTION = '$cmd'
# Counter for generating unique request ids.
@@current_request_id = 0
@@ -44,8 +45,8 @@ class DB
# Returns the value of the +strict+ flag.
def strict?; @strict; end
- # The name of the database and the local safe option.
- attr_reader :name, :safe
+ # The name of the database and the local write concern options.
+ attr_reader :name, :write_concern
# The Mongo::Client instance connecting to the MongoDB server.
attr_reader :connection
@@ -70,10 +71,10 @@ def strict?; @strict; end
# fields the factory wishes to inject. (NOTE: if the object already has a primary key,
# the factory should not inject a new key).
#
- # @option opts [Boolean, Hash] :safe (false) Set the default safe-mode options
- # propagated to Collection objects instantiated off of this DB. If no
- # value is provided, the default value set on this instance's Client object will be used. This
- # default can be overridden upon instantiation of any collection by explicitly setting a :safe value
+ # @option opts [Hash] :w, :j, :wtimeout, :fsync Set the default write concern for this database.
+ # Propagated to Collection objects instantiated off of this DB. If no
+ # options are provided, the default write concern set on this instance's Client object will be used. This
+ # default can be overridden upon instantiation of any collection by explicitly setting write concern values
# on initialization
#
# @option opts [Integer] :cache_time (300) Set the time that all ensure_index calls should cache the command.
@@ -84,7 +85,9 @@ def initialize(name, client, opts={})
@connection = client
@strict = opts[:strict]
@pk_factory = opts[:pk]
- @safe = opts.fetch(:safe, @connection.safe)
+
+ @write_concern = get_write_concern(opts, client)
+
if value = opts[:read]
Mongo::Support.validate_read_preference(value)
else
@@ -173,7 +176,7 @@ def add_stored_function(function_name, code)
# @return [Boolean]
def remove_stored_function(function_name)
if self[SYSTEM_JS_COLLECTION].find_one({"_id" => function_name})
- self[SYSTEM_JS_COLLECTION].remove({"_id" => function_name}, :safe => true)
+ self[SYSTEM_JS_COLLECTION].remove({"_id" => function_name}, :w => 1)
else
return false
end
@@ -205,7 +208,7 @@ def add_user(username, password, read_only = false)
# @return [Boolean]
def remove_user(username)
if self[SYSTEM_USER_COLLECTION].find_one({:user => username})
- self[SYSTEM_USER_COLLECTION].remove({:user => username}, :safe => true)
+ self[SYSTEM_USER_COLLECTION].remove({:user => username}, :w => 1)
else
return false
end
@@ -323,7 +326,6 @@ def collection(name, opts={})
"Currently in strict mode."
else
opts = opts.dup
- opts[:safe] = opts.fetch(:safe, @safe)
opts.merge!(:pk => @pk_factory) unless opts[:pk]
Collection.new(name, self, opts)
end
diff --git a/lib/mongo/gridfs/grid.rb b/lib/mongo/gridfs/grid.rb
index 2f6349f121..57f07c263b 100644
--- a/lib/mongo/gridfs/grid.rb
+++ b/lib/mongo/gridfs/grid.rb
@@ -62,8 +62,9 @@ def initialize(db, fs_name=DEFAULT_FS_NAME)
# the content type will may be inferred from the filename extension if the mime-types gem can be
# loaded. Otherwise, the content type 'binary/octet-stream' will be used.
# @option opts [Integer] (262144) :chunk_size size of file chunks in bytes.
- # @option opts [Boolean] :safe (false) When safe mode is enabled, the chunks sent to the server
- # will be validated using an md5 hash. If validation fails, an exception will be raised.
+ # @option opts [Boolean] :w (1), :j (false), :wtimeout (false), :fsync (false) Set the default write concern
+ # When :w > 0, the chunks sent to the server are validated using an md5 hash.
+ # If validation fails, an exception will be raised.
#
# @return [BSON::ObjectId] the file's id.
def put(data, opts={})
diff --git a/lib/mongo/gridfs/grid_file_system.rb b/lib/mongo/gridfs/grid_file_system.rb
index f1e3bceb4a..013d31713a 100644
--- a/lib/mongo/gridfs/grid_file_system.rb
+++ b/lib/mongo/gridfs/grid_file_system.rb
@@ -69,7 +69,8 @@ def initialize(db, fs_name=Grid::DEFAULT_FS_NAME)
# @option opts [Boolean] :delete_old (false) ensure that old versions of the file are deleted. This option
# only work in 'w' mode. Certain precautions must be taken when deleting GridFS files. See the notes under
# GridFileSystem#delete.
- # @option opts [Boolean] :safe (false) When safe mode is enabled, the chunks sent to the server
+ # @option opts [Boolean] :w (1), :j (false), :wtimeout (false), :fsync (false) Set the default write concern
+ # When :w > 0, the chunks sent to the server
# will be validated using an md5 hash. If validation fails, an exception will be raised.
# @option opts [Integer] :versions (false) deletes all versions which exceed the number specified to
# retain ordered by uploadDate. This option only works in 'w' mode. Certain precautions must be taken when
diff --git a/lib/mongo/gridfs/grid_io.rb b/lib/mongo/gridfs/grid_io.rb
index 8b1290f245..cdf4014360 100644
--- a/lib/mongo/gridfs/grid_io.rb
+++ b/lib/mongo/gridfs/grid_io.rb
@@ -48,7 +48,8 @@ class GridIO
# @option opts [String] :content_type ('binary/octet-stream') If no content type is specified,
# the content type will may be inferred from the filename extension if the mime-types gem can be
# loaded. Otherwise, the content type 'binary/octet-stream' will be used.
- # @option opts [Boolean] :safe (false) When safe mode is enabled, the chunks sent to the server
+ # @option opts [Boolean] :w (1), :j (false), :wtimeout (false), :fsync (false) Set the default write concern
+ # When :w > 0, the chunks sent to the server
# will be validated using an md5 hash. If validation fails, an exception will be raised.
def initialize(files, chunks, filename, mode, opts={})
@files = files
diff --git a/lib/mongo/legacy.rb b/lib/mongo/legacy.rb
index c98bc13e3f..863c34d729 100644
--- a/lib/mongo/legacy.rb
+++ b/lib/mongo/legacy.rb
@@ -17,26 +17,65 @@
# ++
module Mongo
- # @deprecated Use Mongo::Client instead.
+ module LegacyWriteConcern
+ @legacy_write_concern = true
+
+ def safe=(value)
+ @write_concern = value
+ end
+
+ def safe
+ if @write_concern[:w] == 0
+ return false
+ elsif @write_concern[:w] == 1
+ return true
+ else
+ return @write_concern
+ end
+ end
+
+ def self.from_uri(uri = ENV['MONGODB_URI'], extra_opts={})
+ parser = URIParser.new uri
+ parser.connection(extra_opts, true)
+ end
+ end
+end
+
+module Mongo
+ # @deprecated Use Mongo::Client instead. Support will be removed after v2.0
class Connection < Client
+ include Mongo::LegacyWriteConcern
+
def initialize(host=nil, port=nil, opts={})
- warn '[DEPRECATED] Mongo::Connection has been replaced with Mongo::Client.'
+ write_concern_from_legacy(opts)
super
end
end
- # @deprecated Use Mongo::ReplSetClient instead.
+ # @deprecated Use Mongo::ReplSetClient instead. Support will be removed after v2.0
class ReplSetConnection < ReplSetClient
+ include Mongo::LegacyWriteConcern
+
def initialize(*args)
- warn '[DEPRECATED] Mongo::ReplSetConnection has been replaced with Mongo::ReplSetClient.'
+ if args.last.is_a?(Hash)
+ opts = args.pop
+ write_concern_from_legacy(opts)
+ args.push(opts)
+ end
super
end
end
- # @deprecated Use Mongo::ShardedClient instead.
+ # @deprecated Use Mongo::ShardedClient instead. Support will be removed after v2.0
class ShardedConnection < ShardedClient
+ include Mongo::LegacyWriteConcern
+
def initialize(*args)
- warn '[DEPRECATED] Mongo::ShardedConnection has been replaced with Mongo::ShardedClient.'
+ if args.last.is_a?(Hash)
+ opts = args.pop
+ write_concern_from_legacy(opts)
+ args.push(opts)
+ end
super
end
end
diff --git a/lib/mongo/networking.rb b/lib/mongo/networking.rb
index 9a5dfdf4ce..7bc084cdcf 100644
--- a/lib/mongo/networking.rb
+++ b/lib/mongo/networking.rb
@@ -56,7 +56,7 @@ def send_message(operation, message, opts={})
# @see DB#get_last_error for valid last error params.
#
# @return [Hash] The document returned by the call to getlasterror.
- def send_message_with_safe_check(operation, message, db_name, log_message=nil, last_error_params=false)
+ def send_message_with_acknowledge(operation, message, db_name, log_message=nil, last_error_params=false)
docs = num_received = cursor_id = ''
add_message_headers(message, operation)
@@ -210,14 +210,23 @@ def read_documents(number_received, sock)
end
# Constructs a getlasterror message. This method is used exclusively by
- # Client#send_message_with_safe_check.
+ # Client#send_message_with_acknowledge.
#
# Because it modifies message by reference, we don't need to return it.
def build_last_error_message(message, db_name, opts)
+
+ # flags bit vector
message.put_int(0)
+
+ # namespace
BSON::BSON_RUBY.serialize_cstr(message, "#{db_name}.$cmd")
+
+ # number to skip
message.put_int(0)
+
+ # numer to return (-1 closes cursor)
message.put_int(-1)
+
cmd = BSON::OrderedHash.new
cmd[:getlasterror] = 1
if opts.is_a?(Hash)
diff --git a/lib/mongo/repl_set_client.rb b/lib/mongo/repl_set_client.rb
index 00e2fc29ca..7282bf39cd 100644
--- a/lib/mongo/repl_set_client.rb
+++ b/lib/mongo/repl_set_client.rb
@@ -21,11 +21,25 @@ module Mongo
# Instantiates and manages connections to a MongoDB replica set.
class ReplSetClient < Client
- REPL_SET_OPTS = [:read, :refresh_mode, :refresh_interval, :read_secondary,
- :rs_name, :name, :tag_sets, :secondary_acceptable_latency_ms]
-
- attr_reader :replica_set_name, :seeds, :refresh_interval, :refresh_mode,
- :refresh_version, :manager, :tag_sets, :acceptable_latency
+ REPL_SET_OPTS = [
+ :read,
+ :refresh_mode,
+ :refresh_interval,
+ :read_secondary,
+ :rs_name,
+ :name,
+ :tag_sets,
+ :secondary_acceptable_latency_ms
+ ]
+
+ attr_reader :replica_set_name,
+ :seeds,
+ :refresh_interval,
+ :refresh_mode,
+ :refresh_version,
+ :manager,
+ :tag_sets,
+ :acceptable_latency
# Create a connection to a MongoDB replica set.
#
@@ -39,9 +53,9 @@ class ReplSetClient < Client
# @overload initialize(seeds=ENV["MONGODB_URI"], opts={})
# @param [Array, Array] seeds
#
- # @option opts [Boolean, Hash] :safe (false) Set the default safe-mode options
+ # @option opts [Hash] :w (1), :j (false), :wtimeout (false), :fsync (false) Set the default write concern
# propagated to DB objects instantiated off of this Client. This
- # default can be overridden upon instantiation of any DB by explicitly setting a :safe value
+ # default can be overridden upon instantiation of any DB by explicitly setting write concern values
# on initialization.
# @option opts [:primary, :primary_preferred, :secondary, :secondary_preferred, :nearest] :read_preference (:primary)
# A "read preference" determines the candidate replica set members to which a query or command can be sent.
@@ -150,7 +164,7 @@ def initialize(*args)
end
def valid_opts
- GENERIC_OPTS + REPL_SET_OPTS
+ super + REPL_SET_OPTS - CLIENT_ONLY_OPTS
end
def inspect
@@ -437,8 +451,8 @@ def max_bson_size
# Parse option hash
def setup(opts)
# Refresh
- @refresh_mode = opts.fetch(:refresh_mode, false)
- @refresh_interval = opts.fetch(:refresh_interval, 90)
+ @refresh_mode = opts.delete(:refresh_mode) || false
+ @refresh_interval = opts.delete(:refresh_interval) || 90
if @refresh_mode && @refresh_interval < 60
@refresh_interval = 60 unless ENV['TEST_MODE'] = 'TRUE'
@@ -456,26 +470,26 @@ def setup(opts)
if opts[:read_secondary]
warn ":read_secondary options has now been deprecated and will " +
"be removed in driver v2.0. Use the :read option instead."
- @read_secondary = opts.fetch(:read_secondary, false)
+ @read_secondary = opts.delete(:read_secondary) || false
@read = :secondary_preferred
else
- @read = opts.fetch(:read, :primary)
+ @read = opts.delete(:read) || :primary
Mongo::Support.validate_read_preference(@read)
end
- @tag_sets = opts.fetch(:tag_sets, [])
- @acceptable_latency = opts.fetch(:secondary_acceptable_latency_ms, 15)
+ @tag_sets = opts.delete(:tag_sets) || []
+ @acceptable_latency = opts.delete(:secondary_acceptable_latency_ms) || 15
# Replica set name
if opts[:rs_name]
warn ":rs_name option has been deprecated and will be removed in v2.0. " +
"Please use :name instead."
- @replica_set_name = opts[:rs_name]
+ @replica_set_name = opts.delete(:rs_name)
else
- @replica_set_name = opts[:name]
+ @replica_set_name = opts.delete(:name)
end
- opts[:connect_timeout] = opts[:connect_timeout] || 30
+ opts[:connect_timeout] = opts.delete(:connect_timeout) || 30
super opts
end
diff --git a/lib/mongo/sharded_client.rb b/lib/mongo/sharded_client.rb
index 7175054216..4564af8e47 100644
--- a/lib/mongo/sharded_client.rb
+++ b/lib/mongo/sharded_client.rb
@@ -34,9 +34,9 @@ class ShardedClient < ReplSetClient
#
# @option opts [String] :name (nil) The name of the sharded cluster to connect to. You
# can use this option to verify that you're connecting to the right sharded cluster.
- # @option opts [Boolean, Hash] :safe (false) Set the default safe-mode options
+ # @option opts [Hash] ::w (1), :j (false), :wtimeout (false), :fsync (false) Set the default write concern
# propagated to DB objects instantiated off of this Client. This
- # default can be overridden upon instantiation of any DB by explicitly setting a :safe value
+ # default can be overridden upon instantiation of any DB by explicitly setting a write concern values
# on initialization.
# @option opts [Logger] :logger (nil) Logger instance to receive driver operation log.
# @option opts [Integer] :pool_size (1) The maximum number of socket connections allowed per
diff --git a/lib/mongo/util/ssl_socket.rb b/lib/mongo/util/ssl_socket.rb
index c3beab63e9..b99220086b 100644
--- a/lib/mongo/util/ssl_socket.rb
+++ b/lib/mongo/util/ssl_socket.rb
@@ -20,7 +20,7 @@ def initialize(host, port, op_timeout=nil, connect_timeout=nil)
@ssl = OpenSSL::SSL::SSLSocket.new(@socket)
@ssl.sync_close = true
-
+
connect
end
diff --git a/lib/mongo/util/support.rb b/lib/mongo/util/support.rb
index 5324c4824d..2926cc5631 100644
--- a/lib/mongo/util/support.rb
+++ b/lib/mongo/util/support.rb
@@ -20,15 +20,31 @@
module Mongo
module Support
+
include Mongo::Conversions
extend self
- READ_PREFERENCES = [:primary, :primary_preferred, :secondary, :secondary_preferred, :nearest]
+ READ_PREFERENCES = [
+ :primary,
+ :primary_preferred,
+ :secondary,
+ :secondary_preferred,
+ :nearest
+ ]
# Commands that may be sent to replica-set secondaries, depending on
# read preference and tags. All other commands are always run on the primary.
- SECONDARY_OK_COMMANDS = ['group', 'aggregate', 'collstats', 'dbstats', 'count', 'distinct',
- 'geonear', 'geosearch', 'geowalk']
+ SECONDARY_OK_COMMANDS = [
+ 'group',
+ 'aggregate',
+ 'collstats',
+ 'dbstats',
+ 'count',
+ 'distinct',
+ 'geonear',
+ 'geosearch',
+ 'geowalk'
+ ]
# Generate an MD5 for authentication.
#
diff --git a/lib/mongo/util/uri_parser.rb b/lib/mongo/util/uri_parser.rb
index 12d038ef2f..339e65c8dd 100644
--- a/lib/mongo/util/uri_parser.rb
+++ b/lib/mongo/util/uri_parser.rb
@@ -35,7 +35,20 @@ class URIParser
MONGODB_URI_SPEC = "mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]"
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', 'true', 'false', true, false].include?(arg)},
:replicaset => lambda {|arg| arg.length > 0},
@@ -76,7 +89,18 @@ class URIParser
:wtimeoutms => lambda {|arg| arg.to_i }
}
- attr_reader :auths, :connect, :replicaset, :slaveok, :safe, :w, :wtimeout, :fsync, :journal, :connecttimeoutms, :sockettimeoutms, :wtimeoutms
+ attr_reader :auths,
+ :connect,
+ :replicaset,
+ :slaveok,
+ :safe,
+ :w,
+ :wtimeout,
+ :fsync,
+ :journal,
+ :connecttimeoutms,
+ :sockettimeoutms,
+ :wtimeoutms
# Parse a MongoDB URI. This method is used by Client.from_uri.
# Returns an array of nodes and an array of db authorizations, if applicable.
@@ -105,12 +129,20 @@ def initialize(uri)
# @note Don't confuse this with attribute getter method #connect.
#
# @return [Client,ReplSetClient]
- def connection(extra_opts)
+ def connection(extra_opts, legacy=false)
opts = connection_options.merge! extra_opts
- if replicaset?
- ReplSetClient.new(nodes, opts)
+ if(legacy)
+ if replicaset?
+ ReplSetConnection.new(nodes, opts)
+ else
+ Connection.new(host, port, opts)
+ end
else
- Client.new(host, port, opts)
+ if replicaset?
+ ReplSetClient.new(nodes, opts)
+ else
+ Client.new(host, port, opts)
+ end
end
end
@@ -152,32 +184,16 @@ def port
def connection_options
opts = {}
- if (@w || @journal || @wtimeout || @fsync || @wtimeoutms) && !@safe
- raise MongoArgumentError, "Safe must be true if w, journal, wtimeoutMS, or fsync is specified"
+ if @wtimeout
+ warn "Using wtimeout in a URI is deprecated, please use wtimeoutMS. It will be removed in v2.0."
+ opts[:wtimeout] = @wtimeout
end
+ opts[:wtimeout] = @wtimeoutms
- if @safe
- if @w || @journal || @wtimeout || @fsync || @wtimeoutms
- safe_opts = {}
- safe_opts[:w] = @w if @w
- safe_opts[:j] = @journal if @journal
-
- if @wtimeout
- warn "Using wtimeout in a URI is deprecated, please use wtimeoutMS. It will be removed in v2.0."
- safe_opts[:wtimeout] = @wtimeout
- end
-
- if @wtimeoutms
- safe_opts[:wtimeout] = @wtimeoutms
- end
-
- safe_opts[:fsync] = @fsync if @fsync
- else
- safe_opts = true
- end
-
- opts[:safe] = safe_opts
- end
+ opts[:w] = 1 if @safe
+ opts[:w] = @w if @w
+ opts[:j] = @journal
+ opts[:fsync] = @fsync
if @connecttimeoutms
opts[:connect_timeout] = @connecttimeoutms
diff --git a/lib/mongo/util/write_concern.rb b/lib/mongo/util/write_concern.rb
new file mode 100644
index 0000000000..63228fa78f
--- /dev/null
+++ b/lib/mongo/util/write_concern.rb
@@ -0,0 +1,67 @@
+# encoding: UTF-8
+
+# --
+# Copyright (C) 2008-2011 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 WriteConcern
+
+ attr_reader :legacy_write_concern
+
+ @@safe_warn = nil
+ def write_concern_from_legacy(opts)
+ # Warn if 'safe' parameter is being used,
+ if opts.key?(:safe) && !@@safe_warn && !ENV['TEST_MODE']
+ warn "[DEPRECATED] The 'safe' write concern option has been deprecated in favor of 'w'."
+ @@safe_warn = true
+ end
+
+ # nil: set :w => 0
+ # false: set :w => 0
+ # true: set :w => 1
+ # hash: set :w => 0 and merge with opts
+
+ unless opts.has_key?(:w)
+ opts[:w] = 0 # legacy default, unacknowledged
+ safe = opts.delete(:safe)
+ if(safe && safe.is_a?(Hash))
+ opts.merge!(safe)
+ elsif(safe == true)
+ opts[:w] = 1
+ end
+ end
+ end
+
+ # todo: throw exception for conflicting write concern options
+ def get_write_concern(opts, parent=nil)
+ write_concern_from_legacy(opts) if opts.key?(:safe) || @legacy_write_concern
+ write_concern = {
+ :w => 1,
+ :j => false,
+ :fsync => false,
+ :wtimeout => false
+ }
+ write_concern.merge!(parent.write_concern) if parent
+ write_concern.merge!(opts.select {|k| write_concern.keys.include?(k)})
+ write_concern
+ end
+
+ def self.gle?(write_concern)
+ write_concern[:w] > 0 || write_concern[:j] || write_concern[:fsync] || write_concern[:wtimeout]
+ end
+
+ end
+end
\ No newline at end of file
diff --git a/lib/mongo/version.rb b/lib/mongo/version.rb
deleted file mode 100644
index a222744177..0000000000
--- a/lib/mongo/version.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-module Mongo
- VERSION = "1.7.0"
-end
diff --git a/tasks/testing.rake b/tasks/testing.rake
index 1659c2de99..8a91f49fd5 100644
--- a/tasks/testing.rake
+++ b/tasks/testing.rake
@@ -17,6 +17,12 @@ namespace :test do
desc "Runs default test suites"
task :ruby do
+ SimpleCov.start do
+ add_group "Mongo", 'lib/mongo'
+ add_group "BSON", 'lib/bson'
+ add_filter "/test/"
+ end
+
if ENV['TEST']
Rake::Task['test:functional'].invoke
else
@@ -55,12 +61,12 @@ namespace :test do
require 'mongo'
client = Mongo::Client.new(
ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
- ENV['MONGO_RUBY_DRIVER_PORT'] || Mongo::Client::DEFAULT_PORT, :safe => true)
+ ENV['MONGO_RUBY_DRIVER_PORT'] || Mongo::Client::DEFAULT_PORT)
client.database_names.each {|name| client.drop_database(name) if name =~ /^ruby-test/ }
if File.directory?('data')
puts "[CLEAN-UP] Removing replica set data files..."
- Dir.delete('data')
+ FileUtils.rm_rf 'data'
end
end
diff --git a/test/auxillary/authentication_test.rb b/test/auxillary/authentication_test.rb
index 188d33d40a..c1e63e7eb4 100644
--- a/test/auxillary/authentication_test.rb
+++ b/test/auxillary/authentication_test.rb
@@ -28,18 +28,18 @@ def test_authenticate
@admin.logout
assert_raise Mongo::OperationFailure do
- @db1['stuff'].insert({:a => 2}, :safe => true)
+ @db1['stuff'].insert({:a => 2})
end
assert_raise Mongo::OperationFailure do
- @db2['stuff'].insert({:a => 2}, :safe => true)
+ @db2['stuff'].insert({:a => 2})
end
@db1.authenticate('user1', 'secret')
@db2.authenticate('user2', 'secret')
- assert @db1['stuff'].insert({:a => 2}, :safe => true)
- assert @db2['stuff'].insert({:a => 2}, :safe => true)
+ assert @db1['stuff'].insert({:a => 2})
+ assert @db2['stuff'].insert({:a => 2})
puts "Please bounce the server."
gets
@@ -50,24 +50,24 @@ def test_authenticate
rescue Mongo::ConnectionFailure
end
- assert @db1['stuff'].insert({:a => 2}, :safe => true)
- assert @db2['stuff'].insert({:a => 2}, :safe => true)
- assert @db2['stuff'].find({}, :safe => true)
+ assert @db1['stuff'].insert({:a => 2})
+ assert @db2['stuff'].insert({:a => 2})
+ assert @db2['stuff'].find({})
@db1.logout
assert_raise Mongo::OperationFailure do
- @db1['stuff'].insert({:a => 2}, :safe => true)
+ @db1['stuff'].insert({:a => 2})
end
@db2.logout
assert_raise Mongo::OperationFailure do
- assert @db2['stuff'].insert({:a => 2}, :safe => true)
+ assert @db2['stuff'].insert({:a => 2})
end
@db2.authenticate('userRO', 'secret')
- assert @db2['stuff'].find({}, :safe => true)
+ assert @db2['stuff'].find({})
assert_raise Mongo::OperationFailure do
- assert @db2['stuff'].insert({:a => 2}, :safe => true)
+ assert @db2['stuff'].insert({:a => 2})
end
end
diff --git a/test/auxillary/repl_set_auth_test.rb b/test/auxillary/repl_set_auth_test.rb
index 695c291630..e15f7697e3 100644
--- a/test/auxillary/repl_set_auth_test.rb
+++ b/test/auxillary/repl_set_auth_test.rb
@@ -21,14 +21,14 @@ def test_repl_set_auth
# Ensure that insert fails
assert_raise_error Mongo::OperationFailure, "unauthorized" do
- @client['foo']['stuff'].insert({:a => 2}, :safe => {:w => 3})
+ @client['foo']['stuff'].insert({:a => 2}, {:w => 3})
end
# Then authenticate
assert @client['admin'].authenticate("me", "secret")
# Insert should succeed now
- assert @client['foo']['stuff'].insert({:a => 2}, :safe => {:w => 3})
+ assert @client['foo']['stuff'].insert({:a => 2}, {:w => 3})
# So should a query
assert @client['foo']['stuff'].find_one
diff --git a/test/auxillary/threaded_authentication_test.rb b/test/auxillary/threaded_authentication_test.rb
index f34cb53fd5..6309ea5400 100644
--- a/test/auxillary/threaded_authentication_test.rb
+++ b/test/auxillary/threaded_authentication_test.rb
@@ -43,13 +43,13 @@ def test_authenticate
threaded_exec do
assert_raise Mongo::OperationFailure do
- @db1['stuff'].insert({:a => 2}, :safe => true)
+ @db1['stuff'].insert({:a => 2})
end
end
threaded_exec do
assert_raise Mongo::OperationFailure do
- @db2['stuff'].insert({:a => 2}, :safe => true)
+ @db2['stuff'].insert({:a => 2})
end
end
@@ -57,11 +57,11 @@ def test_authenticate
@db2.authenticate('user2', 'secret')
threaded_exec do
- assert @db1['stuff'].insert({:a => 2}, :safe => true)
+ assert @db1['stuff'].insert({:a => 2})
end
threaded_exec do
- assert @db2['stuff'].insert({:a => 2}, :safe => true)
+ assert @db2['stuff'].insert({:a => 2})
end
puts "Please bounce the server."
@@ -74,24 +74,24 @@ def test_authenticate
end
threaded_exec do
- assert @db1['stuff'].insert({:a => 2}, :safe => true)
+ assert @db1['stuff'].insert({:a => 2})
end
threaded_exec do
- assert @db2['stuff'].insert({:a => 2}, :safe => true)
+ assert @db2['stuff'].insert({:a => 2})
end
@db1.logout
threaded_exec do
assert_raise Mongo::OperationFailure do
- @db1['stuff'].insert({:a => 2}, :safe => true)
+ @db1['stuff'].insert({:a => 2})
end
end
@db2.logout
threaded_exec do
assert_raise Mongo::OperationFailure do
- assert @db2['stuff'].insert({:a => 2}, :safe => true)
+ assert @db2['stuff'].insert({:a => 2})
end
end
end
diff --git a/test/functional/collection_test.rb b/test/functional/collection_test.rb
index 6c18e7362c..4f7bb73249 100644
--- a/test/functional/collection_test.rb
+++ b/test/functional/collection_test.rb
@@ -92,23 +92,23 @@ def test_rename_collection
end
def test_nil_id
- assert_equal 5, @@test.insert({"_id" => 5, "foo" => "bar"}, {:safe => true})
- assert_equal 5, @@test.save({"_id" => 5, "foo" => "baz"}, {:safe => true})
+ assert_equal 5, @@test.insert({"_id" => 5, "foo" => "bar"})
+ assert_equal 5, @@test.save({"_id" => 5, "foo" => "baz"})
assert_equal nil, @@test.find_one("foo" => "bar")
assert_equal "baz", @@test.find_one(:_id => 5)["foo"]
assert_raise OperationFailure do
- @@test.insert({"_id" => 5, "foo" => "bar"}, {:safe => true})
+ @@test.insert({"_id" => 5, "foo" => "bar"})
end
- assert_equal nil, @@test.insert({"_id" => nil, "foo" => "bar"}, {:safe => true})
- assert_equal nil, @@test.save({"_id" => nil, "foo" => "baz"}, {:safe => true})
+ assert_equal nil, @@test.insert({"_id" => nil, "foo" => "bar"})
+ assert_equal nil, @@test.save({"_id" => nil, "foo" => "baz"})
assert_equal nil, @@test.find_one("foo" => "bar")
assert_equal "baz", @@test.find_one(:_id => nil)["foo"]
assert_raise OperationFailure do
- @@test.insert({"_id" => nil, "foo" => "bar"}, {:safe => true})
+ @@test.insert({"_id" => nil, "foo" => "bar"})
end
assert_raise OperationFailure do
- @@test.insert({:_id => nil, "foo" => "bar"}, {:safe => true})
+ @@test.insert({:_id => nil, "foo" => "bar"})
end
end
@@ -146,11 +146,11 @@ def test_safe_insert
@@test.create_index("hello", :unique => true)
a = {"hello" => "world"}
@@test.insert(a)
- @@test.insert(a)
+ @@test.insert(a, :w => 0)
assert(@@db.get_last_error['err'].include?("11000"))
assert_raise OperationFailure do
- @@test.insert(a, :safe => true)
+ @@test.insert(a)
end
end
@@ -174,7 +174,7 @@ def test_bulk_insert_with_continue_on_error
docs << {:foo => 2}
docs << {:foo => 3}
assert_raise OperationFailure do
- @@test.insert(docs, :safe => true)
+ @@test.insert(docs)
end
assert_equal 1, @@test.count
@@test.remove
@@ -185,7 +185,7 @@ def test_bulk_insert_with_continue_on_error
docs << {:foo => 2}
docs << {:foo => 3}
assert_raise OperationFailure do
- @@test.insert(docs, :safe => true, :continue_on_error => true)
+ @@test.insert(docs, :continue_on_error => true)
end
assert_equal 3, @@test.count
@@ -255,26 +255,26 @@ def test_maximum_insert_size
end
end
- if @@version >= "1.5.1"
- def test_safe_mode_with_advanced_safe_with_invalid_options
- assert_raise_error ArgumentError, "Unknown key(s): wtime" do
- @@test.insert({:foo => 1}, :safe => {:w => 2, :wtime => 1, :fsync => true})
- end
- assert_raise_error ArgumentError, "Unknown key(s): wtime" do
- @@test.update({:foo => 1}, {:foo => 2}, :safe => {:w => 2, :wtime => 1, :fsync => true})
- end
-
- assert_raise_error ArgumentError, "Unknown key(s): wtime" do
- @@test.remove({:foo => 2}, :safe => {:w => 2, :wtime => 1, :fsync => true})
- end
- end
- end
+ #if @@version >= "1.5.1"
+ # def test_safe_mode_with_advanced_safe_with_invalid_options
+ # assert_raise_error ArgumentError, "Unknown key(s): wtime" do
+ # @@test.insert({:foo => 1}, :w => 2, :wtime => 1, :fsync => true)
+ # end
+ # assert_raise_error ArgumentError, "Unknown key(s): wtime" do
+ # @@test.update({:foo => 1}, {:foo => 2}, :w => 2, :wtime => 1, :fsync => true)
+ # end
+ #
+ # assert_raise_error ArgumentError, "Unknown key(s): wtime" do
+ # @@test.remove({:foo => 2}, :w => 2, :wtime => 1, :fsync => true)
+ # end
+ # end
+ #end
if @@version >= "2.0.0"
def test_safe_mode_with_journal_commit_option
- @@test.insert({:foo => 1}, :safe => {:j => true})
- @@test.update({:foo => 1}, {:foo => 2}, :safe => {:j => true})
- @@test.remove({:foo => 2}, :safe => {:j => true})
+ @@test.insert({:foo => 1}, :j => true)
+ @@test.update({:foo => 1}, {:foo => 2}, :j => true)
+ @@test.remove({:foo => 2}, :j => true)
end
end
@@ -332,7 +332,7 @@ def test_safe_update
# Can't change an index.
assert_raise OperationFailure do
- @@test.update({}, {"$inc" => {"x" => 1}}, :safe => true)
+ @@test.update({}, {"$inc" => {"x" => 1}})
end
@@test.drop
end
@@ -348,7 +348,7 @@ def test_safe_update
# Can't duplicate an index.
assert_raise OperationFailure do
- @@test.update({}, {"x" => 10}, :safe => true)
+ @@test.update({}, {"x" => 10})
end
@@test.drop
end
@@ -358,10 +358,10 @@ def test_safe_save
@@test.create_index("hello", :unique => true)
@@test.save("hello" => "world")
- @@test.save("hello" => "world")
+ @@test.save({"hello" => "world"}, :w => 0)
assert_raise OperationFailure do
- @@test.save({"hello" => "world"}, :safe => true)
+ @@test.save({"hello" => "world"})
end
@@test.drop
end
@@ -374,7 +374,7 @@ def test_mocked_safe_remove
@client.stubs(:receive).returns([[{'ok' => 0, 'err' => 'failed'}], 1, 0])
assert_raise OperationFailure do
- @test.remove({}, :safe => true)
+ @test.remove({})
end
@test.drop
end
@@ -385,12 +385,12 @@ def test_safe_remove
@test = @db['test-safe-remove']
@test.remove
@test.save({:a => 50})
- assert_equal 1, @test.remove({}, :safe => true)["n"]
+ assert_equal 1, @test.remove({})["n"]
@test.drop
end
def test_remove_return_value
- assert_equal true, @@test.remove({})
+ assert_equal true, @@test.remove({}, :w => 0)
end
def test_count
diff --git a/test/functional/connection_test.rb b/test/functional/connection_test.rb
index f610632f5a..4905221a7c 100644
--- a/test/functional/connection_test.rb
+++ b/test/functional/connection_test.rb
@@ -361,7 +361,7 @@ def test_connection_activity
end
end
- should "close the connection on send_message_with_safe_check for major exceptions" do
+ should "close the connection on send_message_with_acknowledge for major exceptions" do
@con.expects(:checkout_writer).raises(SystemStackError)
@con.expects(:close)
begin
diff --git a/test/functional/cursor_fail_test.rb b/test/functional/cursor_fail_test.rb
index 4a807a4947..4813196288 100644
--- a/test/functional/cursor_fail_test.rb
+++ b/test/functional/cursor_fail_test.rb
@@ -11,37 +11,11 @@ class CursorFailTest < Test::Unit::TestCase
@@version = @@connection.server_version
def setup
- @@coll.remove({}, :safe => true)
- @@coll.insert({'a' => 1}, :safe => true) # collection not created until it's used
+ @@coll.remove({})
+ @@coll.insert({'a' => 1}) # collection not created until it's used
@@coll_full_name = "#{MONGO_TEST_DB}.test"
end
- #def test_refill_via_get_more
- # assert_equal 1, @@coll.count
- # 1000.times { |i|
- # assert_equal 1 + i, @@coll.count
- # @@coll.insert({'a' => i}, :safe => true)
- # }
- #
- # assert_equal 1001, @@coll.count
- # count = 0
- # @@coll.find.each { |obj|
- # count += obj['a']
- # }
- # assert_equal 1001, @@coll.count
-
- # # do the same thing again for debugging
- # assert_equal 1001, @@coll.count
- # count2 = 0
- # @@coll.find.each { |obj|
- # count2 += obj['a']
- # }
- # assert_equal 1001, @@coll.count
- #
- # assert_equal count, count2
- # assert_equal 499501, count
- #end
-
def test_refill_via_get_more_alt_coll
coll = @@db.collection('test-alt-coll')
coll.remove
diff --git a/test/functional/cursor_test.rb b/test/functional/cursor_test.rb
index 35ae485b2a..c84a9bc1c9 100644
--- a/test/functional/cursor_test.rb
+++ b/test/functional/cursor_test.rb
@@ -195,15 +195,15 @@ def test_id_range_queries
t1 = Time.now
t1_id = ObjectId.from_time(t1)
- @@coll.save({:t => 't1'}, {:safe => true})
- @@coll.save({:t => 't1'}, {:safe => true})
- @@coll.save({:t => 't1'}, {:safe => true})
+ @@coll.save({:t => 't1'})
+ @@coll.save({:t => 't1'})
+ @@coll.save({:t => 't1'})
sleep(2)
t2 = Time.now
t2_id = ObjectId.from_time(t2)
- @@coll.save({:t => 't2'}, {:safe => true})
- @@coll.save({:t => 't2'}, {:safe => true})
- @@coll.save({:t => 't2'}, {:safe => true})
+ @@coll.save({:t => 't2'})
+ @@coll.save({:t => 't2'})
+ @@coll.save({:t => 't2'})
assert_equal 3, @@coll.find({'_id' => {'$gt' => t1_id, '$lt' => t2_id}}).count
@@coll.find({'_id' => {'$gt' => t2_id}}).each do |doc|
diff --git a/test/functional/db_api_test.rb b/test/functional/db_api_test.rb
index 9a2ac947d9..01c4f53f3b 100644
--- a/test/functional/db_api_test.rb
+++ b/test/functional/db_api_test.rb
@@ -329,8 +329,7 @@ def test_collection_options_are_passed_to_the_existing_ones
@@db.create_collection('foobar')
- opts = {:safe => true}
- coll = @@db.create_collection('foobar', opts)
+ coll = @@db.create_collection('foobar')
assert_equal true, coll.safe
end
@@ -429,9 +428,9 @@ def test_index_on_subfield
end
def test_array
- @@coll.remove({'$atomic' => true}, :safe => true)
- @@coll.insert({'b' => [1, 2, 3]}, :safe => true)
- @@coll.insert({'b' => [1, 2, 3]}, :safe => true)
+ @@coll.remove({'$atomic' => true})
+ @@coll.insert({'b' => [1, 2, 3]})
+ @@coll.insert({'b' => [1, 2, 3]})
rows = @@coll.find({}, {:fields => ['b']}).to_a
assert_equal 2, rows.length
assert_equal [1, 2, 3], rows[1]['b']
diff --git a/test/functional/grid_file_system_test.rb b/test/functional/grid_file_system_test.rb
index dc338e25a7..9280fc291c 100644
--- a/test/functional/grid_file_system_test.rb
+++ b/test/functional/grid_file_system_test.rb
@@ -16,7 +16,7 @@ class GridFileSystemTest < Test::Unit::TestCase
setup do
@chunks_data = "CHUNKS" * 50000
@grid = GridFileSystem.new(@db)
- @opts = {:safe => true}
+ @opts = {:w => 1}
@original_opts = @opts.dup
@grid.open('sample.file', 'w', @opts) do |f|
f.write @chunks_data
diff --git a/test/functional/grid_io_test.rb b/test/functional/grid_io_test.rb
index d39a5a3ea8..a59077306f 100644
--- a/test/functional/grid_io_test.rb
+++ b/test/functional/grid_io_test.rb
@@ -186,7 +186,7 @@ class GridIOTest < Test::Unit::TestCase
context "Grid MD5 check" do
should "run in safe mode" do
- file = GridIO.new(@files, @chunks, 'smallfile', 'w', :safe => true)
+ file = GridIO.new(@files, @chunks, 'smallfile', 'w')
file.write("DATA" * 100)
assert file.close
assert_equal file.server_md5, file.client_md5
@@ -194,7 +194,7 @@ class GridIOTest < Test::Unit::TestCase
should "validate with a large file" do
io = File.open(File.join(TEST_DATA, 'sample_file.pdf'), 'r')
- file = GridIO.new(@files, @chunks, 'bigfile', 'w', :safe => true)
+ file = GridIO.new(@files, @chunks, 'bigfile', 'w')
file.write(io)
assert file.close
assert_equal file.server_md5, file.client_md5
@@ -203,7 +203,7 @@ class GridIOTest < Test::Unit::TestCase
should "raise an exception when check fails" do
io = File.open(File.join(TEST_DATA, 'sample_file.pdf'), 'r')
@db.stubs(:command).returns({'md5' => '12345'})
- file = GridIO.new(@files, @chunks, 'bigfile', 'w', :safe => true)
+ file = GridIO.new(@files, @chunks, 'bigfile', 'w')
file.write(io)
assert_raise GridMD5Failure do
assert file.close
diff --git a/test/functional/grid_test.rb b/test/functional/grid_test.rb
index 948675f1ae..7ba7d26991 100644
--- a/test/functional/grid_test.rb
+++ b/test/functional/grid_test.rb
@@ -59,12 +59,6 @@ class GridTest < Test::Unit::TestCase
assert_equal 'sample', file['filename']
end
- #should "not be able to overwrite an exising file" do
- # assert_raise GridError do
- # @grid.put(@data, :filename => 'sample', :_id => @id, :safe => true)
- # end
- #end
-
should "return nil if it doesn't exist" do
assert_nil @grid.exist?(:metadata => 'foo')
end
diff --git a/test/functional/safe_test.rb b/test/functional/safe_test.rb
index 48d6640cf5..12d9182fb9 100644
--- a/test/functional/safe_test.rb
+++ b/test/functional/safe_test.rb
@@ -4,65 +4,65 @@
class SafeTest < Test::Unit::TestCase
context "Safe mode propogation: " do
setup do
- @con = standard_connection(:safe => {:w => 1})
- @db = @con[MONGO_TEST_DB]
- @col = @db['test-safe']
- @col.create_index([[:a, 1]], :unique => true)
- @col.remove
+ @connection = standard_connection({:safe => true}, true) # Legacy
+ @db = @connection[MONGO_TEST_DB]
+ @collection = @db['test-safe']
+ @collection.create_index([[:a, 1]], :unique => true)
+ @collection.remove
end
should "propogate safe option on insert" do
- @col.insert({:a => 1})
+ @collection.insert({:a => 1})
assert_raise_error(OperationFailure, "duplicate key") do
- @col.insert({:a => 1})
+ @collection.insert({:a => 1})
end
end
should "allow safe override on insert" do
- @col.insert({:a => 1})
- @col.insert({:a => 1}, :safe => false)
+ @collection.insert({:a => 1})
+ @collection.insert({:a => 1}, :safe => false)
end
should "propogate safe option on update" do
- @col.insert({:a => 1})
- @col.insert({:a => 2})
+ @collection.insert({:a => 1})
+ @collection.insert({:a => 2})
assert_raise_error(OperationFailure, "duplicate key") do
- @col.update({:a => 2}, {:a => 1})
+ @collection.update({:a => 2}, {:a => 1})
end
end
should "allow safe override on update" do
- @col.insert({:a => 1})
- @col.insert({:a => 2})
- @col.update({:a => 2}, {:a => 1}, :safe => false)
+ @collection.insert({:a => 1})
+ @collection.insert({:a => 2})
+ @collection.update({:a => 2}, {:a => 1}, :safe => false)
end
end
context "Safe error objects" do
setup do
- @con = standard_connection
- @db = @con[MONGO_TEST_DB]
- @col = @db['test']
- @col.remove
- @col.insert({:a => 1})
- @col.insert({:a => 1})
- @col.insert({:a => 1})
+ @connection = standard_connection({:safe => true}, true) # Legacy
+ @db = @connection[MONGO_TEST_DB]
+ @collection = @db['test']
+ @collection.remove
+ @collection.insert({:a => 1})
+ @collection.insert({:a => 1})
+ @collection.insert({:a => 1})
end
should "return object on update" do
- response = @col.update({:a => 1}, {"$set" => {:a => 2}},
- :multi => true, :safe => true)
+ response = @collection.update({:a => 1}, {"$set" => {:a => 2}},
+ :multi => true)
assert response['updatedExisting']
assert_equal 3, response['n']
end
should "return object on remove" do
- response = @col.remove({}, :safe => true)
+ response = @collection.remove({})
assert_equal 3, response['n']
end
end
-end
+end
\ No newline at end of file
diff --git a/test/functional/write_concern.rb b/test/functional/write_concern.rb
new file mode 100644
index 0000000000..1fc227440d
--- /dev/null
+++ b/test/functional/write_concern.rb
@@ -0,0 +1,70 @@
+require 'test_helper'
+include Mongo
+
+class WriteConcern < Test::Unit::TestCase
+ context "Write concern propogation: " do
+ setup do
+ @con = standard_connection
+ @db = @con[MONGO_TEST_DB]
+ @col = @db['test-safe']
+ @col.create_index([[:a, 1]], :unique => true)
+ @col.remove
+ end
+
+ #TODO: add write concern tests for remove
+
+ should "propogate write concern options on insert" do
+ @col.insert({:a => 1})
+
+ assert_raise_error(OperationFailure, "duplicate key") do
+ @col.insert({:a => 1})
+ end
+ end
+
+ should "allow write concern override on insert" do
+ @col.insert({:a => 1})
+ @col.insert({:a => 1}, :w => 0)
+ end
+
+ should "propogate write concern option on update" do
+ @col.insert({:a => 1})
+ @col.insert({:a => 2})
+
+ assert_raise_error(OperationFailure, "duplicate key") do
+ @col.update({:a => 2}, {:a => 1})
+ end
+ end
+
+ should "allow write concern override on update" do
+ @col.insert({:a => 1})
+ @col.insert({:a => 2})
+ @col.update({:a => 2}, {:a => 1}, :w => 0)
+ end
+ end
+
+ context "Write concern error objects" do
+ setup do
+ @con = standard_connection
+ @db = @con[MONGO_TEST_DB]
+ @col = @db['test']
+ @col.remove
+ @col.insert({:a => 1})
+ @col.insert({:a => 1})
+ @col.insert({:a => 1})
+ end
+
+ should "return object on update" do
+ response = @col.update({:a => 1}, {"$set" => {:a => 2}},
+ :multi => true)
+
+ assert response['updatedExisting']
+ assert_equal 3, response['n']
+ end
+
+ should "return object on remove" do
+ response = @col.remove({})
+ assert_equal 3, response['n']
+ end
+ end
+
+end
diff --git a/test/replica_set/basic_test.rb b/test/replica_set/basic_test.rb
index f90a444232..e466b56c0e 100644
--- a/test/replica_set/basic_test.rb
+++ b/test/replica_set/basic_test.rb
@@ -30,15 +30,15 @@ def test_connect
def test_safe_option
client = Mongo::ReplSetClient.new(@rs.repl_set_seeds, :name => @rs.repl_set_name)
assert client.connected?
- assert !client.safe
+ assert client.write_concern[:w] > 0
client.close
- client = Mongo::ReplSetClient.new(@rs.repl_set_seeds, :name => @rs.repl_set_name, :safe => false)
+ client = Mongo::ReplSetClient.new(@rs.repl_set_seeds, :name => @rs.repl_set_name, :w => 0)
assert client.connected?
- assert !client.safe
+ assert client.write_concern[:w] < 1
client.close
- client = Mongo::ReplSetClient.new(@rs.repl_set_seeds, :name => @rs.repl_set_name, :safe => true)
+ client = Mongo::ReplSetClient.new(@rs.repl_set_seeds, :name => @rs.repl_set_name, :w => 2)
assert client.connected?
- assert client.safe
+ assert client.write_concern[:w] > 0
client.close
end
@@ -98,11 +98,11 @@ def test_accessors
end
end
- should "close the connection on send_message_with_safe_check for major exceptions" do
+ should "close the connection on send_message_with_acknowledge for major exceptions" do
@client.expects(:checkout_writer).raises(SystemStackError)
@client.expects(:close)
begin
- @coll.insert({:foo => "bar"}, :safe => true)
+ @coll.insert({:foo => "bar"})
rescue SystemStackError
end
end
diff --git a/test/replica_set/connect_test.rb b/test/replica_set/client_test.rb
similarity index 86%
rename from test/replica_set/connect_test.rb
rename to test/replica_set/client_test.rb
index 759170f28e..8f6b2360c0 100644
--- a/test/replica_set/connect_test.rb
+++ b/test/replica_set/client_test.rb
@@ -1,6 +1,6 @@
require 'test_helper'
-class ConnectTest < Test::Unit::TestCase
+class ClientTest < Test::Unit::TestCase
def setup
ensure_cluster(:rs)
@@ -17,7 +17,7 @@ def self.shutdown
end
# To reset after (test) failure
- # $ rm -fr data
+ # rake test:cleanup
def step_down_command
# Adding force=true to avoid 'no secondaries within 10 seconds of my optime' errors
@@ -40,7 +40,7 @@ def test_connect_with_deprecated_multi
[host, @rs.replicas[2].port],
], :name => @rs.repl_set_name)
end
- assert @client.is_a?(ReplSetClient)
+ assert !@client.nil?
assert @client.connected?
end
@@ -70,7 +70,7 @@ def test_connect_with_last_secondary_node_terminated
def test_connect_with_primary_stepped_down
@client = ReplSetClient.new @rs.repl_set_seeds
- @client[MONGO_TEST_DB]['bar'].save({:a => 1}, {:safe => {:w => 3}})
+ @client[MONGO_TEST_DB]['bar'].save({:a => 1}, {:w => 3})
assert @client[MONGO_TEST_DB]['bar'].find_one
primary = Mongo::Client.new(@client.primary_pool.host, @client.primary_pool.port)
@@ -87,7 +87,7 @@ def test_connect_with_primary_stepped_down
def test_connect_with_primary_killed
@client = ReplSetClient.new @rs.repl_set_seeds
assert @client.connected?
- @client[MONGO_TEST_DB]['bar'].save({:a => 1}, {:safe => {:w => 3}})
+ @client[MONGO_TEST_DB]['bar'].save({:a => 1}, {:w => 3})
assert @client[MONGO_TEST_DB]['bar'].find_one
@rs.primary.kill(Signal.list['KILL'])
@@ -107,13 +107,13 @@ def test_save_with_primary_stepped_down
end
rescue_connection_failure do
- @client[MONGO_TEST_DB]['bar'].save({:a => 1}, {:safe => {:w => 3}})
+ @client[MONGO_TEST_DB]['bar'].save({:a => 1}, {:w => 3})
end
end
#def test_connect_with_first_node_removed
# @client = ReplSetClient.new @rs.repl_set_seeds
- # @client[MONGO_TEST_DB]['bar'].save({:a => 1}, {:safe => {:w => 3}})
+ # @client[MONGO_TEST_DB]['bar'].save({:a => 1}, {:w => 3})
#
# old_primary = [@client.primary_pool.host, @client.primary_pool.port]
# old_primary_conn = Mongo::Client.new(*old_primary)
@@ -183,14 +183,14 @@ def test_save_with_primary_stepped_down
def test_connect_with_connection_string
@client = Client.from_uri("mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}?replicaset=#{@rs.repl_set_name}")
- assert @client.is_a?(ReplSetClient)
+ assert !@client.nil?
assert @client.connected?
end
def test_connect_with_connection_string_in_env_var
ENV['MONGODB_URI'] = "mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}?replicaset=#{@rs.repl_set_name}"
@client = ReplSetClient.new
- assert @client.is_a?(ReplSetClient)
+ assert !@client.nil?
assert_equal 2, @client.seeds.length
assert_equal @rs.replicas[0].host, @client.seeds[0][0]
assert_equal @rs.replicas[1].host, @client.seeds[1][0]
@@ -203,7 +203,7 @@ def test_connect_with_connection_string_in_env_var
def test_connect_with_connection_string_in_implicit_mongodb_uri
ENV['MONGODB_URI'] = "mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}?replicaset=#{@rs.repl_set_name}"
@client = Client.from_uri
- assert @client.is_a?(ReplSetClient)
+ assert !@client.nil?
assert_equal 2, @client.seeds.length
assert_equal @rs.replicas[0].host, @client.seeds[0][0]
assert_equal @rs.replicas[1].host, @client.seeds[1][0]
@@ -226,30 +226,30 @@ def test_connect_with_old_seed_format
end
def test_connect_with_full_connection_string
- @client = Client.from_uri("mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}?replicaset=#{@rs.repl_set_name};safe=true;w=2;fsync=true;slaveok=true")
- assert @client.is_a?(ReplSetClient)
+ @client = Client.from_uri("mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}?replicaset=#{@rs.repl_set_name};w=2;fsync=true;slaveok=true")
+ assert !@client.nil?
assert @client.connected?
- assert_equal 2, @client.safe[:w]
- assert @client.safe[:fsync]
+ assert_equal 2, @client.write_concern[:w]
+ assert @client.write_concern[:fsync]
assert @client.read_pool
end
def test_connect_with_full_connection_string_in_env_var
- ENV['MONGODB_URI'] = "mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}?replicaset=#{@rs.repl_set_name};safe=true;w=2;fsync=true;slaveok=true"
+ ENV['MONGODB_URI'] = "mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}?replicaset=#{@rs.repl_set_name};w=2;fsync=true;slaveok=true"
@client = ReplSetClient.new
- assert @client.is_a?(ReplSetClient)
+ assert !@client.nil?
assert @client.connected?
- assert_equal 2, @client.safe[:w]
- assert @client.safe[:fsync]
+ assert_equal 2, @client.write_concern[:w]
+ assert @client.write_concern[:fsync]
assert @client.read_pool
end
def test_connect_options_override_env_var
- ENV['MONGODB_URI'] = "mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}?replicaset=#{@rs.repl_set_name};safe=true;w=2;fsync=true;slaveok=true"
- @client = ReplSetClient.new({:safe => false})
- assert @client.is_a?(ReplSetClient)
+ ENV['MONGODB_URI'] = "mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}?replicaset=#{@rs.repl_set_name};w=2;fsync=true;slaveok=true"
+ @client = ReplSetClient.new({:w => 0})
+ assert !@client.nil?
assert @client.connected?
- assert_equal @client.safe, false
+ assert_equal 0, @client.write_concern[:w]
end
end
diff --git a/test/replica_set/connection_test.rb b/test/replica_set/connection_test.rb
new file mode 100644
index 0000000000..af5886ed1e
--- /dev/null
+++ b/test/replica_set/connection_test.rb
@@ -0,0 +1,255 @@
+require 'test_helper'
+
+class ConnectionTest < Test::Unit::TestCase
+
+ def setup
+ ensure_cluster(:rs)
+ @connection = nil
+ end
+
+ def teardown
+ @connection.close if @connection
+ end
+
+ def self.shutdown
+ @@cluster.stop
+ @@cluster.clobber
+ end
+
+ # To reset after (test) failure
+ # rake test:cleanup
+
+ def step_down_command
+ # Adding force=true to avoid 'no secondaries within 10 seconds of my optime' errors
+ step_down_command = BSON::OrderedHash.new
+ step_down_command[:replSetStepDown] = 60
+ step_down_command[:force] = true
+ step_down_command
+ end
+
+ # TODO: test connect timeout.
+
+ def test_connect_with_deprecated_multi
+ #replica_host_ports = @rs.replicas.collect{|replica| [replica.host, replica.port]}
+ host = @rs.replicas.first.host
+ silently do
+ @connection = Connection.multi([
+ # guaranteed to have one data-holding member
+ [host, @rs.replicas[0].port],
+ [host, @rs.replicas[1].port],
+ [host, @rs.replicas[2].port],
+ ], :name => @rs.repl_set_name)
+ end
+ assert !@connection.nil?
+ assert @connection.connected?
+ end
+
+ def test_connect_bad_name
+ assert_raise_error(ReplicaSetConnectionError, "-wrong") do
+ @connection = ReplSetConnection.new(@rs.repl_set_seeds, :safe => true, :name => @rs.repl_set_name + "-wrong")
+ end
+ end
+
+ def test_connect_with_first_secondary_node_terminated
+ @rs.secondaries.first.stop
+
+ rescue_connection_failure do
+ @connection = ReplSetConnection.new @rs.repl_set_seeds
+ end
+ assert @connection.connected?
+ end
+
+ def test_connect_with_last_secondary_node_terminated
+ @rs.secondaries.last.stop
+
+ rescue_connection_failure do
+ @connection = ReplSetConnection.new @rs.repl_set_seeds
+ end
+ assert @connection.connected?
+ end
+
+ def test_connect_with_primary_stepped_down
+ @connection = ReplSetConnection.new @rs.repl_set_seeds
+ @connection[MONGO_TEST_DB]['bar'].save({:a => 1}, {:safe => {:w => 3}})
+ assert @connection[MONGO_TEST_DB]['bar'].find_one
+
+ primary = Mongo::Connection.new(@connection.primary_pool.host, @connection.primary_pool.port)
+ assert_raise Mongo::ConnectionFailure do
+ primary['admin'].command(step_down_command)
+ end
+ assert @connection.connected?
+
+ rescue_connection_failure do
+ @connection[MONGO_TEST_DB]['bar'].find_one
+ end
+ end
+
+ def test_connect_with_primary_killed
+ @connection = ReplSetConnection.new @rs.repl_set_seeds
+ assert @connection.connected?
+ @connection[MONGO_TEST_DB]['bar'].save({:a => 1}, {:safe => {:w => 3}})
+ assert @connection[MONGO_TEST_DB]['bar'].find_one
+
+ @rs.primary.kill(Signal.list['KILL'])
+
+ rescue_connection_failure do
+ @connection[MONGO_TEST_DB]['bar'].find_one
+ end
+ end
+
+ def test_save_with_primary_stepped_down
+ @connection = ReplSetConnection.new @rs.repl_set_seeds
+ assert @connection.connected?
+
+ primary = Mongo::Connection.new(@connection.primary_pool.host, @connection.primary_pool.port)
+ assert_raise Mongo::ConnectionFailure do
+ primary['admin'].command(step_down_command)
+ end
+
+ rescue_connection_failure do
+ @connection[MONGO_TEST_DB]['bar'].save({:a => 1}, {:safe => {:w => 3}})
+ end
+ end
+
+ #def test_connect_with_first_node_removed
+ # @connection = ReplSetConnection.new @rs.repl_set_seeds
+ # @connection[MONGO_TEST_DB]['bar'].save({:a => 1}, {:safe => {:w => 3}})
+ #
+ # old_primary = [@connection.primary_pool.host, @connection.primary_pool.port]
+ # old_primary_conn = Mongo::Connection.new(*old_primary)
+ # assert_raise Mongo::ConnectionFailure do
+ # old_primary_conn['admin'].command(step_down_command)
+ # end
+ #
+ # # Wait for new primary
+ # rescue_connection_failure do
+ # sleep 1 until @rs.get_node_with_state(1)
+ # end
+ #
+ # new_primary = @rs.get_all_host_pairs_with_state(1).first
+ # new_primary_conn = Mongo::Connection.new(*new_primary)
+ #
+ # config = nil
+ #
+ # # Remove old primary from replset
+ # rescue_connection_failure do
+ # config = @connection['local']['system.replset'].find_one
+ # end
+ #
+ # old_member = config['members'].select {|m| m['host'] == old_primary.join(':')}.first
+ # config['members'].reject! {|m| m['host'] == old_primary.join(':')}
+ # config['version'] += 1
+ #
+ # begin
+ # new_primary_conn['admin'].command({'replSetReconfig' => config})
+ # rescue Mongo::ConnectionFailure
+ # end
+ #
+ # # Wait for the dust to settle
+ # rescue_connection_failure do
+ # assert @connection[MONGO_TEST_DB]['bar'].find_one
+ # end
+ #
+ # # Make sure a new connection skips the old primary
+ # @new_conn = ReplSetConnection.new @rs.repl_set_seeds
+ # @new_conn.connect
+ # new_nodes = [@new_conn.primary] + @new_conn.secondaries
+ # assert !(new_nodes).include?(old_primary)
+ #
+ # # Add the old primary back
+ # config['members'] << old_member
+ # config['version'] += 1
+ #
+ # begin
+ # new_primary_conn['admin'].command({'replSetReconfig' => config})
+ # rescue Mongo::ConnectionFailure
+ # end
+ #end
+
+ #def test_connect_with_hung_first_node
+ # hung_node = nil
+ # begin
+ # hung_node = IO.popen('nc -lk 127.0.0.1 29999 >/dev/null 2>&1')
+ #
+ # @connection = ReplSetConnection.new(['localhost:29999'] + @rs.repl_set_seeds,
+ # :connect_timeout => 2)
+ # @connection.connect
+ # assert ['localhost:29999'] != @connection.primary
+ # assert !@connection.secondaries.include?('localhost:29999')
+ # ensure
+ # Process.kill("KILL", hung_node.pid) if hung_node
+ # end
+ #end
+
+ def test_connect_with_connection_string
+ @connection = Connection.from_uri("mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}?replicaset=#{@rs.repl_set_name}")
+ assert !@connection.nil?
+ assert @connection.connected?
+ end
+
+ def test_connect_with_connection_string_in_env_var
+ ENV['MONGODB_URI'] = "mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}?replicaset=#{@rs.repl_set_name}"
+ @connection = ReplSetConnection.new
+ assert !@connection.nil?
+ assert_equal 2, @connection.seeds.length
+ assert_equal @rs.replicas[0].host, @connection.seeds[0][0]
+ assert_equal @rs.replicas[1].host, @connection.seeds[1][0]
+ assert_equal @rs.replicas[0].port, @connection.seeds[0][1]
+ assert_equal @rs.replicas[1].port, @connection.seeds[1][1]
+ assert_equal @rs.repl_set_name, @connection.replica_set_name
+ assert @connection.connected?
+ end
+
+ def test_connect_with_connection_string_in_implicit_mongodb_uri
+ ENV['MONGODB_URI'] = "mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}?replicaset=#{@rs.repl_set_name}"
+ @connection = Connection.from_uri
+ assert !@connection.nil?
+ assert_equal 2, @connection.seeds.length
+ assert_equal @rs.replicas[0].host, @connection.seeds[0][0]
+ assert_equal @rs.replicas[1].host, @connection.seeds[1][0]
+ assert_equal @rs.replicas[0].port, @connection.seeds[0][1]
+ assert_equal @rs.replicas[1].port, @connection.seeds[1][1]
+ assert_equal @rs.repl_set_name, @connection.replica_set_name
+ assert @connection.connected?
+ end
+
+ def test_connect_with_new_seed_format
+ @connection = ReplSetConnection.new @rs.repl_set_seeds
+ assert @connection.connected?
+ end
+
+ def test_connect_with_old_seed_format
+ silently do
+ @connection = ReplSetConnection.new(@rs.replicas[0].host_port_a, @rs.replicas[1].host_port_a)
+ end
+ assert @connection.connected?
+ end
+
+ def test_connect_with_full_connection_string
+ @connection = Connection.from_uri("mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}?replicaset=#{@rs.repl_set_name};safe=true;w=2;fsync=true;slaveok=true")
+ assert !@connection.nil?
+ assert @connection.connected?
+ assert_equal 2, @connection.write_concern[:w]
+ assert @connection.write_concern[:fsync]
+ assert @connection.read_pool
+ end
+
+ def test_connect_with_full_connection_string_in_env_var
+ ENV['MONGODB_URI'] = "mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}?replicaset=#{@rs.repl_set_name};safe=true;w=2;fsync=true;slaveok=true"
+ @connection = ReplSetConnection.new
+ assert !@connection.nil?
+ assert @connection.connected?
+ assert_equal 2, @connection.write_concern[:w]
+ assert @connection.write_concern[:fsync]
+ assert @connection.read_pool
+ end
+
+ def test_connect_options_override_env_var
+ ENV['MONGODB_URI'] = "mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}?replicaset=#{@rs.repl_set_name};safe=true;w=2;fsync=true;slaveok=true"
+ @connection = ReplSetConnection.new({:safe => {:w => 1}})
+ assert !@connection.nil?
+ assert @connection.connected?
+ assert_equal 1, @connection.write_concern[:w]
+ end
+
+end
diff --git a/test/replica_set/count_test.rb b/test/replica_set/count_test.rb
index 66087fe2bb..c451431ccb 100644
--- a/test/replica_set/count_test.rb
+++ b/test/replica_set/count_test.rb
@@ -22,22 +22,22 @@ def self.shutdown
end
def test_correct_count_after_insertion_reconnect
- @coll.insert({:a => 20}, :safe => {:w => 2, :wtimeout => 10000})
+ @coll.insert({:a => 20}, :w => 2, :wtimeout => 10000)
assert_equal 1, @coll.count
# Kill the current master node
@rs.primary.stop
rescue_connection_failure do
- @coll.insert({:a => 30}, :safe => true)
+ @coll.insert({:a => 30})
end
- @coll.insert({:a => 40}, :safe => true)
+ @coll.insert({:a => 40})
assert_equal 3, @coll.count, "Second count failed"
end
def test_count_command_sent_to_primary
- @coll.insert({:a => 20}, :safe => {:w => 2, :wtimeout => 10000})
+ @coll.insert({:a => 20}, :w => 2, :wtimeout => 10000)
count_before = @primary['admin'].command({:serverStatus => 1})['opcounters']['command']
assert_equal 1, @coll.count
count_after = @primary['admin'].command({:serverStatus => 1})['opcounters']['command']
diff --git a/test/replica_set/cursor_test.rb b/test/replica_set/cursor_test.rb
index e90d4f3f5b..fb08c169d8 100644
--- a/test/replica_set/cursor_test.rb
+++ b/test/replica_set/cursor_test.rb
@@ -34,9 +34,9 @@ def setup_client(read=:primary)
@db.drop_collection("cursor_tests")
@coll = @db.collection("cursor_tests")
- @coll.insert({:a => 1}, :safe => true, :w => 3)
- @coll.insert({:b => 2}, :safe => true, :w => 3)
- @coll.insert({:c => 3}, :safe => true, :w => 3)
+ @coll.insert({:a => 1}, :w => 3)
+ @coll.insert({:b => 2}, :w => 3)
+ @coll.insert({:c => 3}, :w => 3)
# Pin reader
@coll.find_one
diff --git a/test/replica_set/insert_test.rb b/test/replica_set/insert_test.rb
index 12b4f2f884..326228ce21 100644
--- a/test/replica_set/insert_test.rb
+++ b/test/replica_set/insert_test.rb
@@ -20,18 +20,18 @@ def self.shutdown
end
def test_insert
- @coll.save({:a => 20}, :safe => {:w => 2})
+ @coll.save({:a => 20}, :w => 2)
@rs.primary.stop
rescue_connection_failure do
- @coll.save({:a => 30}, :safe => {:w => 2})
+ @coll.save({:a => 30}, :w => 2)
end
- @coll.save({:a => 40}, :safe => {:w => 2})
- @coll.save({:a => 50}, :safe => {:w => 2})
- @coll.save({:a => 60}, :safe => {:w => 2})
- @coll.save({:a => 70}, :safe => {:w => 2})
+ @coll.save({:a => 40}, :w => 2)
+ @coll.save({:a => 50}, :w => 2)
+ @coll.save({:a => 60}, :w => 2)
+ @coll.save({:a => 70}, :w => 2)
# Restart the old master and wait for sync
@rs.start
@@ -45,7 +45,7 @@ def test_insert
end
end
- @coll.save({:a => 80}, :safe => {:w => 2})
+ @coll.save({:a => 80}, :w => 2)
@coll.find.each {|r| results << r}
[20, 30, 40, 50, 60, 70, 80].each do |a|
assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a} on second find"
diff --git a/test/replica_set/old/basic_test.rb b/test/replica_set/old/basic_test.rb
deleted file mode 100644
index d3e322d1b7..0000000000
--- a/test/replica_set/old/basic_test.rb
+++ /dev/null
@@ -1,119 +0,0 @@
-$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-require './test/replica_sets/rs_test_helper'
-
-class BasicTest < Test::Unit::TestCase
-
- def setup
- ensure_rs
- end
-
- def teardown
- @rs.restart_killed_nodes
- @client.close if defined?(@conn) && @conn
- end
-
- def test_connect
- @client = ReplSetClient.new(build_seeds(3), :name => @rs.name)
- assert @client.connected?
-
- assert_equal @rs.primary, @client.primary
- assert_equal @rs.secondaries.sort, @client.secondaries.sort
- assert_equal @rs.arbiters.sort, @client.arbiters.sort
-
- @client = ReplSetClient.new(["#{@rs.host}:#{@rs.ports[1]}","#{@rs.host}:#{@rs.ports[0]}"],
- :name => @rs.name)
- assert @client.connected?
- end
-
- def test_multiple_concurrent_replica_set_connection
- @conn1 = ReplSetClient.new(build_seeds(3), :name => @rs.name)
- @conn2 = ReplSetClient.new(build_seeds(3), :name => @rs.name)
- assert @conn1.connected?
- assert @conn2.connected?
-
- assert @conn1.manager != @conn2.manager
- assert @conn1.local_manager != @conn2.local_manager
- end
-
- def test_cache_original_seed_nodes
- seeds = build_seeds(3) << "#{@rs.host}:19356"
- @client = ReplSetClient.new(seeds, :name => @rs.name)
- assert @client.connected?
- assert @client.seeds.include?([@rs.host, 19356]), "Original seed nodes not cached!"
- assert_equal [@rs.host, 19356], @client.seeds.last, "Original seed nodes not cached!"
- end
-
- def test_accessors
- seeds = build_seeds(3)
- args = {:name => @rs.name}
- @client = ReplSetClient.new(seeds, args)
-
- assert_equal @client.host, @rs.primary[0]
- assert_equal @client.port, @rs.primary[1]
- assert_equal @client.host, @client.primary_pool.host
- assert_equal @client.port, @client.primary_pool.port
- assert_equal 2, @client.secondaries.length
- assert_equal 0, @client.arbiters.length
- assert_equal 2, @client.secondary_pools.length
- assert_equal @rs.name, @client.replica_set_name
- assert @client.secondary_pools.include?(@client.read_pool(:secondary))
- assert_equal 90, @client.refresh_interval
- assert_equal @client.refresh_mode, false
- end
-
- context "Socket pools" do
- context "checking out writers" do
- setup do
- seeds = build_seeds(3)
- args = {:name => @rs.name}
- @con = ReplSetClient.new(seeds, args)
- @coll = @con[MONGO_TEST_DB]['test-connection-exceptions']
- end
-
- should "close the connection on send_message for major exceptions" do
- @con.expects(:checkout_writer).raises(SystemStackError)
- @con.expects(:close)
- begin
- @coll.insert({:foo => "bar"})
- rescue SystemStackError
- end
- end
-
- should "close the connection on send_message_with_safe_check for major exceptions" do
- @con.expects(:checkout_writer).raises(SystemStackError)
- @con.expects(:close)
- begin
- @coll.insert({:foo => "bar"}, :safe => true)
- rescue SystemStackError
- end
- end
-
- should "close the connection on receive_message for major exceptions" do
- @con.expects(:checkout_reader).raises(SystemStackError)
- @con.expects(:close)
- begin
- @coll.find({}, :read => :primary).next
- rescue SystemStackError
- end
- end
- end
-
- context "checking out readers" do
- setup do
- seeds = build_seeds(3)
- args = {:name => @rs.name}
- @con = ReplSetClient.new(seeds, args)
- @coll = @con[MONGO_TEST_DB]['test-connection-exceptions']
- end
-
- should "close the connection on receive_message for major exceptions" do
- @con.expects(:checkout_reader).raises(SystemStackError)
- @con.expects(:close)
- begin
- @coll.find({}, :read => :secondary).next
- rescue SystemStackError
- end
- end
- end
- end
-end
diff --git a/test/replica_set/old/complex_connect_test.rb b/test/replica_set/old/complex_connect_test.rb
deleted file mode 100644
index 7f0b25440e..0000000000
--- a/test/replica_set/old/complex_connect_test.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-require './test/replica_sets/rs_test_helper'
-
-class ComplexConnectTest < Test::Unit::TestCase
-
- def setup
- ensure_rs
- end
-
- def teardown
- @rs.restart_killed_nodes
- @client.close if defined?(@conn) && @conn
- end
-
- def test_complex_connect
- primary = Client.new(@rs.host, @rs.ports[0])
-
- @client = ReplSetClient.new([
- "#{@rs.host}:#{@rs.ports[2]}",
- "#{@rs.host}:#{@rs.ports[1]}",
- "#{@rs.host}:#{@rs.ports[0]}",
- ])
-
- version = @client.server_version
-
- @client['test']['foo'].insert({:a => 1})
- assert @client['test']['foo'].find_one
-
- config = primary['local']['system.replset'].find_one
- config['version'] += 1
- config['members'].delete_if do |member|
- member['host'].include?(@rs.ports[2].to_s)
- end
-
- assert_raise ConnectionFailure do
- primary['admin'].command({:replSetReconfig => config})
- end
- @rs.ensure_up
-
- force_stepdown = BSON::OrderedHash.new
- force_stepdown[:replSetStepDown] = 1
- force_stepdown[:force] = true
-
- assert_raise ConnectionFailure do
- primary['admin'].command(force_stepdown)
- end
-
- # isMaster is currently broken in 2.1+ when called on removed nodes
- if version < "2.1"
- rescue_connection_failure do
- assert @client['test']['foo'].find_one
- end
-
- assert @client['test']['foo'].find_one
- end
- end
-end
diff --git a/test/replica_set/old/complex_read_preference_test.rb b/test/replica_set/old/complex_read_preference_test.rb
deleted file mode 100644
index 1e051150d9..0000000000
--- a/test/replica_set/old/complex_read_preference_test.rb
+++ /dev/null
@@ -1,237 +0,0 @@
-$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-require './test/replica_sets/rs_test_helper'
-require 'logger'
-
-# Tags for members:
-# 0 => {"dc" => "ny", "rack" => "a", "db" => "main"}
-# 1 => {"dc" => "ny", "rack" => "b", "db" => "main"}
-# 2 => {"dc" => "sf", "rack" => "a", "db" => "main"}
-
-class ComplexReadPreferenceTest < Test::Unit::TestCase
- def setup
- ensure_rs
-
- # Insert data
- conn = Client.new(@rs.host, @rs.primary[1])
- db = conn.db(MONGO_TEST_DB)
- coll = db.collection("test-sets")
- coll.save({:a => 20}, :safe => {:w => 2})
- end
-
- def test_primary_with_tags
- # Test specifying a tag set with default read preference of primary throws and error
- conn = make_connection({:tag_sets => {"rack" => "a"}})
- assert_raise_error MongoArgumentError, "Read preferecy :primary cannot be combined with tags" do
- conn.read_pool
- end
- end
-
- def test_tags
- return true if @rs.version < "2.1"
-
- assert_read_pool(:primary, {}, 0)
- assert_read_pool(:primary_preferred, {}, 0)
- assert_read_pool(:secondary, {}, [1,2])
- assert_read_pool(:secondary_preferred, {}, [1,2])
-
- # Test tag_sets are ignored on primary
- assert_read_pool(:primary_preferred,
- {"rack" => "b"}, 0)
-
- # Test single tag
- assert_read_pool(:secondary,
- {"rack" => "a"}, 2)
- assert_read_pool(:secondary,
- {"rack" => "b"}, 1)
- assert_read_pool(:secondary,
- {"db" => "main"}, [1, 2])
-
- # Test multiple tags
- assert_read_pool(:secondary,
- {"db" => "main", "rack" => "a"}, 2)
- assert_read_pool(:secondary,
- {"dc" => "ny", "rack" => "b", "db" => "main"}, 1)
-
- # Test multiple tags failing
- assert_fail_pool(:secondary,
- {"dc" => "ny", "rack" => "a"})
- assert_fail_pool(:secondary,
- {"dc" => "ny", "rack" => "b", "db" => "main", "xtra" => "?"})
-
- # Test symbol is converted to string for key
- assert_read_pool(:secondary,
- {:db => "main", "rack" => "b"}, 1)
- assert_read_pool(:secondary,
- {:db => "main", :rack => "b"}, 1)
- assert_read_pool(:secondary,
- {"db" => "main", :rack => "b"}, 1)
-
- # Test secondary_preferred
- assert_read_pool(:secondary_preferred,
- {"dc" => "ny"}, 1)
- assert_read_pool(:secondary_preferred,
- {"dc" => "sf"}, 2)
- assert_read_pool(:secondary_preferred,
- {"dc" => "china"}, 0)
-
- # Test secondary_preferred with no matching member
- assert_read_pool(:secondary_preferred,
- {"dc" => "bad"}, 0)
- assert_read_pool(:secondary_preferred,
- {"db" => "main", "dc" => "china"}, 0)
- assert_read_pool(:secondary_preferred,
- {"db" => "ny", "rack" => "a"}, 0)
- end
-
- def test_tag_sets
- return true if @rs.version < "2.1"
-
- # Test primary_preferred overrides any tags when primary is available
- assert_read_pool(:primary_preferred, [
- {"dc" => "sf"}
- ], 0)
-
- # Test first tag_set takes priority over the second
- assert_read_pool(:secondary, [
- {"dc" => "sf"},
- {"dc" => "ny"}
- ], 2)
- assert_read_pool(:secondary, [
- {"dc" => "ny"},
- {"dc" => "sf"}
- ], 1)
- assert_read_pool(:secondary_preferred, [
- {"dc" => "sf"},
- {"dc" => "ny"}
- ], 2)
- assert_read_pool(:secondary_preferred, [
- {"dc" => "ny"},
- {"dc" => "sf"}
- ], 1)
-
- # Test tags not matching any member throw an error
- assert_fail_pool(:secondary, [
- {"dc" => "ny", "rack" => "a"},
- {"dc" => "sf", "rack" => "b"},
- ])
-
- # Test bad tags get skipped over
- assert_read_pool(:secondary_preferred, [
- {"bad" => "tag"},
- {"dc" => "sf"}
- ], 2)
-
- # Test less selective tags
- assert_read_pool(:secondary, [
- {"dc" => "ny", "rack" => "b", "db" => "alt"},
- {"dc" => "ny", "rack" => "a"},
- {"dc" => "sf"}
- ], 2)
- assert_read_pool(:secondary_preferred, [
- {"dc" => "ny", "rack" => "b", "db" => "alt"},
- {"dc" => "ny", "rack" => "a"},
- {"dc" => "sf"}
- ], 2)
- assert_read_pool(:secondary_preferred, [
- {"dc" => "ny", "rack" => "a"},
- {"dc" => "sf", "rack" => "b"},
- {"db" => "main"}
- ], [1,2])
-
- # Test secondary preferred gives primary if no tags match
- assert_read_pool(:secondary_preferred, [
- {"dc" => "ny", "rack" => "a"},
- {"dc" => "sf", "rack" => "b"}
- ], 0)
- assert_read_pool(:secondary_preferred, [
- {"dc" => "ny", "rack" => "a"},
- {"dc" => "sf", "rack" => "b"},
- {"dc" => "ny", "rack" => "b"},
- ], 1)
-
- # Basic nearest test
- assert_read_pool(:nearest, [
- {"dc" => "ny", "rack" => "a"},
- {"dc" => "sf", "rack" => "b"},
- {"db" => "main"}
- ], [0,1,2])
- end
-
- def test_nearest
- # Test refresh happens on connection after interval has passed
- conn = make_connection(
- :read => :secondary_preferred,
- :refresh_mode => :sync,
- :refresh_interval => 1,
- :secondary_acceptable_latency_ms => 10
- )
- pools = conn.manager.pools
-
- # Connection should select node with 110 ping every time
- set_pings(pools, [100,110,130])
- sleep(2)
-
- assert conn.read_pool == pools[1]
-
- # Connection should select node with 100 ping every time
- set_pings(pools, [100,120,100])
- sleep(2)
-
- assert conn.read_pool == pools[2]
- end
-
- def test_tags_and_nearest
- return true if @rs.version < "2.1"
-
- # Test connection's read pool matches tags
- assert_read_pool(:secondary_preferred, {"dc" => "sf"}, 2, [100,110,130])
-
- # Test connection's read pool picks near pool (both match tags)
- assert_read_pool(:secondary_preferred, {"db" => "main"}, 1, [100,110,130])
- assert_read_pool(:secondary_preferred, {"db" => "main"}, 2, [100,130,110])
- assert_read_pool(:secondary_preferred, {"db" => "fake"}, 0, [100,130,110])
- end
-
- private
-
- def set_pings(pools, pings)
- pools.sort! { |a,b| a.port <=> b.port }
- pools.each_with_index do |pool, index|
- pool.stubs(:ping_time).returns(pings[index])
- end
- end
-
- def make_connection(opts = {})
- ReplSetClient.new(build_seeds(3), opts)
- end
-
- def assert_read_pool(mode=:primary, tags=[], node_nums=[0], pings=[], latency=10)
- if pings.empty?
- conn = make_connection({:read => mode, :tag_sets => tags})
- else
- conn = make_connection({
- :read => mode,
- :tag_sets => tags,
- :refresh_mode => :sync,
- :refresh_interval => 1,
- :secondary_acceptable_latency_ms => latency
- })
-
- set_pings(conn.manager.pools, pings)
- sleep(2)
- end
-
- assert conn[MONGO_TEST_DB]['test-sets'].find_one
-
- target_ports = [*node_nums].collect {|num| @rs.ports[num]}
-
- assert target_ports.member?(conn.read_pool.port)
- end
-
- def assert_fail_pool(mode=:primary, tags={})
- assert_raise_error ConnectionFailure, "No replica set member available for query " +
- "with read preference matching mode #{mode} and tags matching #{tags}." do
- make_connection({:read => mode, :tag_sets => tags}).read_pool
- end
- end
-end
\ No newline at end of file
diff --git a/test/replica_set/old/connect_test.rb b/test/replica_set/old/connect_test.rb
deleted file mode 100644
index 5d8855245c..0000000000
--- a/test/replica_set/old/connect_test.rb
+++ /dev/null
@@ -1,248 +0,0 @@
-$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-require './test/replica_sets/rs_test_helper'
-
-class ConnectTest < Test::Unit::TestCase
- def setup
- @old_mongodb_uri = ENV['MONGODB_URI']
- ensure_rs
- end
-
- def teardown
- @rs.restart_killed_nodes
- @client.close if defined?(@client) && @client
- ENV['MONGODB_URI'] = @old_mongodb_uri
- end
-
- def step_down_command
- # Adding force=true to avoid 'no secondaries within 10 seconds of my optime' errors
- step_down_command = BSON::OrderedHash.new
- step_down_command[:replSetStepDown] = 60
- step_down_command[:force] = true
- step_down_command
- end
-
- # TODO: test connect timeout.
-
- def test_connect_with_deprecated_multi
- silently do
- @client = Client.multi([[@rs.host, @rs.ports[0]], [@rs.host, @rs.ports[1]]], :name => @rs.name)
- end
- assert @client.is_a?(ReplSetClient)
- assert @client.connected?
- end
-
- def test_connect_bad_name
- assert_raise_error(ReplicaSetConnectionError, "-wrong") do
- @client = ReplSetClient.new(build_seeds(3), :name => @rs.name + "-wrong")
- end
- end
-
- def test_connect_with_secondary_node_terminated
- @rs.kill_secondary
-
- rescue_connection_failure do
- @client = ReplSetClient.new build_seeds(3)
- end
- assert @client.connected?
- end
-
- def test_connect_with_third_node_terminated
- @rs.kill(@rs.get_node_from_port(@rs.ports[2]))
-
- rescue_connection_failure do
- @client = ReplSetClient.new build_seeds(3)
- end
- assert @client.connected?
- end
-
- def test_connect_with_primary_stepped_down
- @client = ReplSetClient.new build_seeds(3)
- @client[MONGO_TEST_DB]['bar'].save({:a => 1}, {:safe => {:w => 3}})
- assert @client[MONGO_TEST_DB]['bar'].find_one
-
- primary = Mongo::Client.new(@client.primary_pool.host, @client.primary_pool.port)
- assert_raise Mongo::ConnectionFailure do
- primary['admin'].command(step_down_command)
- end
- assert @client.connected?
-
- rescue_connection_failure do
- @client[MONGO_TEST_DB]['bar'].find_one
- end
- end
-
- def test_connect_with_primary_killed
- @client = ReplSetClient.new build_seeds(3)
- @client[MONGO_TEST_DB]['bar'].save({:a => 1}, {:safe => {:w => 3}})
- assert @client[MONGO_TEST_DB]['bar'].find_one
-
- @rs.kill_primary(Signal.list['KILL'])
-
- rescue_connection_failure do
- @client[MONGO_TEST_DB]['bar'].find_one
- end
- end
-
- def test_save_with_primary_stepped_down
- @client = ReplSetClient.new build_seeds(3)
-
- primary = Mongo::Client.new(@client.primary_pool.host, @client.primary_pool.port)
- assert_raise Mongo::ConnectionFailure do
- primary['admin'].command(step_down_command)
- end
-
- rescue_connection_failure do
- @client[MONGO_TEST_DB]['bar'].save({:a => 1}, {:safe => {:w => 3}})
- end
- end
-
- def test_save_with_primary_killed
- @client = ReplSetClient.new build_seeds(3)
-
- @rs.kill_primary(Signal.list['KILL'])
-
- rescue_connection_failure do
- @client[MONGO_TEST_DB]['bar'].save({:a => 1}, {:safe => {:w => 2}})
- end
- end
-
- def test_connect_with_first_node_removed
- @client = ReplSetClient.new build_seeds(3)
- @client[MONGO_TEST_DB]['bar'].save({:a => 1}, {:safe => {:w => 3}})
-
- old_primary = [@client.primary_pool.host, @client.primary_pool.port]
- old_primary_conn = Mongo::Client.new(*old_primary)
- assert_raise Mongo::ConnectionFailure do
- old_primary_conn['admin'].command(step_down_command)
- end
-
- # Wait for new primary
- rescue_connection_failure do
- sleep 1 until @rs.get_node_with_state(1)
- end
-
- new_primary = @rs.get_all_host_pairs_with_state(1).first
- new_primary_conn = Mongo::Client.new(*new_primary)
-
- config = nil
-
- # Remove old primary from replset
- rescue_connection_failure do
- config = @client['local']['system.replset'].find_one
- end
-
- old_member = config['members'].select {|m| m['host'] == old_primary.join(':')}.first
- config['members'].reject! {|m| m['host'] == old_primary.join(':')}
- config['version'] += 1
-
- begin
- new_primary_conn['admin'].command({'replSetReconfig' => config})
- rescue Mongo::ConnectionFailure
- end
-
- # Wait for the dust to settle
- rescue_connection_failure do
- assert @client[MONGO_TEST_DB]['bar'].find_one
- end
-
- # Make sure a new connection skips the old primary
- @new_conn = ReplSetClient.new build_seeds(3)
- @new_conn.connect
- new_nodes = [@new_conn.primary] + @new_conn.secondaries
- assert !(new_nodes).include?(old_primary)
-
- # Add the old primary back
- config['members'] << old_member
- config['version'] += 1
-
- begin
- new_primary_conn['admin'].command({'replSetReconfig' => config})
- rescue Mongo::ConnectionFailure
- end
- end
-
- def test_connect_with_hung_first_node
- hung_node = nil
- begin
- hung_node = IO.popen('nc -lk 127.0.0.1 29999 >/dev/null 2>&1')
-
- @client = ReplSetClient.new(['localhost:29999'] + build_seeds(3),
- :connect_timeout => 2)
- @client.connect
- assert ['localhost:29999'] != @client.primary
- assert !@client.secondaries.include?('localhost:29999')
- ensure
- Process.kill("KILL", hung_node.pid) if hung_node
- end
- end
-
- def test_connect_with_connection_string
- @client = Client.from_uri("mongodb://#{@rs.host}:#{@rs.ports[0]},#{@rs.host}:#{@rs.ports[1]}?replicaset=#{@rs.name}")
- assert @client.is_a?(ReplSetClient)
- assert @client.connected?
- end
-
- def test_connect_with_connection_string_in_env_var
- ENV['MONGODB_URI'] = "mongodb://#{@rs.host}:#{@rs.ports[0]},#{@rs.host}:#{@rs.ports[1]}?replicaset=#{@rs.name}"
- @client = ReplSetClient.new
- assert @client.is_a?(ReplSetClient)
- assert_equal 2, @client.seeds.length
- assert_equal @rs.host, @client.seeds[0][0]
- assert_equal @rs.host, @client.seeds[1][0]
- assert_equal @rs.ports[0], @client.seeds[0][1]
- assert_equal @rs.ports[1], @client.seeds[1][1]
- assert @client.connected?
- end
-
- def test_connect_with_connection_string_in_implicit_mongodb_uri
- ENV['MONGODB_URI'] = "mongodb://#{@rs.host}:#{@rs.ports[0]},#{@rs.host}:#{@rs.ports[1]}?replicaset=#{@rs.name}"
- @client = Client.from_uri
- assert @client.is_a?(ReplSetClient)
- assert_equal 2, @client.seeds.length
- assert_equal @rs.host, @client.seeds[0][0]
- assert_equal @rs.host, @client.seeds[1][0]
- assert_equal @rs.ports[0], @client.seeds[0][1]
- assert_equal @rs.ports[1], @client.seeds[1][1]
- assert_equal @rs.name, @client.replica_set_name
- assert @client.connected?
- end
-
- def test_connect_with_new_seed_format
- @client = ReplSetClient.new build_seeds(3)
- assert @client.connected?
- end
-
- def test_connect_with_old_seed_format
- silently do
- @client = ReplSetClient.new([@rs.host, @rs.ports[0]], [@rs.host, @rs.ports[1]], [@rs.host, @rs.ports[2]])
- end
- assert @client.connected?
- end
-
- def test_connect_with_full_connection_string
- @client = Client.from_uri("mongodb://#{@rs.host}:#{@rs.ports[0]},#{@rs.host}:#{@rs.ports[1]}?replicaset=#{@rs.name};safe=true;w=2;fsync=true;slaveok=true")
- assert @client.is_a?(ReplSetClient)
- assert @client.connected?
- assert_equal 2, @client.safe[:w]
- assert @client.safe[:fsync]
- assert @client.read_pool
- end
-
- def test_connect_with_full_connection_string_in_env_var
- 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"
- @client = ReplSetClient.new
- assert @client.is_a?(ReplSetClient)
- assert @client.connected?
- assert_equal 2, @client.safe[:w]
- assert @client.safe[:fsync]
- assert @client.read_pool
- end
-
- def test_connect_options_override_env_var
- 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"
- @client = ReplSetClient.new({:safe => false})
- assert @client.is_a?(ReplSetClient)
- assert @client.connected?
- assert_equal @client.safe, false
- end
-end
diff --git a/test/replica_set/old/count_test.rb b/test/replica_set/old/count_test.rb
deleted file mode 100644
index d79261bd93..0000000000
--- a/test/replica_set/old/count_test.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-require './test/replica_sets/rs_test_helper'
-
-class ReplicaSetCountTest < Test::Unit::TestCase
-
- def setup
- ensure_rs
- @client = ReplSetClient.new(build_seeds(3), :read => :primary_preferred)
- assert @client.primary_pool
- @primary = Client.new(@client.primary_pool.host, @client.primary_pool.port)
- @db = @client.db(MONGO_TEST_DB)
- @db.drop_collection("test-sets")
- @coll = @db.collection("test-sets")
- end
-
- def teardown
- @rs.restart_killed_nodes
- @client.close if @conn
- end
-
- def test_correct_count_after_insertion_reconnect
- @coll.insert({:a => 20}, :safe => {:w => 2, :wtimeout => 10000})
- assert_equal 1, @coll.count
-
- # Kill the current master node
- @node = @rs.kill_primary
-
- rescue_connection_failure do
- @coll.insert({:a => 30}, :safe => true)
- end
-
- @coll.insert({:a => 40}, :safe => true)
- assert_equal 3, @coll.count, "Second count failed"
- end
-
- def test_count_command_sent_to_primary
- @coll.insert({:a => 20}, :safe => {:w => 2, :wtimeout => 10000})
- count_before = @primary['admin'].command({:serverStatus => 1})['opcounters']['command']
- assert_equal 1, @coll.count
- count_after = @primary['admin'].command({:serverStatus => 1})['opcounters']['command']
- assert_equal 2, count_after - count_before
- end
-end
diff --git a/test/replica_set/old/cursor_test.rb b/test/replica_set/old/cursor_test.rb
deleted file mode 100644
index c1269f0988..0000000000
--- a/test/replica_set/old/cursor_test.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-require './test/replica_sets/rs_test_helper'
-
-class ReplicaSetCursorTest < Test::Unit::TestCase
- def setup
- ensure_rs
- end
-
- def test_cursors_get_closed
- setup_client
- assert_cursor_count
- end
-
- def test_cursors_get_closed_secondary
- setup_client(:secondary)
- assert_cursor_count
- end
-
- private
-
- def setup_client(read=:primary)
- # Setup ReplicaSet Client
- @client = Mongo::ReplSetClient.new(
- build_seeds(3),
- :read => read
- )
-
- @db = @client.db(MONGO_TEST_DB)
- @db.drop_collection("cursor_tests")
- @coll = @db.collection("cursor_tests")
-
- @coll.insert({:a => 1}, :safe => true, :w => 3)
- @coll.insert({:b => 2}, :safe => true, :w => 3)
- @coll.insert({:c => 3}, :safe => true, :w => 3)
-
- # Pin reader
- @coll.find_one
-
- # Setup Direct Connections
- @primary = Mongo::Client.new(*@client.manager.primary)
- @read = Mongo::Client.new(*@client.manager.read)
- end
-
- def cursor_count(client)
- client['cursor_tests'].command({:cursorInfo => 1})['totalOpen']
- end
-
- def query_count(client)
- client['admin'].command({:serverStatus => 1})['opcounters']['query']
- end
-
- def assert_cursor_count
- before_primary = cursor_count(@primary)
- before_read = cursor_count(@read)
- before_query = query_count(@read)
-
- @coll.find.limit(2).to_a
- sleep(1)
-
- after_primary = cursor_count(@primary)
- after_read = cursor_count(@read)
- after_query = query_count(@read)
-
- assert_equal before_primary, after_primary
- assert_equal before_read, after_read
- assert_equal 1, after_query - before_query
- end
-
-end
-
diff --git a/test/replica_set/old/insert_test.rb b/test/replica_set/old/insert_test.rb
deleted file mode 100644
index 43cb3742f9..0000000000
--- a/test/replica_set/old/insert_test.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-require './test/replica_sets/rs_test_helper'
-
-class ReplicaSetInsertTest < Test::Unit::TestCase
-
- def setup
- ensure_rs
- @client = ReplSetClient.new build_seeds(3)
- @db = @client.db(MONGO_TEST_DB)
- @db.drop_collection("test-sets")
- @coll = @db.collection("test-sets")
- end
-
- def teardown
- @rs.restart_killed_nodes
- @client.close if @conn
- end
-
- def test_insert
- @coll.save({:a => 20}, :safe => {:w => 2})
-
- @rs.kill_primary
-
- rescue_connection_failure do
- @coll.save({:a => 30}, :safe => {:w => 2})
- end
-
- @coll.save({:a => 40}, :safe => {:w => 2})
- @coll.save({:a => 50}, :safe => {:w => 2})
- @coll.save({:a => 60}, :safe => {:w => 2})
- @coll.save({:a => 70}, :safe => {:w => 2})
-
- # Restart the old master and wait for sync
- @rs.restart_killed_nodes
- sleep(5)
- results = []
-
- rescue_connection_failure do
- @coll.find.each {|r| results << r}
- [20, 30, 40, 50, 60, 70].each do |a|
- assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
- end
- end
-
- @coll.save({:a => 80}, :safe => {:w => 2})
- @coll.find.each {|r| results << r}
- [20, 30, 40, 50, 60, 70, 80].each do |a|
- assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a} on second find"
- end
- end
-
-end
diff --git a/test/replica_set/old/pooled_insert_test.rb b/test/replica_set/old/pooled_insert_test.rb
deleted file mode 100644
index f16c49dcfe..0000000000
--- a/test/replica_set/old/pooled_insert_test.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-require './test/replica_sets/rs_test_helper'
-
-# NOTE: This test expects a replica set of three nodes to be running
-# on the local host.
-class ReplicaSetPooledInsertTest < Test::Unit::TestCase
-
- def setup
- ensure_rs
- @client = ReplSetClient.new(build_seeds(3), :pool_size => 10, :pool_timeout => 5, :refresh_mode => false)
- @db = @client.db(MONGO_TEST_DB)
- @db.drop_collection("test-sets")
- @coll = @db.collection("test-sets")
- end
-
- def teardown
- @rs.restart_killed_nodes
- @client.close if @conn
- end
-
- def test_insert
- expected_results = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
- @coll.save({:a => -1}, :safe => {:w => 2})
-
- @rs.kill_primary
-
- threads = []
- 10.times do |i|
- threads[i] = Thread.new do
- rescue_connection_failure do
- @coll.save({:a => i}, :safe => {:w => 2})
- end
- end
- end
-
- threads.each {|t| t.join}
-
- # Restart the old master and wait for sync
- @rs.restart_killed_nodes
- sleep(5)
- results = []
-
- rescue_connection_failure do
- @coll.find.each {|r| results << r}
- expected_results.each do |a|
- assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
- end
- end
-
- @coll.save({:a => 10}, :safe => {:w => 2})
- @coll.find.each {|r| results << r}
- (expected_results + [10]).each do |a|
- assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a} on second find"
- end
- end
-
-end
diff --git a/test/replica_set/old/query_test.rb b/test/replica_set/old/query_test.rb
deleted file mode 100644
index 77dbb8b369..0000000000
--- a/test/replica_set/old/query_test.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-require './test/replica_sets/rs_test_helper'
-
-class ReplicaSetQueryTest < Test::Unit::TestCase
-
- def setup
- ensure_rs
- @client = ReplSetClient.new build_seeds(1)
- @db = @client.db(MONGO_TEST_DB)
- @db.drop_collection("test-sets")
- @coll = @db.collection("test-sets")
- end
-
- def teardown
- @rs.restart_killed_nodes
- @client.close if @conn
- end
-
- def test_query
- @coll.save({:a => 20}, :safe => {:w => 3})
- @coll.save({:a => 30}, :safe => {:w => 3})
- @coll.save({:a => 40}, :safe => {:w => 3})
- results = []
- @coll.find.each {|r| results << r}
- [20, 30, 40].each do |a|
- assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
- end
-
- #puts "Benchmark before failover: #{benchmark_queries}"
-
- @rs.kill_primary
-
- results = []
- rescue_connection_failure do
- @coll.find.each {|r| results << r}
- [20, 30, 40].each do |a|
- assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
- end
-
- #puts "Benchmark after failover: #{benchmark_queries}"
- end
- end
-
- def benchmark_queries
- t1 = Time.now
- 10000.times { @coll.find_one }
- Time.now - t1
- end
-
-end
diff --git a/test/replica_set/old/read_preference_test.rb b/test/replica_set/old/read_preference_test.rb
deleted file mode 100644
index f66a8c6b7b..0000000000
--- a/test/replica_set/old/read_preference_test.rb
+++ /dev/null
@@ -1,240 +0,0 @@
-$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-require './test/replica_sets/rs_test_helper'
-require 'logger'
-
-class ReadPreferenceTest < Test::Unit::TestCase
-
- def setup
- ensure_rs(:secondary_count => 1, :arbiter_count => 1)
-
- # Insert data
- conn = Client.new(@rs.host, @rs.primary[1])
- db = conn.db(MONGO_TEST_DB)
- coll = db.collection("test-sets")
- coll.save({:a => 20}, :safe => {:w => 2})
- end
-
- def test_read_primary
- conn = make_connection
- rescue_connection_failure do
- assert conn.read_primary?
- assert conn.primary?
- end
-
- conn = make_connection(:primary_preferred)
- rescue_connection_failure do
- assert conn.read_primary?
- assert conn.primary?
- end
-
- conn = make_connection(:secondary)
- rescue_connection_failure do
- assert !conn.read_primary?
- assert !conn.primary?
- end
-
- conn = make_connection(:secondary_preferred)
- rescue_connection_failure do
- assert !conn.read_primary?
- assert !conn.primary?
- end
- end
-
- def test_read_secondary_then_primary
- conn = make_connection
- conn[MONGO_TEST_DB]['test-sets'].find_one({}, {:read => :secondary})
- assert conn[MONGO_TEST_DB]['test-sets'].find_one
- end
-
- def test_connection_pools
- conn = make_connection
- assert conn.primary_pool, "No primary pool!"
- assert conn.read_pool, "No read pool!"
- assert conn.primary_pool.port == conn.read_pool.port,
- "Primary port and read port are not the same!"
-
- conn = make_connection(:primary_preferred)
- assert conn.primary_pool, "No primary pool!"
- assert conn.read_pool, "No read pool!"
- assert conn.primary_pool.port == conn.read_pool.port,
- "Primary port and read port are not the same!"
-
- conn = make_connection(:secondary)
- assert conn.primary_pool, "No primary pool!"
- assert conn.read_pool, "No read pool!"
- assert conn.primary_pool.port != conn.read_pool.port,
- "Primary port and read port are the same!"
-
- conn = make_connection(:secondary_preferred)
- assert conn.primary_pool, "No primary pool!"
- assert conn.read_pool, "No read pool!"
- assert conn.primary_pool.port != conn.read_pool.port,
- "Primary port and read port are the same!"
- end
-
- def test_read_routing
- prepare_routing_test
-
- # Test that reads are going to the right members
- assert_query_route(@primary, @primary_direct)
- assert_query_route(@primary_preferred, @primary_direct)
- assert_query_route(@secondary, @secondary_direct)
- assert_query_route(@secondary_preferred, @secondary_direct)
- end
-
- def test_read_routing_with_primary_down
- prepare_routing_test
-
- # Test that reads are going to the right members
- assert_query_route(@primary, @primary_direct)
- assert_query_route(@primary_preferred, @primary_direct)
- assert_query_route(@secondary, @secondary_direct)
- assert_query_route(@secondary_preferred, @secondary_direct)
-
- # Kill the primary so only a single secondary exists
- @rs.kill_primary
-
- # Test that reads are going to the right members
- assert_raise_error ConnectionFailure do
- @primary[MONGO_TEST_DB]['test-sets'].find_one
- end
- assert_query_route(@primary_preferred, @secondary_direct)
- assert_query_route(@secondary, @secondary_direct)
- assert_query_route(@secondary_preferred, @secondary_direct)
-
- # Restore set
- @rs.restart_killed_nodes
- sleep(1)
- @repl_cons.each { |con| con.refresh }
- sleep(1)
- @primary_direct = Client.new(
- @rs.host,
- @primary.read_pool.port
- )
-
- # Test that reads are going to the right members
- assert_query_route(@primary, @primary_direct)
- assert_query_route(@primary_preferred, @primary_direct)
- assert_query_route(@secondary, @secondary_direct)
- assert_query_route(@secondary_preferred, @secondary_direct)
- end
-
- def test_read_routing_with_secondary_down
- prepare_routing_test
-
- # Test that reads are going to the right members
- assert_query_route(@primary, @primary_direct)
- assert_query_route(@primary_preferred, @primary_direct)
- assert_query_route(@secondary, @secondary_direct)
- assert_query_route(@secondary_preferred, @secondary_direct)
-
- # Kill the secondary so that only primary exists
- @rs.kill_secondary
-
- # Test that reads are going to the right members
- assert_query_route(@primary, @primary_direct)
- assert_query_route(@primary_preferred, @primary_direct)
- assert_raise_error ConnectionFailure do
- @secondary[MONGO_TEST_DB]['test-sets'].find_one
- end
- assert_query_route(@secondary_preferred, @primary_direct)
-
- # Restore set
- @rs.restart_killed_nodes
- sleep(1)
- @repl_cons.each { |con| con.refresh }
- sleep(1)
- @secondary_direct = Client.new(
- @rs.host,
- @secondary.read_pool.port,
- :slave_ok => true
- )
-
- # Test that reads are going to the right members
- assert_query_route(@primary, @primary_direct)
- assert_query_route(@primary_preferred, @primary_direct)
- assert_query_route(@secondary, @secondary_direct)
- assert_query_route(@secondary_preferred, @secondary_direct)
- end
-
- def test_write_conecern
- @client = make_connection(:secondary_preferred)
- @db = @client[MONGO_TEST_DB]
- @coll = @db.collection("test-sets", :safe => {
- :w => 2, :wtimeout => 20000
- })
- @coll.save({:a => 20})
- @coll.save({:a => 30})
- @coll.save({:a => 40})
-
- # pin the read pool
- @coll.find_one
- @secondary = Client.new(@rs.host, @client.read_pool.port, :slave_ok => true)
-
- results = []
- @coll.find.each {|r| results << r["a"]}
-
- assert results.include?(20)
- assert results.include?(30)
- assert results.include?(40)
-
- @rs.kill_primary
-
- results = []
- rescue_connection_failure do
- @coll.find.each {|r| results << r}
- [20, 30, 40].each do |a|
- assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
- end
- end
- @rs.restart_killed_nodes
- end
-
- def test_write_lots_of_data
- @client = make_connection(:secondary_preferred)
- @db = @client[MONGO_TEST_DB]
- @coll = @db.collection("test-sets", {:safe => {:w => 2}})
-
- 6000.times do |n|
- @coll.save({:a => n})
- end
-
- cursor = @coll.find()
- cursor.next
- cursor.close
- end
-
- private
-
- def prepare_routing_test
- # Setup replica set connections
- @primary = make_connection(:primary)
- @primary_preferred = make_connection(:primary_preferred)
- @secondary = make_connection(:secondary)
- @secondary_preferred = make_connection(:secondary_preferred)
- @repl_cons = [@primary, @primary_preferred, @secondary, @secondary_preferred]
-
- # Setup direct connections
- @primary_direct = Client.new(@rs.host, @primary.read_pool.port)
- @secondary_direct = Client.new(@rs.host, @secondary.read_pool.port, :slave_ok => true)
- end
-
- def make_connection(mode = :primary, opts = {})
- opts.merge!({:read => mode})
- ReplSetClient.new(build_seeds(3), opts)
- end
-
- def query_count(connection)
- connection['admin'].command({:serverStatus => 1})['opcounters']['query']
- end
-
- def assert_query_route(test_connection, expected_target)
- #puts "#{test_connection.read_pool.port} #{expected_target.read_pool.port}"
- queries_before = query_count(expected_target)
- assert_nothing_raised do
- test_connection['MONGO_TEST_DB']['test-sets'].find_one
- end
- queries_after = query_count(expected_target)
- assert_equal 1, queries_after - queries_before
- end
-end
diff --git a/test/replica_set/old/refresh_test.rb b/test/replica_set/old/refresh_test.rb
deleted file mode 100644
index 85a8f908c7..0000000000
--- a/test/replica_set/old/refresh_test.rb
+++ /dev/null
@@ -1,156 +0,0 @@
-$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-require './test/replica_sets/rs_test_helper'
-require 'benchmark'
-
-class ReplicaSetRefreshTest < Test::Unit::TestCase
-
- def setup
- ensure_rs
- end
-
- def teardown
- @rs.restart_killed_nodes
- @client.close if defined?(@conn)
- end
-
-=begin
- def test_connect_speed
- Benchmark.bm do |x|
- x.report("Connect") do
- 10.times do
- ReplSetClient.new(build_seeds(3), :refresh_mode => false)
- end
- end
-
- @con = ReplSetClient.new(build_seeds(3), :refresh_mode => false)
-
- x.report("manager") do
- man = Mongo::PoolManager.new(@con, @con.seeds)
- 10.times do
- man.connect
- end
- end
- end
- end
-=end
-
- def test_connect_and_manual_refresh_with_secondaries_down
- @rs.kill_all_secondaries
- sleep(4)
-
- rescue_connection_failure do
- @client = ReplSetClient.new(build_seeds(3), :refresh_mode => false)
- end
-
- assert_equal [], @client.secondaries
- assert @client.connected?
- assert_equal @client.read_pool, @client.primary_pool
-
- # Refresh with no change to set
- @client.refresh
- assert_equal [], @client.secondaries
- assert @client.connected?
- assert_equal @client.read_pool, @client.primary_pool
-
- @rs.restart_killed_nodes
- assert_equal [], @client.secondaries
- assert @client.connected?
- assert_equal @client.read_pool, @client.primary_pool
-
- # Refresh with everything up
- @client.refresh
- assert @client.read_pool
- assert @client.secondaries.length > 0
- end
-
- def test_automated_refresh_with_secondaries_down
- @rs.kill_all_secondaries
- sleep(4)
-
- rescue_connection_failure do
- @client = ReplSetClient.new(build_seeds(3),
- :refresh_interval => 2, :refresh_mode => :sync, :read => :secondary_preferred)
- end
-
- assert_equal [], @client.secondaries
- assert @client.connected?
- assert_equal @client.manager.read, @client.manager.primary
- old_refresh_version = @client.refresh_version
-
- @rs.restart_killed_nodes
- sleep(4)
- @client['foo']['bar'].find_one
- @client['foo']['bar'].insert({:a => 1})
-
- assert @client.refresh_version > old_refresh_version,
- "Refresh version hasn't changed."
- assert @client.secondaries.length > 0,
- "No secondaries have been added."
- assert @client.manager.read != @client.manager.primary,
- "Read pool and primary pool are identical."
- end
-
- def test_automated_refresh_when_secondary_goes_down
- @client = ReplSetClient.new(build_seeds(3),
- :refresh_interval => 2, :refresh_mode => :sync)
-
- num_secondaries = @client.secondary_pools.length
- old_refresh_version = @client.refresh_version
-
- @rs.kill_secondary
- sleep(4)
- @client['foo']['bar'].find_one
-
- assert @client.refresh_version > old_refresh_version,
- "Refresh version hasn't changed."
- assert_equal num_secondaries - 1, @client.secondaries.length
- assert_equal num_secondaries - 1, @client.secondary_pools.length
-
- @rs.restart_killed_nodes
- end
-
- def test_automated_refresh_with_removed_node
- @client = ReplSetClient.new(build_seeds(3),
- :refresh_interval => 2, :refresh_mode => :sync)
-
- num_secondaries = @client.secondary_pools.length
- old_refresh_version = @client.refresh_version
-
- n = @rs.remove_secondary_node
- sleep(4)
- @client['foo']['bar'].find_one
-
- assert @client.refresh_version > old_refresh_version,
- "Refresh version hasn't changed."
- assert_equal num_secondaries - 1, @client.secondaries.length
- assert_equal num_secondaries - 1, @client.secondary_pools.length
-
- @rs.add_node(n)
- end
-
- def test_adding_and_removing_nodes
- @client = ReplSetClient.new(build_seeds(3),
- :refresh_interval => 2, :refresh_mode => :sync)
-
- @rs.add_node
- sleep(4)
- @client['foo']['bar'].find_one
-
- @conn2 = ReplSetClient.new(build_seeds(3),
- :refresh_interval => 2, :refresh_mode => :sync)
-
- assert @conn2.secondaries.sort == @client.secondaries.sort,
- "Second connection secondaries not equal to first."
- assert_equal 3, @client.secondary_pools.length
- assert_equal 3, @client.secondaries.length
-
- config = @client['admin'].command({:ismaster => 1})
-
- @rs.remove_secondary_node
- sleep(4)
- config = @client['admin'].command({:ismaster => 1})
-
- assert_equal 2, @client.secondary_pools.length
- assert_equal 2, @client.secondaries.length
- end
-end
diff --git a/test/replica_set/old/refresh_with_threads_test.rb b/test/replica_set/old/refresh_with_threads_test.rb
deleted file mode 100644
index 76b7db6d0d..0000000000
--- a/test/replica_set/old/refresh_with_threads_test.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-require './test/replica_sets/rs_test_helper'
-require 'benchmark'
-
-class ReplicaSetRefreshWithThreadsTest < Test::Unit::TestCase
-
- def setup
- ensure_rs
- @client = nil
- end
-
- def teardown
- @client.close if @conn
- end
-
- def test_read_write_load_with_added_nodes
- # MongoDB < 2.0 will disconnect clients on rs.reconfig()
- return true if @rs.version < "2"
-
- seeds = build_seeds(3)
- args = {
- :refresh_interval => 5,
- :refresh_mode => :sync,
- :read => :secondary_preferred
- }
- @client = ReplSetClient.new(seeds, args)
- @duplicate = @client[MONGO_TEST_DB]['duplicate']
- @unique = @client[MONGO_TEST_DB]['unique']
- @duplicate.insert("test" => "insert")
- @duplicate.insert("test" => "update")
- @unique.insert("test" => "insert")
- @unique.insert("test" => "update")
- @unique.create_index("test", :unique => true)
-
- threads = []
- 10.times do
- threads << Thread.new do
- 1000.times do |i|
- if i % 2 == 0
- assert_raise Mongo::OperationFailure do
- @unique.insert({"test" => "insert"}, :safe => true)
- end
- else
- @duplicate.insert({"test" => "insert"}, :safe => true)
- end
- end
- end
- end
-
- @rs.add_node
- threads.each {|t| t.join }
-
- sleep(1)
-
- @client['admin'].command({:ismaster => 1})
-
- assert_equal 3, @client.secondary_pools.length
- assert_equal 3, @client.secondaries.length
- end
-end
diff --git a/test/replica_set/old/replication_ack_test.rb b/test/replica_set/old/replication_ack_test.rb
deleted file mode 100644
index e2ea003b43..0000000000
--- a/test/replica_set/old/replication_ack_test.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-require './test/replica_sets/rs_test_helper'
-
-class ReplicaSetAckTest < Test::Unit::TestCase
-
- def setup
- ensure_rs
- @client = ReplSetClient.new(build_seeds(1))
-
- @slave1 = Client.new(@client.secondary_pools[0].host,
- @client.secondary_pools[0].port, :slave_ok => true)
-
- assert !@slave1.read_primary?
-
- @db = @client.db(MONGO_TEST_DB)
- @db.drop_collection("test-sets")
- @col = @db.collection("test-sets")
- end
-
- def teardown
- @rs.restart_killed_nodes
- @client.close if @conn
- end
-
- def test_safe_mode_with_w_failure
- assert_raise_error OperationFailure, "timeout" do
- @col.insert({:foo => 1}, :safe => {:w => 4, :wtimeout => 1, :fsync => true})
- end
- assert_raise_error OperationFailure, "timeout" do
- @col.update({:foo => 1}, {:foo => 2}, :safe => {:w => 4, :wtimeout => 1, :fsync => true})
- end
- assert_raise_error OperationFailure, "timeout" do
- @col.remove({:foo => 2}, :safe => {:w => 4, :wtimeout => 1, :fsync => true})
- end
- end
-
- def test_safe_mode_replication_ack
- @col.insert({:baz => "bar"}, :safe => {:w => 3, :wtimeout => 5000})
-
- assert @col.insert({:foo => "0" * 5000}, :safe => {:w => 3, :wtimeout => 5000})
- assert_equal 2, @slave1[MONGO_TEST_DB]["test-sets"].count
-
- assert @col.update({:baz => "bar"}, {:baz => "foo"}, :safe => {:w => 3, :wtimeout => 5000})
- assert @slave1[MONGO_TEST_DB]["test-sets"].find_one({:baz => "foo"})
-
- assert @col.remove({}, :safe => {:w => 3, :wtimeout => 5000})
- assert_equal 0, @slave1[MONGO_TEST_DB]["test-sets"].count
- end
-
- def test_last_error_responses
- 20.times { @col.insert({:baz => "bar"}) }
- response = @db.get_last_error(:w => 2, :wtimeout => 5000)
- assert response['ok'] == 1
- assert response['lastOp']
-
- @col.update({}, {:baz => "foo"}, :multi => true)
- response = @db.get_last_error(:w => 2, :wtimeout => 5000)
- assert response['ok'] == 1
- assert response['lastOp']
-
- @col.remove({})
- response = @db.get_last_error(:w => 2, :wtimeout => 5000)
- assert response['ok'] == 1
- assert response['n'] == 20
- assert response['lastOp']
- end
-
-end
diff --git a/test/replica_set/old/rs_test_helper.rb b/test/replica_set/old/rs_test_helper.rb
deleted file mode 100644
index bce1ea3112..0000000000
--- a/test/replica_set/old/rs_test_helper.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-require File.expand_path("../../test_helper", __FILE__)
-require './test/tools/repl_set_manager'
-
-class Test::Unit::TestCase
- # Ensure replica set is available as an instance variable and that
- # a new set is spun up for each TestCase class
- def ensure_rs(opts={})
- unless defined?(@@current_class) and @@current_class == self.class
- @@current_class = self.class
- @@rs = ReplSetManager.new(opts)
- @@rs.start_set
- end
- @rs = @@rs
- end
-
- # Generic code for rescuing connection failures and retrying operations.
- # This could be combined with some timeout functionality.
- def rescue_connection_failure(max_retries=30)
- retries = 0
- begin
- yield
- rescue Mongo::ConnectionFailure => ex
- #puts "Rescue attempt #{retries}: from #{ex}"
- retries += 1
- raise ex if retries > max_retries
- sleep(2)
- retry
- end
- end
-
- def build_seeds(num_hosts)
- seeds = []
- num_hosts.times do |n|
- seeds << "#{@rs.host}:#{@rs.ports[n]}"
- end
- seeds
- end
-end
diff --git a/test/replica_set/query_test.rb b/test/replica_set/query_test.rb
index be0e4c7085..85bf5240e2 100644
--- a/test/replica_set/query_test.rb
+++ b/test/replica_set/query_test.rb
@@ -20,9 +20,9 @@ def self.shutdown
end
def test_query
- @coll.save({:a => 20}, :safe => {:w => 3})
- @coll.save({:a => 30}, :safe => {:w => 3})
- @coll.save({:a => 40}, :safe => {:w => 3})
+ @coll.save({:a => 20}, :w => 3)
+ @coll.save({:a => 30}, :w => 3)
+ @coll.save({:a => 40}, :w => 3)
results = []
@coll.find.each {|r| results << r}
[20, 30, 40].each do |a|
diff --git a/test/replica_set/replication_ack_test.rb b/test/replica_set/replication_ack_test.rb
index 0dcc2f3be2..4f8713c130 100644
--- a/test/replica_set/replication_ack_test.rb
+++ b/test/replica_set/replication_ack_test.rb
@@ -6,7 +6,8 @@ def setup
ensure_cluster(:rs)
@client = ReplSetClient.new(@rs.repl_set_seeds)
- @slave1 = Client.new(@client.secondary_pools[0].host,
+ @slave1 = Client.new(
+ @client.secondary_pools[0].host,
@client.secondary_pools[0].port, :slave_ok => true)
assert !@slave1.read_primary?
@@ -27,26 +28,26 @@ def self.shutdown
def test_safe_mode_with_w_failure
assert_raise_error OperationFailure, "timeout" do
- @col.insert({:foo => 1}, :safe => {:w => 4, :wtimeout => 1, :fsync => true})
+ @col.insert({:foo => 1}, :w => 4, :wtimeout => 1, :fsync => true)
end
assert_raise_error OperationFailure, "timeout" do
- @col.update({:foo => 1}, {:foo => 2}, :safe => {:w => 4, :wtimeout => 1, :fsync => true})
+ @col.update({:foo => 1}, {:foo => 2}, :w => 4, :wtimeout => 1, :fsync => true)
end
assert_raise_error OperationFailure, "timeout" do
- @col.remove({:foo => 2}, :safe => {:w => 4, :wtimeout => 1, :fsync => true})
+ @col.remove({:foo => 2}, :w => 4, :wtimeout => 1, :fsync => true)
end
end
def test_safe_mode_replication_ack
- @col.insert({:baz => "bar"}, :safe => {:w => 3, :wtimeout => 5000})
+ @col.insert({:baz => "bar"}, :w => 3, :wtimeout => 5000)
- assert @col.insert({:foo => "0" * 5000}, :safe => {:w => 3, :wtimeout => 5000})
+ assert @col.insert({:foo => "0" * 5000}, :w => 3, :wtimeout => 5000)
assert_equal 2, @slave1[MONGO_TEST_DB]["test-sets"].count
- assert @col.update({:baz => "bar"}, {:baz => "foo"}, :safe => {:w => 3, :wtimeout => 5000})
+ assert @col.update({:baz => "bar"}, {:baz => "foo"}, :w => 3, :wtimeout => 5000)
assert @slave1[MONGO_TEST_DB]["test-sets"].find_one({:baz => "foo"})
- assert @col.remove({}, :safe => {:w => 3, :wtimeout => 5000})
+ assert @col.remove({}, :w => 3, :wtimeout => 5000)
assert_equal 0, @slave1[MONGO_TEST_DB]["test-sets"].count
end
@@ -56,7 +57,7 @@ def test_last_error_responses
assert response['ok'] == 1
assert response['lastOp']
- @col.update({}, {:baz => "foo"}, :multi => true)
+ @col.update({}, {:baz => "foo"})
response = @db.get_last_error(:w => 2, :wtimeout => 5000)
assert response['ok'] == 1
assert response['lastOp']
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 81509e78c4..391220d3f5 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -92,12 +92,16 @@ class Test::Unit::TestCase
include Mongo
include BSON
- def self.standard_connection(options={})
- Client.new(TEST_HOST, TEST_PORT, options)
+ def self.standard_connection(options={}, legacy=false)
+ if legacy
+ Connection.new(TEST_HOST, TEST_PORT, options)
+ else
+ Client.new(TEST_HOST, TEST_PORT, options)
+ end
end
- def standard_connection(options={})
- self.class.standard_connection(options)
+ def standard_connection(options={}, legacy=false)
+ self.class.standard_connection(options, legacy)
end
def self.host_port
diff --git a/test/unit/client_test.rb b/test/unit/client_test.rb
new file mode 100644
index 0000000000..830b9072a6
--- /dev/null
+++ b/test/unit/client_test.rb
@@ -0,0 +1,230 @@
+require 'test_helper'
+include Mongo
+
+class ClientTest < Test::Unit::TestCase
+ context "Mongo::Client intialization " do
+ context "given a single node" do
+ setup do
+ @client = Client.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})
+ @client.expects(:[]).with('admin').returns(admin_db)
+ @client.connect
+ end
+
+ should "acknowledge writes by default" do
+ assert_equal 1, @client.write_concern[:w]
+ end
+
+ should "set localhost and port to master" do
+ assert_equal 'localhost', @client.primary_pool.host
+ assert_equal 27017, @client.primary_pool.port
+ end
+
+ should "set connection pool to 1" do
+ assert_equal 1, @client.primary_pool.size
+ end
+
+ should "default slave_ok to false" do
+ assert !@client.slave_ok?
+ end
+
+ should "raise exception for invalid host or port" do
+ assert_raise MongoArgumentError do
+ Client.new(:w => 1)
+ end
+ assert_raise MongoArgumentError do
+ Client.new('localhost', :w => 1)
+ end
+ end
+
+ should "warn if invalid options are specified" do
+ client = Client.allocate
+ opts = {:connect => false}
+
+ ReplSetClient::REPL_SET_OPTS.each do |opt|
+ client.expects(:warn).with("#{opt} is not a valid option for #{client.class}")
+ opts[opt] = true
+ end
+
+ args = ['localhost', 27017, opts]
+ client.send(:initialize, *args)
+ end
+
+ context "given a replica set" do
+
+ should "warn if invalid options are specified" do
+ client = ReplSetClient.allocate
+ opts = {:connect => false}
+
+ Client::CLIENT_ONLY_OPTS.each do |opt|
+ client.expects(:warn).with("#{opt} is not a valid option for #{client.class}")
+ opts[opt] = true
+ end
+
+ args = [['localhost:27017'], opts]
+ client.send(:initialize, *args)
+ end
+ end
+ end
+
+ context "initializing with a mongodb uri" do
+ should "parse a simple uri" do
+ @client = Client.from_uri("mongodb://localhost", :connect => false)
+ assert_equal ['localhost', 27017], @client.host_to_try
+ end
+
+ should "allow a complex host names" do
+ host_name = "foo.bar-12345.org"
+ @client = Client.from_uri("mongodb://#{host_name}", :connect => false)
+ assert_equal [host_name, 27017], @client.host_to_try
+ end
+
+ should "allow db without username and password" do
+ host_name = "foo.bar-12345.org"
+ @client = Client.from_uri("mongodb://#{host_name}/foo", :connect => false)
+ assert_equal [host_name, 27017], @client.host_to_try
+ end
+
+ should "set write concern options on connection" do
+ host_name = "localhost"
+ opts = "w=2&wtimeoutMS=1000&fsync=true&journal=true"
+ @client = Client.from_uri("mongodb://#{host_name}/foo?#{opts}", :connect => false)
+ assert_equal({:w => 2, :wtimeout => 1000, :fsync => true, :j => true}, @client.write_concern)
+ end
+
+ should "set timeout options on connection" do
+ host_name = "localhost"
+ opts = "connectTimeoutMS=1000&socketTimeoutMS=5000"
+ @client = Client.from_uri("mongodb://#{host_name}/foo?#{opts}", :connect => false)
+ assert_equal 1, @client.connect_timeout
+ assert_equal 5, @client.op_timeout
+ end
+
+ should "parse a uri with a hyphen & underscore in the username or password" do
+ @client = Client.from_uri("mongodb://hyphen-user_name:p-s_s@localhost:27017/db", :connect => false)
+ assert_equal ['localhost', 27017], @client.host_to_try
+ auth_hash = { 'db_name' => 'db', 'username' => 'hyphen-user_name', "password" => 'p-s_s' }
+ assert_equal auth_hash, @client.auths[0]
+ end
+
+ should "attempt to connect" do
+ TCPSocket.stubs(:new).returns(new_mock_socket)
+ @client = Client.from_uri("mongodb://localhost", :connect => false)
+
+ admin_db = new_mock_db
+ admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1})
+ @client.expects(:[]).with('admin').returns(admin_db)
+ @client.connect
+ end
+
+ should "raise an error on invalid uris" do
+ assert_raise MongoArgumentError do
+ Client.from_uri("mongo://localhost", :connect => false)
+ end
+
+ assert_raise MongoArgumentError do
+ Client.from_uri("mongodb://localhost:abc", :connect => false)
+ end
+ end
+
+ should "require all of username, if password and db are specified" do
+ assert Client.from_uri("mongodb://kyle:jones@localhost/db", :connect => false)
+
+ assert_raise MongoArgumentError do
+ Client.from_uri("mongodb://kyle:password@localhost", :connect => false)
+ 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"
+ @client = Client.new
+ assert_equal ['localhost', 27017], @client.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"
+ @client = Client.new
+ assert_equal [host_name, 27017], @client.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"
+ @client = Client.new
+ assert_equal [host_name, 27017], @client.host_to_try
+ end
+
+ should "set write concern options on connection" do
+ host_name = "localhost"
+ opts = "w=2&wtimeoutMS=1000&fsync=true&journal=true&connect=false"
+ ENV['MONGODB_URI'] = "mongodb://#{host_name}/foo?#{opts}"
+ @client = Client.new
+ assert_equal({:w => 2, :wtimeout => 1000, :fsync => true, :j => true}, @client.write_concern)
+ 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}"
+ @client = Client.new
+ assert_equal 1, @client.connect_timeout
+ assert_equal 5, @client.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"
+ @client = Client.new
+ assert_equal ['localhost', 27017], @client.host_to_try
+ auth_hash = { 'db_name' => 'db', 'username' => 'hyphen-user_name', "password" => 'p-s_s' }
+ assert_equal auth_hash, @client.auths[0]
+ end
+
+ should "attempt to connect" do
+ TCPSocket.stubs(:new).returns(new_mock_socket)
+ ENV['MONGODB_URI'] = "mongodb://localhost?connect=false" # connect=false ??
+ @client = Client.new
+
+ admin_db = new_mock_db
+ admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1})
+ @client.expects(:[]).with('admin').returns(admin_db)
+ @client.connect
+ end
+
+ should "raise an error on invalid uris" do
+ ENV['MONGODB_URI'] = "mongo://localhost"
+ assert_raise MongoArgumentError do
+ Client.new
+ end
+
+ ENV['MONGODB_URI'] = "mongodb://localhost:abc"
+ assert_raise MongoArgumentError do
+ Client.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 Client.new
+
+ ENV['MONGODB_URI'] = "mongodb://kyle:password@localhost"
+ assert_raise MongoArgumentError do
+ Client.new
+ end
+ end
+ end
+ end
+end
diff --git a/test/unit/collection_test.rb b/test/unit/collection_test.rb
index 5c9c429689..a62fe002fa 100644
--- a/test/unit/collection_test.rb
+++ b/test/unit/collection_test.rb
@@ -13,7 +13,7 @@ class CollectionTest < Test::Unit::TestCase
@client = Client.new('localhost', 27017, :logger => @logger, :connect => false)
@db = @client['testing']
@coll = @db.collection('books')
- @client.expects(:send_message).with do |op, msg, log|
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, log|
op == 2001
end
@coll.stubs(:log_operation)
@@ -24,7 +24,7 @@ class CollectionTest < Test::Unit::TestCase
@client = Client.new('localhost', 27017, :logger => @logger, :connect => false)
@db = @client['testing']
@coll = @db.collection('books')
- @client.expects(:send_message).with do |op, msg, log|
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, log|
op == 2002
end
@coll.expects(:log_operation).with do |name, payload|
@@ -50,7 +50,7 @@ class CollectionTest < Test::Unit::TestCase
@db = @client['testing']
@coll = @db.collection('books')
data = BSON::Binary.new(("BINARY " * 1000).unpack("c*"))
- @client.expects(:send_message).with do |op, msg, log|
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, log|
op == 2002
end
@coll.expects(:log_operation).with do |name, payload|
@@ -63,7 +63,20 @@ class CollectionTest < Test::Unit::TestCase
@client = Client.new('localhost', 27017, :logger => @logger, :connect => false)
@db = @client['testing']
@coll = @db.collection('books')
- @client.expects(:send_message_with_safe_check).with do |op, msg, db_name, log|
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, db_name, log|
+ op == 2001
+ end
+ @coll.expects(:log_operation).with do |name, payload|
+ (name == :update) && payload[:document][:title].include?('Moby')
+ end
+ @coll.update({}, {:title => 'Moby Dick'})
+ end
+
+ should "send safe update message with legacy" do
+ @client = Connection.new('localhost', 27017, :logger => @logger, :connect => false)
+ @db = @client['testing']
+ @coll = @db.collection('books')
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, db_name, log|
op == 2001
end
@coll.expects(:log_operation).with do |name, payload|
@@ -76,7 +89,18 @@ class CollectionTest < Test::Unit::TestCase
@client = Client.new('localhost', 27017, :logger => @logger, :connect => false)
@db = @client['testing']
@coll = @db.collection('books')
- @client.expects(:send_message_with_safe_check).with do |op, msg, db_name, log|
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, db_name, log|
+ op == 2001
+ end
+ @coll.stubs(:log_operation)
+ @coll.update({}, {:title => 'Moby Dick'})
+ end
+
+ should "send safe insert message with legacy" do
+ @client = Connection.new('localhost', 27017, :logger => @logger, :connect => false)
+ @db = @client['testing']
+ @coll = @db.collection('books')
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, db_name, log|
op == 2001
end
@coll.stubs(:log_operation)
diff --git a/test/unit/connection_test.rb b/test/unit/connection_test.rb
index 3c2d3785c7..e3f1094311 100644
--- a/test/unit/connection_test.rb
+++ b/test/unit/connection_test.rb
@@ -1,155 +1,140 @@
require 'test_helper'
-include Mongo
class ConnectionTest < Test::Unit::TestCase
- context "Initialization: " do
+ context "Mongo::Client intialization " do
context "given a single node" do
setup do
- @client = Client.new('localhost', 27017, :safe => true, :connect => false)
+ @connection = Mongo::Connection.new('localhost', 27017, :safe => true, :connect => false)
TCPSocket.stubs(:new).returns(new_mock_socket)
admin_db = new_mock_db
admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1})
- @client.expects(:[]).with('admin').returns(admin_db)
- @client.connect
+ @connection.expects(:[]).with('admin').returns(admin_db)
+ @connection.connect
end
should "set safe mode true" do
- assert_equal true, @client.safe
+ assert_equal true, @connection.safe
end
should "set localhost and port to master" do
- assert_equal 'localhost', @client.primary_pool.host
- assert_equal 27017, @client.primary_pool.port
+ assert_equal 'localhost', @connection.primary_pool.host
+ assert_equal 27017, @connection.primary_pool.port
end
should "set connection pool to 1" do
- assert_equal 1, @client.primary_pool.size
+ assert_equal 1, @connection.primary_pool.size
end
should "default slave_ok to false" do
- assert !@client.slave_ok?
+ assert !@connection.slave_ok?
end
should "raise exception for invalid host or port" do
assert_raise MongoArgumentError do
- Client.new(:safe => true)
+ Mongo::Connection.new(:safe => true)
end
assert_raise MongoArgumentError do
- Client.new('localhost', :safe => true)
+ Mongo::Connection.new('localhost', :safe => true)
end
end
should "warn if invalid options are specified" do
- client = Client.allocate
+ connection = Mongo::Connection.allocate
opts = {:connect => false}
- ReplSetClient::REPL_SET_OPTS.each do |opt|
- client.expects(:warn).with("#{opt} is not a valid option for #{client.class}")
+ Mongo::ReplSetConnection::REPL_SET_OPTS.each do |opt|
+ connection.expects(:warn).with("#{opt} is not a valid option for #{connection.class}")
opts[opt] = true
end
args = ['localhost', 27017, opts]
- client.send(:initialize, *args)
- end
-
- should "warn if deprecated connection class is used" do
- conn = Connection.allocate
- conn.expects(:warn).with('[DEPRECATED] Mongo::Connection has been replaced with Mongo::Client.')
- args = ['localhost', 27017, {:connect => false}]
- conn.send(:initialize, *args)
+ connection.send(:initialize, *args)
end
context "given a replica set" do
- should "warn if invalid options are specified" do
- client = ReplSetClient.allocate
- opts = {:connect => false}
+ # should "warn if invalid options are specified" do
+ # connection = Mongo::ReplSetConnection.allocate
+ # opts = {:connect => false}
- Client::CONNECTION_OPTS.each do |opt|
- client.expects(:warn).with("#{opt} is not a valid option for #{client.class}")
- opts[opt] = true
- end
+ # # Mongo::Connection::CLIENT_ONLY_OPTS.each do |opt|
+ # connection.expects(:warn).with("#{:slave_ok} is not a valid option for #{connection.class}")
+ # opts[:slave_ok] = true
+ # # end
- args = [['localhost:27017'], opts]
- client.send(:initialize, *args)
- end
-
- should "warn if deprecated connection class is used" do
- conn = ReplSetConnection.allocate
- conn.expects(:warn).with('[DEPRECATED] Mongo::ReplSetConnection has been replaced with Mongo::ReplSetClient.')
- args = [['localhost:27017'], {:connect => false}]
- conn.send(:initialize, *args)
- end
+ # args = [['localhost:27017'], opts]
+ # connection.send(:initialize, *args)
+ # end
end
end
context "initializing with a mongodb uri" do
should "parse a simple uri" do
- @client = Client.from_uri("mongodb://localhost", :connect => false)
- assert_equal ['localhost', 27017], @client.host_to_try
+ @connection = Mongo::Connection.from_uri("mongodb://localhost", :connect => false)
+ assert_equal ['localhost', 27017], @connection.host_to_try
end
should "allow a complex host names" do
host_name = "foo.bar-12345.org"
- @client = Client.from_uri("mongodb://#{host_name}", :connect => false)
- assert_equal [host_name, 27017], @client.host_to_try
+ @connection = Mongo::Connection.from_uri("mongodb://#{host_name}", :connect => false)
+ assert_equal [host_name, 27017], @connection.host_to_try
end
should "allow db without username and password" do
host_name = "foo.bar-12345.org"
- @client = Client.from_uri("mongodb://#{host_name}/foo", :connect => false)
- assert_equal [host_name, 27017], @client.host_to_try
+ @connection = Mongo::Connection.from_uri("mongodb://#{host_name}/foo", :connect => false)
+ assert_equal [host_name, 27017], @connection.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"
- @client = Client.from_uri("mongodb://#{host_name}/foo?#{opts}", :connect => false)
- assert_equal({:w => 2, :wtimeout => 1000, :fsync => true, :j => true}, @client.safe)
+ @connection = Mongo::Connection.from_uri("mongodb://#{host_name}/foo?#{opts}", :connect => false)
+ assert_equal({:w => 2, :wtimeout => 1000, :fsync => true, :j => true}, @connection.write_concern)
end
should "set timeout options on connection" do
host_name = "localhost"
opts = "connectTimeoutMS=1000&socketTimeoutMS=5000"
- @client = Client.from_uri("mongodb://#{host_name}/foo?#{opts}", :connect => false)
- assert_equal 1, @client.connect_timeout
- assert_equal 5, @client.op_timeout
+ @connection = Mongo::Connection.from_uri("mongodb://#{host_name}/foo?#{opts}", :connect => false)
+ assert_equal 1, @connection.connect_timeout
+ assert_equal 5, @connection.op_timeout
end
should "parse a uri with a hyphen & underscore in the username or password" do
- @client = Client.from_uri("mongodb://hyphen-user_name:p-s_s@localhost:27017/db", :connect => false)
- assert_equal ['localhost', 27017], @client.host_to_try
+ @connection = Mongo::Connection.from_uri("mongodb://hyphen-user_name:p-s_s@localhost:27017/db", :connect => false)
+ assert_equal ['localhost', 27017], @connection.host_to_try
auth_hash = { 'db_name' => 'db', 'username' => 'hyphen-user_name', "password" => 'p-s_s' }
- assert_equal auth_hash, @client.auths[0]
+ assert_equal auth_hash, @connection.auths[0]
end
should "attempt to connect" do
TCPSocket.stubs(:new).returns(new_mock_socket)
- @client = Client.from_uri("mongodb://localhost", :connect => false)
+ @connection = Mongo::Connection.from_uri("mongodb://localhost", :connect => false)
admin_db = new_mock_db
admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1})
- @client.expects(:[]).with('admin').returns(admin_db)
- @client.connect
+ @connection.expects(:[]).with('admin').returns(admin_db)
+ @connection.connect
end
should "raise an error on invalid uris" do
assert_raise MongoArgumentError do
- Client.from_uri("mongo://localhost", :connect => false)
+ Mongo::Connection.from_uri("mongo://localhost", :connect => false)
end
assert_raise MongoArgumentError do
- Client.from_uri("mongodb://localhost:abc", :connect => false)
+ Mongo::Connection.from_uri("mongodb://localhost:abc", :connect => false)
end
end
should "require all of username, if password and db are specified" do
- assert Client.from_uri("mongodb://kyle:jones@localhost/db", :connect => false)
+ assert Mongo::Connection.from_uri("mongodb://kyle:jones@localhost/db", :connect => false)
assert_raise MongoArgumentError do
- Client.from_uri("mongodb://kyle:password@localhost", :connect => false)
+ Mongo::Connection.from_uri("mongodb://kyle:password@localhost", :connect => false)
end
end
end
@@ -165,79 +150,79 @@ class ConnectionTest < Test::Unit::TestCase
should "parse a simple uri" do
ENV['MONGODB_URI'] = "mongodb://localhost?connect=false"
- @client = Client.new
- assert_equal ['localhost', 27017], @client.host_to_try
+ @connection = Mongo::Connection.new
+ assert_equal ['localhost', 27017], @connection.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"
- @client = Client.new
- assert_equal [host_name, 27017], @client.host_to_try
+ @connection = Mongo::Connection.new
+ assert_equal [host_name, 27017], @connection.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"
- @client = Client.new
- assert_equal [host_name, 27017], @client.host_to_try
+ @connection = Mongo::Connection.new
+ assert_equal [host_name, 27017], @connection.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}"
- @client = Client.new
- assert_equal({:w => 2, :wtimeout => 1000, :fsync => true, :j => true}, @client.safe)
+ @connection = Mongo::Connection.new
+ assert_equal({:w => 2, :wtimeout => 1000, :fsync => true, :j => true}, @connection.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}"
- @client = Client.new
- assert_equal 1, @client.connect_timeout
- assert_equal 5, @client.op_timeout
+ @connection = Mongo::Connection.new
+ assert_equal 1, @connection.connect_timeout
+ assert_equal 5, @connection.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"
- @client = Client.new
- assert_equal ['localhost', 27017], @client.host_to_try
+ @connection = Mongo::Connection.new
+ assert_equal ['localhost', 27017], @connection.host_to_try
auth_hash = { 'db_name' => 'db', 'username' => 'hyphen-user_name', "password" => 'p-s_s' }
- assert_equal auth_hash, @client.auths[0]
+ assert_equal auth_hash, @connection.auths[0]
end
should "attempt to connect" do
TCPSocket.stubs(:new).returns(new_mock_socket)
ENV['MONGODB_URI'] = "mongodb://localhost?connect=false" # connect=false ??
- @client = Client.new
+ @connection = Mongo::Connection.new
admin_db = new_mock_db
admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1})
- @client.expects(:[]).with('admin').returns(admin_db)
- @client.connect
+ @connection.expects(:[]).with('admin').returns(admin_db)
+ @connection.connect
end
should "raise an error on invalid uris" do
ENV['MONGODB_URI'] = "mongo://localhost"
assert_raise MongoArgumentError do
- Client.new
+ Mongo::Connection.new
end
ENV['MONGODB_URI'] = "mongodb://localhost:abc"
assert_raise MongoArgumentError do
- Client.new
+ Mongo::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 Client.new
+ assert Mongo::Connection.new
ENV['MONGODB_URI'] = "mongodb://kyle:password@localhost"
assert_raise MongoArgumentError do
- Client.new
+ Mongo::Connection.new
end
end
end
diff --git a/test/unit/db_test.rb b/test/unit/db_test.rb
index b001adc6a7..8b2c54b0f2 100644
--- a/test/unit/db_test.rb
+++ b/test/unit/db_test.rb
@@ -14,7 +14,7 @@ class DBTest < Test::Unit::TestCase
context "DB commands" do
setup do
@client = stub()
- @client.stubs(:safe)
+ @client.stubs(:write_concern).returns({})
@client.stubs(:read_preference)
@client.stubs(:tag_sets)
@client.stubs(:acceptable_latency)
diff --git a/test/unit/grid_test.rb b/test/unit/grid_test.rb
index eb3c6e7f58..cee65a387a 100644
--- a/test/unit/grid_test.rb
+++ b/test/unit/grid_test.rb
@@ -5,7 +5,7 @@ class GridTest < Test::Unit::TestCase
context "GridFS: " do
setup do
@client = stub()
- @client.stubs(:safe)
+ @client.stubs(:write_concern).returns({})
@client.stubs(:read_preference)
@client.stubs(:tag_sets)
@client.stubs(:acceptable_latency)
diff --git a/test/unit/safe_test.rb b/test/unit/safe_test.rb
new file mode 100644
index 0000000000..3a64038b03
--- /dev/null
+++ b/test/unit/safe_test.rb
@@ -0,0 +1,125 @@
+require 'test_helper'
+
+class WriteConcernTest < Test::Unit::TestCase
+
+ context "Write-Concern modes on Mongo::Connection " do
+ setup do
+ @safe_value = {:w => 7, :j => false, :fsync => false, :wtimeout => false}
+ @client = Mongo::Connection.new('localhost', 27017, :safe => @safe_value, :connect => false)
+ end
+
+ should "propogate to DB" do
+ db = @client['foo']
+ assert_equal @safe_value[:w], db.write_concern[:w]
+
+
+ db = @client.db('foo')
+ assert_equal @safe_value[:w], db.write_concern[:w]
+
+ db = DB.new('foo', @client)
+ assert_equal @safe_value[:w], db.write_concern[:w]
+ end
+
+ should "allow db override" do
+ db = DB.new('foo', @client, :safe => false)
+ assert_equal 0, db.write_concern[:w]
+
+ db = @client.db('foo', :safe => false)
+ assert_equal 0, db.write_concern[:w]
+ end
+
+ context "on DB: " do
+ setup do
+ @db = @client['foo']
+ end
+
+ should "propogate to collection" do
+ col = @db.collection('bar')
+ assert_equal @safe_value, col.write_concern
+
+ col = @db['bar']
+ assert_equal @safe_value, col.write_concern
+
+ col = Collection.new('bar', @db)
+ assert_equal @safe_value, col.write_concern
+ end
+
+ should "allow override on collection" do
+ col = @db.collection('bar', :safe => false)
+ assert_equal 0, col.write_concern[:w]
+
+ col = Collection.new('bar', @db, :safe => false)
+ assert_equal 0, col.write_concern[:w]
+ end
+ end
+
+ context "on operations supporting safe mode" do
+ setup do
+ @col = @client['foo']['bar']
+ end
+
+ should "use default value on insert" do
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, log, n, safe|
+ safe == @safe_value
+ end
+
+ @col.insert({:a => 1})
+ end
+
+ should "allow override alternate value on insert" do
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, log, n, safe|
+ safe == {:w => 100, :j => false, :fsync => false, :wtimeout => false}
+ end
+
+ @col.insert({:a => 1}, :safe => {:w => 100})
+ end
+
+ should "allow override to disable on insert" do
+ @client.expects(:send_message)
+ @col.insert({:a => 1}, :safe => false)
+ end
+
+ should "use default value on update" do
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, log, n, safe|
+ safe == @safe_value
+ end
+
+ @col.update({:a => 1}, {:a => 2})
+ end
+
+ should "allow override alternate value on update" do
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, log, n, safe|
+ safe == {:w => 100, :j => false, :fsync => false, :wtimeout => false}
+ end
+
+ @col.update({:a => 1}, {:a => 2}, :safe => {:w => 100})
+ end
+
+ should "allow override to disable on update" do
+ @client.expects(:send_message)
+ @col.update({:a => 1}, {:a => 2}, :safe => false)
+ end
+
+ should "use default value on remove" do
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, log, n, safe|
+ safe == @safe_value
+ end
+
+ @col.remove
+ end
+
+ should "allow override alternate value on remove" do
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, log, n, safe|
+ safe == {:w => 100, :j => false, :fsync => false, :wtimeout => false}
+ end
+
+ @col.remove({}, :safe => {:w => 100})
+ end
+
+ should "allow override to disable on remove" do
+ @client.expects(:send_message)
+ @col.remove({}, :safe => false)
+ end
+ end
+ end
+end
diff --git a/test/unit/write_concern_test.rb b/test/unit/write_concern_test.rb
index 55e4f86f90..4a475ad1fe 100644
--- a/test/unit/write_concern_test.rb
+++ b/test/unit/write_concern_test.rb
@@ -2,30 +2,38 @@
class WriteConcernTest < Test::Unit::TestCase
- context "Write-Concern modes on connection: " do
+ context "Write-Concern modes on Mongo::Client " do
setup do
- @safe_value = {:w => 7}
- @client = Mongo::Client.new('localhost', 27017, :safe => @safe_value, :connect => false)
+ @write_concern = {
+ :w => 7,
+ :j => false,
+ :fsync => false,
+ :wtimeout => false
+ }
+
+ @client =
+ Mongo::Client.new('localhost', 27017,
+ @write_concern.merge({:connect => false}))
end
should "propogate to DB" do
db = @client['foo']
- assert_equal @safe_value, db.safe
+ assert_equal @write_concern, db.write_concern
db = @client.db('foo')
- assert_equal @safe_value, db.safe
+ assert_equal @write_concern, db.write_concern
db = DB.new('foo', @client)
- assert_equal @safe_value, db.safe
+ assert_equal @write_concern, db.write_concern
end
should "allow db override" do
- db = DB.new('foo', @client, :safe => false)
- assert_equal false, db.safe
+ db = DB.new('foo', @client, :w => 0)
+ assert_equal 0, db.write_concern[:w]
- db = @client.db('foo', :safe => false)
- assert_equal false, db.safe
+ db = @client.db('foo', :w => 0)
+ assert_equal 0, db.write_concern[:w]
end
context "on DB: " do
@@ -34,91 +42,91 @@ class WriteConcernTest < Test::Unit::TestCase
end
should "propogate to collection" do
- col = @db.collection('bar')
- assert_equal @safe_value, col.safe
+ collection = @db.collection('bar')
+ assert_equal @write_concern, collection.write_concern
- col = @db['bar']
- assert_equal @safe_value, col.safe
+ collection = @db['bar']
+ assert_equal @write_concern, collection.write_concern
- col = Collection.new('bar', @db)
- assert_equal @safe_value, col.safe
+ collection = Collection.new('bar', @db)
+ assert_equal @write_concern, collection.write_concern
end
should "allow override on collection" do
- col = @db.collection('bar', :safe => false)
- assert_equal false, col.safe
+ collection = @db.collection('bar', :w => 0)
+ assert_equal 0, collection.write_concern[:w]
- col = Collection.new('bar', @db, :safe => false)
- assert_equal false, col.safe
+ collection = Collection.new('bar', @db, :w => 0)
+ assert_equal 0, collection.write_concern[:w]
end
end
- context "on operations supporting safe mode" do
+ context "on operations supporting 'acknowledged' mode" do
setup do
- @col = @client['foo']['bar']
+ @collection = @client['foo']['bar']
end
should "use default value on insert" do
- @client.expects(:send_message_with_safe_check).with do |op, msg, log, n, safe|
- safe == @safe_value
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, log, n, wc|
+ wc == @write_concern
end
- @col.insert({:a => 1})
+ @collection.insert({:a => 1})
end
should "allow override alternate value on insert" do
- @client.expects(:send_message_with_safe_check).with do |op, msg, log, n, safe|
- safe == {:w => 100}
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, log, n, wc|
+ wc == {:w => 100, :j => false, :fsync => false, :wtimeout => false}
end
- @col.insert({:a => 1}, :safe => {:w => 100})
+ @collection.insert({:a => 1}, {:w => 100})
end
should "allow override to disable on insert" do
@client.expects(:send_message)
- @col.insert({:a => 1}, :safe => false)
+ @collection.insert({:a => 1}, :w => 0)
end
should "use default value on update" do
- @client.expects(:send_message_with_safe_check).with do |op, msg, log, n, safe|
- safe == @safe_value
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, log, n, wc|
+ wc == @write_concern
end
- @col.update({:a => 1}, {:a => 2})
+ @collection.update({:a => 1}, {:a => 2})
end
should "allow override alternate value on update" do
- @client.expects(:send_message_with_safe_check).with do |op, msg, log, n, safe|
- safe == {:w => 100}
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, log, n, wc|
+ wc == {:w => 100, :j => false, :fsync => false, :wtimeout => false}
end
- @col.update({:a => 1}, {:a => 2}, :safe => {:w => 100})
+ @collection.update({:a => 1}, {:a => 2}, {:w => 100})
end
should "allow override to disable on update" do
@client.expects(:send_message)
- @col.update({:a => 1}, {:a => 2}, :safe => false)
+ @collection.update({:a => 1}, {:a => 2}, :w => 0)
end
should "use default value on remove" do
- @client.expects(:send_message_with_safe_check).with do |op, msg, log, n, safe|
- safe == @safe_value
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, log, n, wc|
+ wc == @write_concern
end
- @col.remove
+ @collection.remove
end
should "allow override alternate value on remove" do
- @client.expects(:send_message_with_safe_check).with do |op, msg, log, n, safe|
- safe == {:w => 100}
+ @client.expects(:send_message_with_acknowledge).with do |op, msg, log, n, wc|
+ wc == {:w => 100, :j => false, :fsync => false, :wtimeout => false}
end
- @col.remove({}, :safe => {:w => 100})
+ @collection.remove({}, {:w => 100})
end
should "allow override to disable on remove" do
@client.expects(:send_message)
- @col.remove({}, :safe => false)
+ @collection.remove({}, :w => 0)
end
end
end