Merge branch 'master' of github.com:mongodb/mongo-ruby-driver

This commit is contained in:
Tyler Brock 2012-02-16 13:03:08 -05:00
commit a4e49d86ac
10 changed files with 88 additions and 16 deletions

View File

@ -87,6 +87,7 @@ module Mongo
@db, @name = db, name
@connection = @db.connection
@logger = @connection.logger
@log_duration = @connection.log_duration
@cache_time = @db.cache_time
@cache = Hash.new(0)
unless pk_factory

View File

@ -36,7 +36,7 @@ module Mongo
mongo_thread_local_accessor :connections
attr_reader :logger, :size, :auths, :primary, :safe, :host_to_try,
attr_reader :logger, :log_duration, :size, :auths, :primary, :safe, :host_to_try,
:pool_size, :connect_timeout, :pool_timeout,
:primary_pool, :socket_class, :op_timeout
@ -63,6 +63,8 @@ module Mongo
# to a single, slave node.
# @option opts [Logger, #debug] :logger (nil) A Logger instance for debugging driver ops. Note that
# logging negatively impacts performance; therefore, it should not be used for high-performance apps.
# @option opts [Boolean, #debug] :log_duration (nil) A boolean to say if you want see information about log_duration on logger
# like logging, log_duration negatively impacts performance; therefore, it should not be used for high-performance apps.
# @option opts [Integer] :pool_size (1) The maximum number of socket self.connections allowed per
# connection pool. Note: this setting is relevant only for multi-threaded applications.
# @option opts [Float] :pool_timeout (5.0) When all of the self.connections a pool are checked out,
@ -568,6 +570,7 @@ module Mongo
if @logger
write_logging_startup_message
@log_duration = opts[:log_duration] || false
end
should_connect = opts.fetch(:connect, true)

View File

@ -43,6 +43,7 @@ module Mongo
@collection = collection
@connection = @db.connection
@logger = @connection.logger
@log_duration = @connection.log_duration
# Query selector
@selector = opts[:selector] || {}

View File

@ -173,12 +173,15 @@ module Mongo
#
# @param [String] username
# @param [String] password
# @param [Boolean] read_only
# Create a read-only user.
#
# @return [Hash] an object representing the user.
def add_user(username, password)
def add_user(username, password, read_only = false)
users = self[SYSTEM_USER_COLLECTION]
user = users.find_one({:user => username}) || {:user => username}
user['pwd'] = Mongo::Support.hash_password(username, password)
user['readOnly'] = true if read_only;
users.save(user)
return user
end

View File

@ -71,6 +71,9 @@ module Mongo
# GridFileSystem#delete.
# @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 [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
# deleting GridFS files. See the notes under GridFileSystem#delete.
#
# @example
#
@ -97,7 +100,12 @@ module Mongo
def open(filename, mode, opts={})
opts = opts.dup
opts.merge!(default_grid_io_opts(filename))
del = opts.delete(:delete_old) && mode == 'w'
if mode == 'w'
versions = opts.delete(:versions)
if opts.delete(:delete_old) || (versions && versions < 1)
versions = 1
end
end
file = GridIO.new(@files, @chunks, filename, mode, opts)
return file unless block_given?
result = nil
@ -105,9 +113,9 @@ module Mongo
result = yield file
ensure
id = file.close
if del
if versions
self.delete do
@files.find({'filename' => filename, '_id' => {'$ne' => id}}, :fields => ['_id'])
@files.find({'filename' => filename, '_id' => {'$ne' => id}}, :fields => ['_id'], :sort => ['uploadDate', -1], :skip => (versions -1))
end
end
end

View File

@ -25,14 +25,15 @@ module Mongo
# Execute the block and log the operation described by name and payload.
def instrument(name, payload = {}, &blk)
time_elapse = @log_duration ? Time.now : nil
res = yield
log_operation(name, payload)
log_operation(name, payload, time_elapse)
res
end
protected
def log_operation(name, payload)
def log_operation(name, payload, time_elapse=nil)
@logger ||= nil
return unless @logger
msg = "#{payload[:database]}['#{payload[:collection]}'].#{name}("
@ -40,8 +41,12 @@ module Mongo
msg += ".skip(#{payload[:skip]})" if payload[:skip]
msg += ".limit(#{payload[:limit]})" if payload[:limit]
msg += ".sort(#{payload[:order]})" if payload[:order]
if time_elapse
@logger.debug "MONGODB (#{Time.now - time_elapse}s) #{msg}"
else
@logger.debug "MONGODB #{msg}"
end
end
end
end

