mongo 2.4.3 → 2.5.0.beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +3 -2
- data.tar.gz.sig +0 -0
- data/lib/mongo.rb +3 -2
- data/lib/mongo/auth/cr.rb +6 -4
- data/lib/mongo/auth/cr/conversation.rb +33 -17
- data/lib/mongo/auth/ldap.rb +4 -2
- data/lib/mongo/auth/ldap/conversation.rb +19 -9
- data/lib/mongo/auth/scram.rb +7 -4
- data/lib/mongo/auth/scram/conversation.rb +62 -24
- data/lib/mongo/auth/user.rb +10 -0
- data/lib/mongo/auth/user/view.rb +44 -22
- data/lib/mongo/auth/x509.rb +4 -2
- data/lib/mongo/auth/x509/conversation.rb +19 -9
- data/lib/mongo/bulk_write.rb +33 -27
- data/lib/mongo/bulk_write/combineable.rb +5 -0
- data/lib/mongo/bulk_write/transformable.rb +2 -0
- data/lib/mongo/bulk_write/validatable.rb +4 -0
- data/lib/mongo/client.rb +123 -12
- data/lib/mongo/cluster.rb +52 -11
- data/lib/mongo/cluster/app_metadata.rb +8 -2
- data/lib/mongo/cluster/cursor_reaper.rb +0 -1
- data/lib/mongo/cluster/topology.rb +1 -1
- data/lib/mongo/collection.rb +114 -27
- data/lib/mongo/collection/view.rb +8 -2
- data/lib/mongo/collection/view/aggregation.rb +11 -7
- data/lib/mongo/collection/view/builder/aggregation.rb +5 -1
- data/lib/mongo/collection/view/builder/find_command.rb +5 -3
- data/lib/mongo/collection/view/builder/map_reduce.rb +11 -3
- data/lib/mongo/collection/view/builder/op_query.rb +1 -1
- data/lib/mongo/collection/view/change_stream.rb +160 -0
- data/lib/mongo/collection/view/change_stream/retryable.rb +57 -0
- data/lib/mongo/collection/view/iterable.rb +11 -10
- data/lib/mongo/collection/view/map_reduce.rb +22 -18
- data/lib/mongo/collection/view/readable.rb +51 -37
- data/lib/mongo/collection/view/writable.rb +72 -40
- data/lib/mongo/cursor.rb +25 -4
- data/lib/mongo/cursor/builder/get_more_command.rb +4 -2
- data/lib/mongo/database.rb +22 -11
- data/lib/mongo/database/view.rb +16 -12
- data/lib/mongo/error.rb +5 -0
- data/lib/mongo/error/invalid_session.rb +36 -0
- data/lib/mongo/error/missing_resume_token.rb +39 -0
- data/lib/mongo/error/operation_failure.rb +17 -0
- data/lib/mongo/error/parser.rb +3 -2
- data/lib/mongo/error/unknown_payload_type.rb +41 -0
- data/lib/mongo/error/unsupported_array_filters.rb +51 -0
- data/lib/mongo/error/unsupported_message_type.rb +23 -0
- data/lib/mongo/grid/fs_bucket.rb +5 -4
- data/lib/mongo/grid/stream/read.rb +3 -2
- data/lib/mongo/grid/stream/write.rb +2 -2
- data/lib/mongo/index/view.rb +35 -25
- data/lib/mongo/monitoring/event/secure.rb +14 -0
- data/lib/mongo/operation.rb +16 -0
- data/lib/mongo/operation/commands.rb +1 -0
- data/lib/mongo/operation/commands/aggregate.rb +9 -5
- data/lib/mongo/operation/commands/aggregate/result.rb +1 -1
- data/lib/mongo/operation/commands/collections_info.rb +6 -6
- data/lib/mongo/operation/commands/command.rb +2 -1
- data/lib/mongo/operation/commands/create.rb +6 -2
- data/lib/mongo/operation/commands/drop.rb +6 -2
- data/lib/mongo/operation/commands/drop_database.rb +6 -2
- data/lib/mongo/operation/commands/explain.rb +27 -0
- data/lib/mongo/operation/commands/explain/result.rb +52 -0
- data/lib/mongo/operation/commands/indexes.rb +1 -1
- data/lib/mongo/operation/commands/list_collections.rb +1 -1
- data/lib/mongo/operation/commands/list_collections/result.rb +1 -1
- data/lib/mongo/operation/commands/list_indexes.rb +1 -1
- data/lib/mongo/operation/commands/list_indexes/result.rb +1 -1
- data/lib/mongo/operation/commands/map_reduce.rb +8 -4
- data/lib/mongo/operation/commands/map_reduce/result.rb +13 -1
- data/lib/mongo/operation/commands/user_query.rb +1 -1
- data/lib/mongo/operation/commands/users_info.rb +6 -2
- data/lib/mongo/operation/executable.rb +4 -1
- data/lib/mongo/operation/read_preference.rb +10 -5
- data/lib/mongo/operation/result.rb +26 -2
- data/lib/mongo/operation/specifiable.rb +13 -1
- data/lib/mongo/operation/uses_command_op_msg.rb +47 -0
- data/lib/mongo/operation/write/bulk/bulkable.rb +4 -1
- data/lib/mongo/operation/write/bulk/insert/result.rb +4 -4
- data/lib/mongo/operation/write/command/create_index.rb +6 -1
- data/lib/mongo/operation/write/command/delete.rb +28 -4
- data/lib/mongo/operation/write/command/drop_index.rb +6 -1
- data/lib/mongo/operation/write/command/insert.rb +22 -18
- data/lib/mongo/operation/write/command/update.rb +24 -9
- data/lib/mongo/operation/write/command/writable.rb +14 -1
- data/lib/mongo/operation/write/insert.rb +4 -1
- data/lib/mongo/operation/write/insert/result.rb +2 -2
- data/lib/mongo/operation/write/update.rb +7 -1
- data/lib/mongo/operation/write/write_command_enabled.rb +20 -3
- data/lib/mongo/protocol.rb +3 -0
- data/lib/mongo/protocol/bit_vector.rb +2 -2
- data/lib/mongo/protocol/compressed.rb +135 -0
- data/lib/mongo/protocol/delete.rb +8 -6
- data/lib/mongo/protocol/get_more.rb +8 -6
- data/lib/mongo/protocol/insert.rb +8 -6
- data/lib/mongo/protocol/kill_cursors.rb +8 -6
- data/lib/mongo/protocol/message.rb +31 -3
- data/lib/mongo/protocol/msg.rb +172 -0
- data/lib/mongo/protocol/query.rb +26 -6
- data/lib/mongo/protocol/registry.rb +76 -0
- data/lib/mongo/protocol/reply.rb +10 -5
- data/lib/mongo/protocol/serializers.rb +224 -0
- data/lib/mongo/protocol/update.rb +8 -6
- data/lib/mongo/retryable.rb +4 -2
- data/lib/mongo/server.rb +6 -3
- data/lib/mongo/server/connectable.rb +1 -1
- data/lib/mongo/server/connection.rb +30 -8
- data/lib/mongo/server/description.rb +25 -1
- data/lib/mongo/server/description/features.rb +4 -1
- data/lib/mongo/server/monitor.rb +5 -0
- data/lib/mongo/server/monitor/connection.rb +50 -2
- data/lib/mongo/server_selector/nearest.rb +10 -4
- data/lib/mongo/server_selector/primary.rb +20 -0
- data/lib/mongo/server_selector/primary_preferred.rb +10 -4
- data/lib/mongo/server_selector/secondary.rb +10 -4
- data/lib/mongo/server_selector/secondary_preferred.rb +24 -4
- data/lib/mongo/session.rb +180 -0
- data/lib/mongo/session/server_session.rb +73 -0
- data/lib/mongo/session/session_pool.rb +161 -0
- data/lib/mongo/uri.rb +11 -0
- data/lib/mongo/version.rb +1 -1
- data/mongo.gemspec +2 -1
- data/spec/mongo/auth/cr_spec.rb +12 -0
- data/spec/mongo/auth/ldap_spec.rb +2 -0
- data/spec/mongo/auth/scram/conversation_spec.rb +6 -6
- data/spec/mongo/auth/scram_spec.rb +25 -1
- data/spec/mongo/auth/user/view_spec.rb +268 -76
- data/spec/mongo/auth/x509_spec.rb +2 -0
- data/spec/mongo/bulk_write_spec.rb +435 -5
- data/spec/mongo/client_spec.rb +356 -39
- data/spec/mongo/cluster/app_metadata_spec.rb +2 -2
- data/spec/mongo/cluster_spec.rb +176 -0
- data/spec/mongo/collection/view/aggregation_spec.rb +33 -12
- data/spec/mongo/collection/view/builder/find_command_spec.rb +46 -6
- data/spec/mongo/collection/view/change_stream_spec.rb +814 -0
- data/spec/mongo/collection/view/map_reduce_spec.rb +94 -17
- data/spec/mongo/collection/view/readable_spec.rb +3 -12
- data/spec/mongo/collection_spec.rb +1048 -42
- data/spec/mongo/cursor/builder/get_more_command_spec.rb +19 -0
- data/spec/mongo/cursor_spec.rb +2 -2
- data/spec/mongo/database_spec.rb +50 -1
- data/spec/mongo/grid/fs_bucket_spec.rb +225 -137
- data/spec/mongo/grid/stream/read_spec.rb +2 -2
- data/spec/mongo/index/view_spec.rb +146 -8
- data/spec/mongo/monitoring/event/secure_spec.rb +42 -0
- data/spec/mongo/operation/read/query_spec.rb +2 -1
- data/spec/mongo/operation/specifiable_spec.rb +2 -2
- data/spec/mongo/operation/write/command/delete_spec.rb +96 -13
- data/spec/mongo/operation/write/command/insert_spec.rb +111 -12
- data/spec/mongo/operation/write/command/update_spec.rb +93 -10
- data/spec/mongo/operation/write/delete_spec.rb +1 -1
- data/spec/mongo/operation/write/insert_spec.rb +1 -1
- data/spec/mongo/operation/write/update_spec.rb +1 -1
- data/spec/mongo/protocol/compressed_spec.rb +66 -0
- data/spec/mongo/protocol/delete_spec.rb +14 -0
- data/spec/mongo/protocol/get_more_spec.rb +14 -0
- data/spec/mongo/protocol/insert_spec.rb +14 -0
- data/spec/mongo/protocol/kill_cursors_spec.rb +14 -0
- data/spec/mongo/protocol/msg_spec.rb +499 -0
- data/spec/mongo/protocol/query_spec.rb +45 -0
- data/spec/mongo/protocol/registry_spec.rb +31 -0
- data/spec/mongo/protocol/reply_spec.rb +14 -0
- data/spec/mongo/protocol/update_spec.rb +14 -0
- data/spec/mongo/retryable_spec.rb +6 -2
- data/spec/mongo/sdam_spec.rb +4 -0
- data/spec/mongo/server/connection_spec.rb +4 -2
- data/spec/mongo/server/description_spec.rb +28 -1
- data/spec/mongo/session/server_session_spec.rb +16 -0
- data/spec/mongo/session/session_pool_spec.rb +194 -0
- data/spec/mongo/uri_spec.rb +31 -2
- data/spec/spec_helper.rb +104 -0
- data/spec/support/authorization.rb +6 -1
- data/spec/support/crud.rb +3 -1
- data/spec/support/crud/write.rb +6 -1
- data/spec/support/crud_tests/write/findOneAndUpdate-arrayFilters.yml +69 -0
- data/spec/support/crud_tests/write/updateMany-arrayFilters.yml +63 -0
- data/spec/support/crud_tests/write/updateOne-arrayFilters.yml +109 -0
- data/spec/support/sdam/rs/discover_arbiters.yml +1 -1
- data/spec/support/sdam/rs/discover_passives.yml +2 -2
- data/spec/support/sdam/rs/discover_primary.yml +1 -1
- data/spec/support/sdam/rs/discover_secondary.yml +1 -1
- data/spec/support/sdam/rs/discovery.yml +4 -4
- data/spec/support/sdam/rs/equal_electionids.yml +1 -0
- data/spec/support/sdam/rs/ghost_discovered.yml +1 -1
- data/spec/support/sdam/rs/hosts_differ_from_seeds.yml +1 -1
- data/spec/support/sdam/rs/ls_timeout.yml +88 -0
- data/spec/support/sdam/rs/member_reconfig.yml +2 -2
- data/spec/support/sdam/rs/member_standalone.yml +2 -2
- data/spec/support/sdam/rs/new_primary.yml +2 -2
- data/spec/support/sdam/rs/new_primary_new_electionid.yml +3 -0
- data/spec/support/sdam/rs/new_primary_new_setversion.yml +3 -0
- data/spec/support/sdam/rs/new_primary_wrong_set_name.yml +2 -2
- data/spec/support/sdam/rs/non_rs_member.yml +1 -1
- data/spec/support/sdam/rs/normalize_case.yml +1 -1
- data/spec/support/sdam/rs/null_election_id.yml +4 -0
- data/spec/support/sdam/rs/primary_becomes_standalone.yml +2 -2
- data/spec/support/sdam/rs/primary_changes_set_name.yml +2 -2
- data/spec/support/sdam/rs/primary_disconnect.yml +2 -2
- data/spec/support/sdam/rs/primary_disconnect_electionid.yml +5 -0
- data/spec/support/sdam/rs/primary_disconnect_setversion.yml +5 -0
- data/spec/support/sdam/rs/primary_hint_from_secondary_with_mismatched_me.yml +58 -0
- data/spec/support/sdam/rs/primary_reports_new_member.yml +4 -4
- data/spec/support/sdam/rs/primary_to_no_primary_mismatched_me.yml +2 -2
- data/spec/support/sdam/rs/primary_wrong_set_name.yml +1 -1
- data/spec/support/sdam/rs/response_from_removed.yml +2 -2
- data/spec/support/sdam/rs/rsother_discovered.yml +1 -1
- data/spec/support/sdam/rs/sec_not_auth.yml +1 -1
- data/spec/support/sdam/rs/secondary_wrong_set_name.yml +1 -1
- data/spec/support/sdam/rs/secondary_wrong_set_name_with_primary.yml +2 -2
- data/spec/support/sdam/rs/setversion_without_electionid.yml +2 -0
- data/spec/support/sdam/rs/stepdown_change_set_name.yml +2 -2
- data/spec/support/sdam/rs/unexpected_mongos.yml +1 -1
- data/spec/support/sdam/rs/use_setversion_without_electionid.yml +3 -0
- data/spec/support/sdam/rs/wrong_set_name.yml +1 -1
- data/spec/support/sdam/sharded/ls_timeout_mongos.yml +97 -0
- data/spec/support/sdam/sharded/mongos_disconnect.yml +3 -3
- data/spec/support/sdam/sharded/multiple_mongoses.yml +1 -1
- data/spec/support/sdam/sharded/non_mongos_removed.yml +1 -1
- data/spec/support/sdam/sharded/normalize_uri_case.yml +1 -1
- data/spec/support/sdam/single/direct_connection_external_ip.yml +1 -1
- data/spec/support/sdam/single/direct_connection_mongos.yml +1 -1
- data/spec/support/sdam/single/direct_connection_rsarbiter.yml +1 -1
- data/spec/support/sdam/single/direct_connection_rsprimary.yml +1 -1
- data/spec/support/sdam/single/direct_connection_rssecondary.yml +1 -1
- data/spec/support/sdam/single/direct_connection_slave.yml +1 -1
- data/spec/support/sdam/single/direct_connection_standalone.yml +1 -1
- data/spec/support/sdam/single/ls_timeout_standalone.yml +35 -0
- data/spec/support/sdam/single/not_ok_response.yml +1 -1
- data/spec/support/sdam/single/standalone_removed.yml +1 -1
- data/spec/support/sdam/single/unavailable_seed.yml +1 -1
- data/spec/support/server_discovery_and_monitoring.rb +4 -0
- data/spec/support/shared/session.rb +236 -0
- metadata +53 -15
- metadata.gz.sig +0 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
# Copyright (C) 2017 MongoDB, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Mongo
|
16
|
+
|
17
|
+
class Session
|
18
|
+
|
19
|
+
# An object representing the server-side session.
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
#
|
23
|
+
# @since 2.5.0
|
24
|
+
class ServerSession
|
25
|
+
|
26
|
+
# Regex for removing dashes from the UUID string.
|
27
|
+
#
|
28
|
+
# @since 2.5.0
|
29
|
+
DASH_REGEX = /\-/.freeze
|
30
|
+
|
31
|
+
# Pack directive for the UUID.
|
32
|
+
#
|
33
|
+
# @since 2.5.0
|
34
|
+
UUID_PACK = 'H*'.freeze
|
35
|
+
|
36
|
+
# The last time the server session was used.
|
37
|
+
#
|
38
|
+
# @since 2.5.0
|
39
|
+
attr_reader :last_use
|
40
|
+
|
41
|
+
# Initialize a ServerSession.
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# ServerSession.new
|
45
|
+
#
|
46
|
+
# @since 2.5.0
|
47
|
+
def initialize
|
48
|
+
set_last_use!
|
49
|
+
end
|
50
|
+
|
51
|
+
# Update the last_use attribute of the server session to now.
|
52
|
+
#
|
53
|
+
# @example Set the last use field to now.
|
54
|
+
# server_session.set_last_use!
|
55
|
+
#
|
56
|
+
# @since 2.5.0
|
57
|
+
def set_last_use!
|
58
|
+
@last_use = Time.now
|
59
|
+
end
|
60
|
+
|
61
|
+
# The session id of this server session.
|
62
|
+
#
|
63
|
+
# @example Get the session id.
|
64
|
+
# server_session.session_id
|
65
|
+
#
|
66
|
+
# @since 2.5.0
|
67
|
+
def session_id
|
68
|
+
@session_id ||= (bytes = [SecureRandom.uuid.gsub(DASH_REGEX, '')].pack(UUID_PACK)
|
69
|
+
BSON::Document.new(id: BSON::Binary.new(bytes, :uuid)))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
# Copyright (C) 2017 MongoDB, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Mongo
|
16
|
+
|
17
|
+
class Session
|
18
|
+
|
19
|
+
# A pool of server sessions.
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
#
|
23
|
+
# @since 2.5.0
|
24
|
+
class SessionPool
|
25
|
+
|
26
|
+
# The command sent to the server to end a session.
|
27
|
+
#
|
28
|
+
# @since 2.5.0
|
29
|
+
END_SESSION = { :endSessions => 1 }.freeze
|
30
|
+
|
31
|
+
# Create a SessionPool.
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# SessionPool.create(client)
|
35
|
+
#
|
36
|
+
# @param [ Mongo::Client ] client The client that will be associated with this
|
37
|
+
# session pool.
|
38
|
+
#
|
39
|
+
# @since 2.5.0
|
40
|
+
def self.create(client)
|
41
|
+
pool = new(client)
|
42
|
+
client.instance_variable_set(:@session_pool, pool)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Initialize a SessionPool.
|
46
|
+
#
|
47
|
+
# @example
|
48
|
+
# SessionPool.new(client)
|
49
|
+
#
|
50
|
+
# @param [ Mongo::Client ] client The client that will be associated with this
|
51
|
+
# session pool.
|
52
|
+
#
|
53
|
+
# @since 2.5.0
|
54
|
+
def initialize(client)
|
55
|
+
@queue = []
|
56
|
+
@mutex = Mutex.new
|
57
|
+
@client = client
|
58
|
+
end
|
59
|
+
|
60
|
+
# Checkout a session to be used in the context of a block and return the session back to
|
61
|
+
# the pool after the block completes.
|
62
|
+
#
|
63
|
+
# @example Checkout, use a session, and return it back to the pool after the block.
|
64
|
+
# pool.with_session do |session|
|
65
|
+
# ...
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# @yieldparam [ ServerSession ] The server session.
|
69
|
+
#
|
70
|
+
# @since 2.5.0
|
71
|
+
def with_session
|
72
|
+
server_session = checkout
|
73
|
+
result = yield(server_session)
|
74
|
+
result
|
75
|
+
ensure
|
76
|
+
begin; checkin(server_session) if server_session; rescue; end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Checkout a server session from the pool.
|
80
|
+
#
|
81
|
+
# @example Checkout a session.
|
82
|
+
# pool.checkout
|
83
|
+
#
|
84
|
+
# @return [ ServerSession ] The server session.
|
85
|
+
#
|
86
|
+
# @since 2.5.0
|
87
|
+
def checkout
|
88
|
+
@mutex.synchronize do
|
89
|
+
loop do
|
90
|
+
if @queue.empty?
|
91
|
+
return ServerSession.new
|
92
|
+
else
|
93
|
+
session = @queue.shift
|
94
|
+
unless about_to_expire?(session)
|
95
|
+
return session
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Checkin a server session to the pool.
|
103
|
+
#
|
104
|
+
# @example Checkin a session.
|
105
|
+
# pool.checkin(session)
|
106
|
+
#
|
107
|
+
# @param [ Session::ServerSession ] The session to checkin.
|
108
|
+
#
|
109
|
+
# @since 2.5.0
|
110
|
+
def checkin(session)
|
111
|
+
@mutex.synchronize do
|
112
|
+
prune!
|
113
|
+
unless about_to_expire?(session)
|
114
|
+
@queue.unshift(session)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# End all sessions in the pool by sending the endSessions command to the server.
|
120
|
+
#
|
121
|
+
# @example End all sessions.
|
122
|
+
# pool.end_sessions
|
123
|
+
#
|
124
|
+
# @since 2.5.0
|
125
|
+
def end_sessions
|
126
|
+
if @client
|
127
|
+
ids = @queue.collect { |s| s.session_id }
|
128
|
+
|
129
|
+
while !ids.empty?
|
130
|
+
begin
|
131
|
+
Operation::Commands::Command.new({
|
132
|
+
:selector => END_SESSION.merge(ids: ids.shift(10_000)),
|
133
|
+
:db_name => Database::ADMIN
|
134
|
+
}).execute(@client.cluster.next_primary)
|
135
|
+
rescue
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
def about_to_expire?(session)
|
144
|
+
if @client.logical_session_timeout
|
145
|
+
idle_time_minutes = (Time.now - session.last_use) / 60
|
146
|
+
(idle_time_minutes + 1) >= @client.logical_session_timeout
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def prune!
|
151
|
+
while !@queue.empty?
|
152
|
+
if about_to_expire?(@queue[-1])
|
153
|
+
@queue.pop
|
154
|
+
else
|
155
|
+
break
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
data/lib/mongo/uri.rb
CHANGED
@@ -395,6 +395,8 @@ module Mongo
|
|
395
395
|
|
396
396
|
# Client Options
|
397
397
|
uri_option 'appname', :app_name
|
398
|
+
uri_option 'compressors', :compressors, :type => :array
|
399
|
+
uri_option 'zlibcompressionlevel', :zlib_compression_level
|
398
400
|
|
399
401
|
# Casts option values that do not have a specifically provided
|
400
402
|
# transformation to the appropriate type.
|
@@ -572,5 +574,14 @@ module Mongo
|
|
572
574
|
set.merge(decode(k).downcase.to_sym => decode(v))
|
573
575
|
end
|
574
576
|
end
|
577
|
+
|
578
|
+
# Extract values from the string and put them into an array.
|
579
|
+
#
|
580
|
+
# @param [ String ] value The string to build an array from.
|
581
|
+
#
|
582
|
+
# @return [ Array ] The array built from the string.
|
583
|
+
def array(value)
|
584
|
+
value.split(',')
|
585
|
+
end
|
575
586
|
end
|
576
587
|
end
|
data/lib/mongo/version.rb
CHANGED
data/mongo.gemspec
CHANGED
data/spec/mongo/auth/cr_spec.rb
CHANGED
@@ -18,6 +18,8 @@ describe Mongo::Auth::CR do
|
|
18
18
|
double('cluster').tap do |cl|
|
19
19
|
allow(cl).to receive(:topology).and_return(topology)
|
20
20
|
allow(cl).to receive(:app_metadata).and_return(app_metadata)
|
21
|
+
allow(cl).to receive(:cluster_time).and_return(nil)
|
22
|
+
allow(cl).to receive(:update_cluster_time)
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
@@ -58,6 +60,16 @@ describe Mongo::Auth::CR do
|
|
58
60
|
cr.login(connection)
|
59
61
|
}.to raise_error(Mongo::Auth::Unauthorized)
|
60
62
|
end
|
63
|
+
|
64
|
+
context 'when compression is used', if: testing_compression? do
|
65
|
+
|
66
|
+
it 'does not compress the message' do
|
67
|
+
expect(Mongo::Protocol::Compressed).not_to receive(:new)
|
68
|
+
expect {
|
69
|
+
cr.login(connection)
|
70
|
+
}.to raise_error(Mongo::Auth::Unauthorized)
|
71
|
+
end
|
72
|
+
end
|
61
73
|
end
|
62
74
|
end
|
63
75
|
|
@@ -18,6 +18,8 @@ describe Mongo::Auth::LDAP do
|
|
18
18
|
double('cluster').tap do |cl|
|
19
19
|
allow(cl).to receive(:topology).and_return(topology)
|
20
20
|
allow(cl).to receive(:app_metadata).and_return(app_metadata)
|
21
|
+
allow(cl).to receive(:cluster_time).and_return(nil)
|
22
|
+
allow(cl).to receive(:update_cluster_time)
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
@@ -48,7 +48,7 @@ describe Mongo::Auth::SCRAM::Conversation do
|
|
48
48
|
describe '#continue' do
|
49
49
|
|
50
50
|
let(:reply) do
|
51
|
-
Mongo::Protocol::
|
51
|
+
Mongo::Protocol::Message.new
|
52
52
|
end
|
53
53
|
|
54
54
|
let(:documents) do
|
@@ -62,7 +62,7 @@ describe Mongo::Auth::SCRAM::Conversation do
|
|
62
62
|
|
63
63
|
before do
|
64
64
|
expect(SecureRandom).to receive(:base64).once.and_return('NDA2NzU3MDY3MDYwMTgy')
|
65
|
-
reply.
|
65
|
+
allow(reply).to receive(:documents).and_return(documents)
|
66
66
|
end
|
67
67
|
|
68
68
|
context 'when the server rnonce starts with the nonce' do
|
@@ -115,7 +115,7 @@ describe Mongo::Auth::SCRAM::Conversation do
|
|
115
115
|
describe '#finalize' do
|
116
116
|
|
117
117
|
let(:continue_reply) do
|
118
|
-
Mongo::Protocol::
|
118
|
+
Mongo::Protocol::Message.new
|
119
119
|
end
|
120
120
|
|
121
121
|
let(:continue_documents) do
|
@@ -134,7 +134,7 @@ describe Mongo::Auth::SCRAM::Conversation do
|
|
134
134
|
end
|
135
135
|
|
136
136
|
let(:reply) do
|
137
|
-
Mongo::Protocol::
|
137
|
+
Mongo::Protocol::Message.new
|
138
138
|
end
|
139
139
|
|
140
140
|
let(:documents) do
|
@@ -148,8 +148,8 @@ describe Mongo::Auth::SCRAM::Conversation do
|
|
148
148
|
|
149
149
|
before do
|
150
150
|
expect(SecureRandom).to receive(:base64).once.and_return('NDA2NzU3MDY3MDYwMTgy')
|
151
|
-
continue_reply.
|
152
|
-
reply.
|
151
|
+
allow(continue_reply).to receive(:documents).and_return(continue_documents)
|
152
|
+
allow(reply).to receive(:documents).and_return(documents)
|
153
153
|
end
|
154
154
|
|
155
155
|
context 'when the verifier matches the server signature' do
|
@@ -18,6 +18,8 @@ describe Mongo::Auth::SCRAM do
|
|
18
18
|
double('cluster').tap do |cl|
|
19
19
|
allow(cl).to receive(:topology).and_return(topology)
|
20
20
|
allow(cl).to receive(:app_metadata).and_return(app_metadata)
|
21
|
+
allow(cl).to receive(:cluster_time).and_return(nil)
|
22
|
+
allow(cl).to receive(:update_cluster_time)
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
@@ -54,6 +56,16 @@ describe Mongo::Auth::SCRAM do
|
|
54
56
|
cr.login(connection)
|
55
57
|
}.to raise_error(Mongo::Auth::Unauthorized)
|
56
58
|
end
|
59
|
+
|
60
|
+
context 'when compression is used', if: testing_compression? do
|
61
|
+
|
62
|
+
it 'does not compress the message' do
|
63
|
+
expect(Mongo::Protocol::Compressed).not_to receive(:new)
|
64
|
+
expect {
|
65
|
+
cr.login(connection)
|
66
|
+
}.to raise_error(Mongo::Auth::Unauthorized)
|
67
|
+
end
|
68
|
+
end
|
57
69
|
end
|
58
70
|
end
|
59
71
|
|
@@ -67,8 +79,20 @@ describe Mongo::Auth::SCRAM do
|
|
67
79
|
cr.login(connection).documents[0]
|
68
80
|
end
|
69
81
|
|
70
|
-
|
82
|
+
after do
|
83
|
+
root_user.instance_variable_set(:@client_key, nil)
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'logs the user into the connection and caches the client key', if: list_command_enabled? do
|
71
87
|
expect(login['ok']).to eq(1)
|
88
|
+
expect(root_user.send(:client_key)).not_to be_nil
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'raises an exception when an incorrect client key is set', if: list_command_enabled? do
|
92
|
+
root_user.instance_variable_set(:@client_key, "incorrect client key")
|
93
|
+
expect {
|
94
|
+
cr.login(connection)
|
95
|
+
}.to raise_error(Mongo::Auth::Unauthorized)
|
72
96
|
end
|
73
97
|
end
|
74
98
|
end
|
@@ -6,33 +6,67 @@ describe Mongo::Auth::User::View do
|
|
6
6
|
described_class.new(root_authorized_client.database)
|
7
7
|
end
|
8
8
|
|
9
|
+
after do
|
10
|
+
begin; view.remove('durran'); rescue; end
|
11
|
+
end
|
12
|
+
|
9
13
|
describe '#create' do
|
10
14
|
|
11
|
-
|
12
|
-
view.create(
|
13
|
-
'durran',
|
14
|
-
password: 'password', roles: [ Mongo::Auth::Roles::READ_WRITE ]
|
15
|
-
)
|
16
|
-
end
|
15
|
+
context 'when a session is not used' do
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
let!(:response) do
|
18
|
+
view.create(
|
19
|
+
'durran',
|
20
|
+
password: 'password', roles: [Mongo::Auth::Roles::READ_WRITE]
|
21
|
+
)
|
22
|
+
end
|
21
23
|
|
22
|
-
|
24
|
+
context 'when user creation was successful' do
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
+
it 'saves the user in the database' do
|
27
|
+
expect(response).to be_successful
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when compression is used', if: testing_compression? do
|
31
|
+
|
32
|
+
it 'does not compress the message' do
|
33
|
+
# The dropUser command message will be compressed, so expect instantiation once.
|
34
|
+
expect(Mongo::Protocol::Compressed).to receive(:new).once.and_call_original
|
35
|
+
expect(response).to be_successful
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when creation was not successful' do
|
41
|
+
|
42
|
+
it 'raises an exception' do
|
43
|
+
expect {
|
44
|
+
view.create('durran', password: 'password')
|
45
|
+
}.to raise_error(Mongo::Error::OperationFailure)
|
46
|
+
end
|
26
47
|
end
|
27
48
|
end
|
28
49
|
|
29
|
-
context 'when
|
50
|
+
context 'when a session is used' do
|
51
|
+
|
52
|
+
let(:operation) do
|
53
|
+
view.create(
|
54
|
+
'durran',
|
55
|
+
password: 'password',
|
56
|
+
roles: [Mongo::Auth::Roles::READ_WRITE],
|
57
|
+
session: session
|
58
|
+
)
|
59
|
+
end
|
30
60
|
|
31
|
-
|
32
|
-
|
33
|
-
view.create('durran', password: 'password')
|
34
|
-
}.to raise_error(Mongo::Error::OperationFailure)
|
61
|
+
let(:session) do
|
62
|
+
client.start_session
|
35
63
|
end
|
64
|
+
|
65
|
+
let(:client) do
|
66
|
+
root_authorized_client
|
67
|
+
end
|
68
|
+
|
69
|
+
it_behaves_like 'an operation using a session'
|
36
70
|
end
|
37
71
|
end
|
38
72
|
|
@@ -41,114 +75,272 @@ describe Mongo::Auth::User::View do
|
|
41
75
|
before do
|
42
76
|
view.create(
|
43
77
|
'durran',
|
44
|
-
password: 'password', roles: [
|
78
|
+
password: 'password', roles: [Mongo::Auth::Roles::READ_WRITE]
|
45
79
|
)
|
46
80
|
end
|
47
81
|
|
48
|
-
after do
|
49
|
-
view.remove('durran')
|
50
|
-
end
|
51
|
-
|
52
82
|
context 'when a user password is updated' do
|
53
83
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
84
|
+
context 'when a session is not used' do
|
85
|
+
|
86
|
+
let!(:response) do
|
87
|
+
view.update(
|
88
|
+
'durran',
|
89
|
+
password: '123', roles: [ Mongo::Auth::Roles::READ_WRITE ]
|
90
|
+
)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'updates the password' do
|
94
|
+
expect(response).to be_successful
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'when compression is used', if: testing_compression? do
|
98
|
+
|
99
|
+
it 'does not compress the message' do
|
100
|
+
# The dropUser command message will be compressed, so expect instantiation once.
|
101
|
+
expect(Mongo::Protocol::Compressed).to receive(:new).once.and_call_original
|
102
|
+
expect(response).to be_successful
|
103
|
+
end
|
104
|
+
end
|
59
105
|
end
|
60
106
|
|
61
|
-
|
62
|
-
|
107
|
+
context 'when a session is used' do
|
108
|
+
|
109
|
+
let(:operation) do
|
110
|
+
view.update(
|
111
|
+
'durran',
|
112
|
+
password: '123',
|
113
|
+
roles: [ Mongo::Auth::Roles::READ_WRITE ],
|
114
|
+
session: session
|
115
|
+
)
|
116
|
+
end
|
117
|
+
|
118
|
+
let(:session) do
|
119
|
+
client.start_session
|
120
|
+
end
|
121
|
+
|
122
|
+
let(:client) do
|
123
|
+
root_authorized_client
|
124
|
+
end
|
125
|
+
|
126
|
+
it_behaves_like 'an operation using a session'
|
63
127
|
end
|
64
128
|
end
|
65
129
|
|
66
130
|
context 'when the roles of a user are updated' do
|
67
131
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
132
|
+
context 'when a session is not used' do
|
133
|
+
|
134
|
+
let!(:response) do
|
135
|
+
view.update(
|
136
|
+
'durran',
|
137
|
+
password: 'password', roles: [ Mongo::Auth::Roles::READ ]
|
138
|
+
)
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'updates the roles' do
|
142
|
+
expect(response).to be_successful
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'when compression is used', if: testing_compression? do
|
146
|
+
|
147
|
+
it 'does not compress the message' do
|
148
|
+
# The dropUser command message will be compressed, so expect instantiation once.
|
149
|
+
expect(Mongo::Protocol::Compressed).to receive(:new).once.and_call_original
|
150
|
+
expect(response).to be_successful
|
151
|
+
end
|
152
|
+
end
|
73
153
|
end
|
74
154
|
|
75
|
-
|
76
|
-
|
155
|
+
context 'when a session is used' do
|
156
|
+
|
157
|
+
let(:operation) do
|
158
|
+
view.update(
|
159
|
+
'durran',
|
160
|
+
password: 'password',
|
161
|
+
roles: [ Mongo::Auth::Roles::READ ],
|
162
|
+
session: session
|
163
|
+
)
|
164
|
+
end
|
165
|
+
|
166
|
+
let(:session) do
|
167
|
+
client.start_session
|
168
|
+
end
|
169
|
+
|
170
|
+
let(:client) do
|
171
|
+
root_authorized_client
|
172
|
+
end
|
173
|
+
|
174
|
+
it_behaves_like 'an operation using a session'
|
77
175
|
end
|
78
176
|
end
|
79
177
|
end
|
80
178
|
|
81
179
|
describe '#remove' do
|
82
180
|
|
83
|
-
context 'when
|
181
|
+
context 'when a session is not used' do
|
84
182
|
|
85
|
-
|
86
|
-
view.create(
|
87
|
-
'durran',
|
88
|
-
password: 'password', roles: [ Mongo::Auth::Roles::READ_WRITE ]
|
89
|
-
)
|
90
|
-
end
|
183
|
+
context 'when user removal was successful' do
|
91
184
|
|
92
|
-
|
93
|
-
|
185
|
+
before do
|
186
|
+
view.create(
|
187
|
+
'durran',
|
188
|
+
password: 'password', roles: [ Mongo::Auth::Roles::READ_WRITE ]
|
189
|
+
)
|
190
|
+
end
|
191
|
+
|
192
|
+
let(:response) do
|
193
|
+
view.remove('durran')
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'saves the user in the database' do
|
197
|
+
expect(response).to be_successful
|
198
|
+
end
|
94
199
|
end
|
95
200
|
|
96
|
-
|
97
|
-
|
201
|
+
context 'when removal was not successful' do
|
202
|
+
|
203
|
+
it 'raises an exception', if: write_command_enabled? do
|
204
|
+
expect {
|
205
|
+
view.remove('notauser')
|
206
|
+
}.to raise_error(Mongo::Error::OperationFailure)
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'does not raise an exception', unless: write_command_enabled? do
|
210
|
+
expect(view.remove('notauser').written_count).to eq(0)
|
211
|
+
end
|
98
212
|
end
|
99
213
|
end
|
100
214
|
|
101
|
-
context 'when
|
215
|
+
context 'when a session is used' do
|
216
|
+
|
217
|
+
context 'when user removal was successful' do
|
102
218
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
219
|
+
before do
|
220
|
+
view.create(
|
221
|
+
'durran',
|
222
|
+
password: 'password', roles: [ Mongo::Auth::Roles::READ_WRITE ]
|
223
|
+
)
|
224
|
+
end
|
225
|
+
|
226
|
+
let(:operation) do
|
227
|
+
view.remove('durran', session: session)
|
228
|
+
end
|
229
|
+
|
230
|
+
let(:session) do
|
231
|
+
client.start_session
|
232
|
+
end
|
233
|
+
|
234
|
+
let(:client) do
|
235
|
+
root_authorized_client
|
236
|
+
end
|
237
|
+
|
238
|
+
it_behaves_like 'an operation using a session'
|
107
239
|
end
|
108
240
|
|
109
|
-
|
110
|
-
|
241
|
+
context 'when removal was not successful' do
|
242
|
+
|
243
|
+
let(:failed_operation) do
|
244
|
+
view.remove('notauser', session: session)
|
245
|
+
end
|
246
|
+
|
247
|
+
let(:session) do
|
248
|
+
client.start_session
|
249
|
+
end
|
250
|
+
|
251
|
+
let(:client) do
|
252
|
+
root_authorized_client
|
253
|
+
end
|
254
|
+
|
255
|
+
it_behaves_like 'a failed operation using a session'
|
111
256
|
end
|
112
257
|
end
|
113
258
|
end
|
114
259
|
|
115
260
|
describe '#info' do
|
116
261
|
|
117
|
-
context 'when a
|
262
|
+
context 'when a session is not used' do
|
118
263
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
264
|
+
context 'when a user exists in the database' do
|
265
|
+
|
266
|
+
before do
|
267
|
+
view.create(
|
268
|
+
'emily',
|
269
|
+
password: 'password'
|
270
|
+
)
|
271
|
+
end
|
272
|
+
|
273
|
+
after do
|
274
|
+
view.remove('emily')
|
275
|
+
end
|
125
276
|
|
126
|
-
|
127
|
-
|
277
|
+
it 'returns information for that user' do
|
278
|
+
expect(view.info('emily')).to_not be_empty
|
279
|
+
end
|
128
280
|
end
|
129
281
|
|
130
|
-
|
131
|
-
|
282
|
+
context 'when a user does not exist in the database' do
|
283
|
+
|
284
|
+
it 'returns nil' do
|
285
|
+
expect(view.info('emily')).to be_empty
|
286
|
+
end
|
132
287
|
end
|
133
|
-
end
|
134
288
|
|
135
|
-
|
289
|
+
context 'when a user is not authorized' do
|
136
290
|
|
137
|
-
|
138
|
-
|
291
|
+
let(:view) do
|
292
|
+
described_class.new(unauthorized_client.database)
|
293
|
+
end
|
294
|
+
|
295
|
+
it 'raises an OperationFailure', if: auth_enabled? do
|
296
|
+
expect{
|
297
|
+
view.info('emily')
|
298
|
+
}.to raise_exception(Mongo::Error::OperationFailure)
|
299
|
+
end
|
139
300
|
end
|
140
301
|
end
|
141
302
|
|
142
|
-
context 'when a
|
303
|
+
context 'when a session is used' do
|
304
|
+
|
305
|
+
context 'when a user exists in the database' do
|
306
|
+
|
307
|
+
before do
|
308
|
+
view.create(
|
309
|
+
'durran',
|
310
|
+
password: 'password'
|
311
|
+
)
|
312
|
+
end
|
313
|
+
|
314
|
+
let(:operation) do
|
315
|
+
view.info('durran', session: session)
|
316
|
+
end
|
317
|
+
|
318
|
+
let(:session) do
|
319
|
+
client.start_session
|
320
|
+
end
|
143
321
|
|
144
|
-
|
145
|
-
|
322
|
+
let(:client) do
|
323
|
+
root_authorized_client
|
324
|
+
end
|
325
|
+
|
326
|
+
it_behaves_like 'an operation using a session'
|
146
327
|
end
|
147
328
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
329
|
+
context 'when a user does not exist in the database' do
|
330
|
+
|
331
|
+
let(:operation) do
|
332
|
+
view.info('emily', session: session)
|
333
|
+
end
|
334
|
+
|
335
|
+
let(:session) do
|
336
|
+
client.start_session
|
337
|
+
end
|
338
|
+
|
339
|
+
let(:client) do
|
340
|
+
root_authorized_client
|
341
|
+
end
|
342
|
+
|
343
|
+
it_behaves_like 'an operation using a session'
|
152
344
|
end
|
153
345
|
end
|
154
346
|
end
|