View File

@ -26,6 +26,7 @@ class AuthenticationTest < Test::Unit::TestCase
@admin.authenticate('bob', 'secret')
@db1.add_user('user1', 'secret')
@db2.add_user('user2', 'secret')
@db2.add_user('userRO', 'secret', true) # read-only
@admin.logout
assert_raise Mongo::OperationFailure do
@ -53,6 +54,7 @@ class AuthenticationTest < Test::Unit::TestCase
assert @db1['stuff'].insert({:a => 2}, :safe => true)
assert @db2['stuff'].insert({:a => 2}, :safe => true)
assert @db2['stuff'].find(:safe => true)
@db1.logout
assert_raise Mongo::OperationFailure do
@ -63,6 +65,12 @@ class AuthenticationTest < Test::Unit::TestCase
assert_raise Mongo::OperationFailure do
assert @db2['stuff'].insert({:a => 2}, :safe => true)
end
@db2.authenticate('userRO', 'secret')
assert @db2['stuff'].find(:safe => true)
assert_raise Mongo::OperationFailure do
assert @db2['stuff'].insert({:a => 2}, :safe => true)
end
end
end

View File

@ -137,6 +137,15 @@ class TestConnection < Test::Unit::TestCase
assert output.string.include?("admin['$cmd'].find")
end
def test_logging_duration
output = StringIO.new
logger = Logger.new(output)
logger.level = Logger::DEBUG
connection = standard_connection(:logger => logger, :log_duration => true).db(MONGO_TEST_DB)
assert output.string.index(/\(0.\d+s\)/)
assert output.string.include?("admin['$cmd'].find")
end
def test_connection_logger
output = StringIO.new
logger = Logger.new(output)
@ -148,6 +157,21 @@ class TestConnection < Test::Unit::TestCase
assert output.string.include?('testing')
end
def test_connection_log_duration_with_logger
output = StringIO.new
logger = Logger.new(output)
logger.level = Logger::DEBUG
connection = standard_connection(:logger => logger, :log_duration => true)
assert logger, connection.logger
assert connection.log_duration
end
def test_connection_log_duration_without_logger
connection = standard_connection(:log_duration => true)
assert_nil connection.logger
assert !connection.log_duration
end
def test_drop_database
db = @conn.db('ruby-mongo-will-be-deleted')
coll = db.collection('temp')

View File

@ -151,6 +151,13 @@ class DBTest < Test::Unit::TestCase
@@db.remove_user('foo:bar')
end
def test_authenticate_read_only
@@db.add_user('joebob', 'user', true) # read-only user
assert @@db.authenticate('joebob', 'user')
@@db.logout
@@db.remove_user('joebob')
end
def test_authenticate_with_connection_uri
@@db.add_user('spongebob', 'squarepants')
assert Mongo::Connection.from_uri("mongodb://spongebob:squarepants@#{host_port}/#{@@db.name}")

View File

@ -165,6 +165,18 @@ class GridFileSystemTest < Test::Unit::TestCase
assert_equal 0, @db['fs.chunks'].find({'files_id' => {'$in' => @ids}}).count
end
should "delete all versions which exceed the number of versions to keep specified by the option :versions" do
@versions = 1 + rand(4-1)
@grid.open('sample', 'w', :versions => @versions) do |f|
f.write @new_data
end
@new_ids = @db['fs.files'].find({'filename' => 'sample'}).map {|file| file['_id']}
assert_equal @versions, @new_ids.length
id = @new_ids.first
assert !@ids.include?(id)
assert_equal @versions, @db['fs.files'].find({'filename' => 'sample'}).count
end
should "delete old versions on write with :delete_old is passed in" do
@grid.open('sample', 'w', :delete_old => true) do |f|
f.write @new_data