mongo 2.16.2 → 2.17.0
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 +0 -0
- data/README.md +1 -1
- data/lib/mongo/auth/aws/request.rb +0 -1
- data/lib/mongo/client.rb +4 -0
- data/lib/mongo/collection/view/aggregation.rb +62 -17
- data/lib/mongo/collection/view/builder/aggregation.rb +11 -13
- data/lib/mongo/collection/view/builder/map_reduce.rb +5 -8
- data/lib/mongo/collection/view/change_stream.rb +7 -3
- data/lib/mongo/collection/view/iterable.rb +2 -3
- data/lib/mongo/collection/view/map_reduce.rb +3 -14
- data/lib/mongo/collection/view/readable.rb +24 -1
- data/lib/mongo/collection/view/writable.rb +23 -0
- data/lib/mongo/collection.rb +21 -1
- data/lib/mongo/database/view.rb +4 -2
- data/lib/mongo/database.rb +6 -6
- data/lib/mongo/error/snapshot_session_invalid_server_version.rb +31 -0
- data/lib/mongo/error/snapshot_session_transaction_prohibited.rb +30 -0
- data/lib/mongo/error.rb +2 -0
- data/lib/mongo/operation/delete/op_msg.rb +2 -1
- data/lib/mongo/operation/find/builder/command.rb +1 -0
- data/lib/mongo/operation/result.rb +6 -0
- data/lib/mongo/operation/shared/executable.rb +4 -0
- data/lib/mongo/operation/shared/sessions_supported.rb +18 -2
- data/lib/mongo/operation/update/op_msg.rb +2 -1
- data/lib/mongo/server/description/features.rb +3 -1
- data/lib/mongo/server_selector/base.rb +26 -4
- data/lib/mongo/session.rb +19 -0
- data/lib/mongo/socket/ocsp_cache.rb +2 -3
- data/lib/mongo/socket.rb +1 -5
- data/lib/mongo/utils.rb +0 -6
- data/lib/mongo/version.rb +1 -1
- data/mongo.gemspec +1 -1
- data/spec/integration/read_preference_spec.rb +16 -12
- data/spec/lite_spec_helper.rb +0 -7
- data/spec/mongo/collection/view/aggregation_spec.rb +71 -95
- data/spec/mongo/collection/view/change_stream_spec.rb +1 -1
- data/spec/mongo/collection/view/map_reduce_spec.rb +14 -17
- data/spec/mongo/operation/read_preference_op_msg_spec.rb +24 -1
- data/spec/mongo/server_selector_spec.rb +136 -15
- data/spec/mongo/socket/ssl_spec.rb +26 -58
- data/spec/mongo/utils_spec.rb +0 -14
- data/spec/runners/auth.rb +1 -1
- data/spec/runners/change_streams/spec.rb +1 -1
- data/spec/runners/cmap.rb +1 -1
- data/spec/runners/command_monitoring.rb +1 -1
- data/spec/runners/connection_string.rb +1 -1
- data/spec/runners/crud/spec.rb +3 -1
- data/spec/runners/crud/verifier.rb +1 -2
- data/spec/runners/gridfs.rb +1 -1
- data/spec/runners/read_write_concern_document.rb +1 -1
- data/spec/runners/sdam.rb +1 -1
- data/spec/runners/server_selection.rb +1 -1
- data/spec/runners/server_selection_rtt.rb +1 -1
- data/spec/runners/unified/assertions.rb +3 -1
- data/spec/runners/unified/crud_operations.rb +77 -23
- data/spec/runners/unified/ddl_operations.rb +29 -1
- data/spec/runners/unified/entity_map.rb +3 -3
- data/spec/runners/unified/support_operations.rb +6 -1
- data/spec/runners/unified/test.rb +15 -3
- data/spec/runners/unified/test_group.rb +1 -1
- data/spec/spec_tests/data/crud_unified/aggregate-let.yml +138 -0
- data/spec/spec_tests/data/crud_unified/aggregate-write-readPreference.yml +155 -0
- data/spec/spec_tests/data/crud_unified/db-aggregate-write-readPreference.yml +151 -0
- data/spec/spec_tests/data/crud_unified/deleteMany-let.yml +91 -0
- data/spec/spec_tests/data/crud_unified/deleteOne-let.yml +89 -0
- data/spec/spec_tests/data/crud_unified/find-let.yml +71 -0
- data/spec/spec_tests/data/crud_unified/findOneAndDelete-let.yml +88 -0
- data/spec/spec_tests/data/crud_unified/findOneAndReplace-let.yml +94 -0
- data/spec/spec_tests/data/crud_unified/findOneAndUpdate-let.yml +96 -0
- data/spec/spec_tests/data/crud_unified/updateMany-let.yml +103 -0
- data/spec/spec_tests/data/crud_unified/updateOne-let.yml +98 -0
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/DefaultNoMaxStaleness.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/LastUpdateTime.yml +3 -3
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Nearest.yml +3 -3
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Nearest2.yml +3 -3
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred_tags.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Secondary.yml +4 -4
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred_tags.yml +4 -4
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/ZeroMaxStaleness.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/DefaultNoMaxStaleness.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LastUpdateTime.yml +3 -3
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LongHeartbeat.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LongHeartbeat2.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/MaxStalenessTooSmall.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/MaxStalenessWithModePrimary.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest.yml +3 -3
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest2.yml +3 -3
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest_tags.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags.yml +5 -5
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags2.yml +3 -3
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Secondary_tags.yml +5 -5
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Secondary_tags2.yml +3 -3
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/ZeroMaxStaleness.yml +2 -2
- data/spec/spec_tests/data/max_staleness/Sharded/SmallMaxStaleness.yml +2 -2
- data/spec/spec_tests/data/max_staleness/Single/SmallMaxStaleness.yml +1 -1
- data/spec/spec_tests/data/max_staleness/Unknown/SmallMaxStaleness.yml +1 -1
- data/spec/spec_tests/data/sessions_unified/snapshot-sessions-not-supported-client-error.yml +69 -0
- data/spec/spec_tests/data/sessions_unified/snapshot-sessions-not-supported-server-error.yml +102 -0
- data/spec/spec_tests/data/sessions_unified/snapshot-sessions-unsupported-ops.yml +258 -0
- data/spec/spec_tests/data/sessions_unified/snapshot-sessions.yml +482 -0
- data/spec/spec_tests/seed_list_discovery_spec.rb +1 -1
- data/spec/spec_tests/sessions_unified_spec.rb +13 -0
- data/spec/support/utils.rb +0 -31
- data.tar.gz.sig +3 -1
- metadata +1051 -1018
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
# Copyright (C) 2021 MongoDB Inc.
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
module Mongo
|
|
19
|
+
class Error
|
|
20
|
+
|
|
21
|
+
# Exception raised if a transaction is attempted on a snapshot session.
|
|
22
|
+
class SnapshotSessionTransactionProhibited < Error
|
|
23
|
+
|
|
24
|
+
# Instantiate the new exception.
|
|
25
|
+
def initialize
|
|
26
|
+
super("Transactions are not supported in snapshot sessions")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/mongo/error.rb
CHANGED
|
@@ -223,6 +223,8 @@ require 'mongo/error/no_server_available'
|
|
|
223
223
|
require 'mongo/error/no_srv_records'
|
|
224
224
|
require 'mongo/error/session_ended'
|
|
225
225
|
require 'mongo/error/sessions_not_supported'
|
|
226
|
+
require 'mongo/error/snapshot_session_invalid_server_version'
|
|
227
|
+
require 'mongo/error/snapshot_session_transaction_prohibited'
|
|
226
228
|
require 'mongo/error/operation_failure'
|
|
227
229
|
require 'mongo/error/pool_closed_error'
|
|
228
230
|
require 'mongo/error/raise_original_error'
|
|
@@ -37,7 +37,8 @@ module Mongo
|
|
|
37
37
|
{ delete: coll_name,
|
|
38
38
|
Protocol::Msg::DATABASE_IDENTIFIER => db_name,
|
|
39
39
|
ordered: ordered?,
|
|
40
|
-
|
|
40
|
+
let: spec[:let],
|
|
41
|
+
}.compact.tap do |selector|
|
|
41
42
|
if hint = spec[:hint]
|
|
42
43
|
validate_hint_on_update(connection, selector)
|
|
43
44
|
selector[:hint] = hint
|
|
@@ -429,6 +429,12 @@ module Mongo
|
|
|
429
429
|
!!(first_document && first_document['writeConcernError'])
|
|
430
430
|
end
|
|
431
431
|
|
|
432
|
+
def snapshot_timestamp
|
|
433
|
+
if doc = reply.documents.first
|
|
434
|
+
doc['cursor']&.[]('atClusterTime') || doc['atClusterTime']
|
|
435
|
+
end
|
|
436
|
+
end
|
|
437
|
+
|
|
432
438
|
private
|
|
433
439
|
|
|
434
440
|
def aggregate_returned_count
|
|
@@ -199,8 +199,13 @@ module Mongo
|
|
|
199
199
|
read_doc
|
|
200
200
|
else
|
|
201
201
|
# In replica sets, read preference is passed to the server if one
|
|
202
|
-
# is specified by the application,
|
|
203
|
-
read&.to_doc
|
|
202
|
+
# is specified by the application, except for primary read preferences.
|
|
203
|
+
read_doc = BSON::Document.new(read&.to_doc || {})
|
|
204
|
+
if [nil, 'primary'].include?(read_doc['mode'])
|
|
205
|
+
nil
|
|
206
|
+
else
|
|
207
|
+
read_doc
|
|
208
|
+
end
|
|
204
209
|
end
|
|
205
210
|
|
|
206
211
|
if read_doc
|
|
@@ -224,6 +229,17 @@ module Mongo
|
|
|
224
229
|
then
|
|
225
230
|
sel[:recoveryToken] = session.recovery_token
|
|
226
231
|
end
|
|
232
|
+
|
|
233
|
+
if session.snapshot?
|
|
234
|
+
unless connection.description.server_version_gte?('5.0')
|
|
235
|
+
raise Error::SnapshotSessionInvalidServerVersion
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
sel[:readConcern] = {level: 'snapshot'}
|
|
239
|
+
if session.snapshot_timestamp
|
|
240
|
+
sel[:readConcern][:atClusterTime] = session.snapshot_timestamp
|
|
241
|
+
end
|
|
242
|
+
end
|
|
227
243
|
end
|
|
228
244
|
|
|
229
245
|
def build_message(connection, context)
|
|
@@ -35,9 +35,11 @@ module Mongo
|
|
|
35
35
|
# - 8 => 4.2
|
|
36
36
|
# - 9 => 4.4
|
|
37
37
|
# - 13 => 5.0
|
|
38
|
+
# - 14 => 5.1
|
|
38
39
|
#
|
|
39
40
|
# @since 2.0.0
|
|
40
41
|
MAPPINGS = {
|
|
42
|
+
merge_out_on_secondary: 13,
|
|
41
43
|
retryable_write_error_label: 9,
|
|
42
44
|
commit_quorum: 9,
|
|
43
45
|
# Server versions older than 4.2 do not reliably validate options
|
|
@@ -78,7 +80,7 @@ module Mongo
|
|
|
78
80
|
# The wire protocol versions that this version of the driver supports.
|
|
79
81
|
#
|
|
80
82
|
# @since 2.0.0
|
|
81
|
-
DRIVER_WIRE_VERSIONS = (
|
|
83
|
+
DRIVER_WIRE_VERSIONS = (6..14).freeze
|
|
82
84
|
|
|
83
85
|
# Create the methods for each mapping to tell if they are supported.
|
|
84
86
|
#
|
|
@@ -162,6 +162,8 @@ module Mongo
|
|
|
162
162
|
# Deprecated and ignored.
|
|
163
163
|
# @param [ Session | nil ] session Optional session to take into account
|
|
164
164
|
# for mongos pinning. Added in version 2.10.0.
|
|
165
|
+
# @param [ true | false ] write_aggregation Whether we need a server that
|
|
166
|
+
# supports writing aggregations (e.g. with $merge/$out) on secondaries.
|
|
165
167
|
#
|
|
166
168
|
# @return [ Mongo::Server ] A server matching the server preference.
|
|
167
169
|
#
|
|
@@ -172,7 +174,7 @@ module Mongo
|
|
|
172
174
|
# lint mode is enabled.
|
|
173
175
|
#
|
|
174
176
|
# @since 2.0.0
|
|
175
|
-
def select_server(cluster, ping = nil, session = nil)
|
|
177
|
+
def select_server(cluster, ping = nil, session = nil, write_aggregation: false)
|
|
176
178
|
if cluster.topology.is_a?(Cluster::Topology::LoadBalanced)
|
|
177
179
|
return cluster.servers.first
|
|
178
180
|
end
|
|
@@ -243,7 +245,7 @@ module Mongo
|
|
|
243
245
|
=end
|
|
244
246
|
|
|
245
247
|
loop do
|
|
246
|
-
server = try_select_server(cluster)
|
|
248
|
+
server = try_select_server(cluster, write_aggregation: write_aggregation)
|
|
247
249
|
|
|
248
250
|
if server
|
|
249
251
|
unless cluster.topology.compatible?
|
|
@@ -294,11 +296,31 @@ module Mongo
|
|
|
294
296
|
# Tries to find a suitable server, returns the server if one is available
|
|
295
297
|
# or nil if there isn't a suitable server.
|
|
296
298
|
#
|
|
299
|
+
# @param [ Mongo::Cluster ] cluster The cluster from which to select
|
|
300
|
+
# an eligible server.
|
|
301
|
+
# @param [ true | false ] write_aggregation Whether we need a server that
|
|
302
|
+
# supports writing aggregations (e.g. with $merge/$out) on secondaries.
|
|
303
|
+
#
|
|
297
304
|
# @return [ Server | nil ] A suitable server, if one exists.
|
|
298
305
|
#
|
|
299
306
|
# @api private
|
|
300
|
-
def try_select_server(cluster)
|
|
301
|
-
servers =
|
|
307
|
+
def try_select_server(cluster, write_aggregation: false)
|
|
308
|
+
servers = if write_aggregation && cluster.replica_set?
|
|
309
|
+
# 1. Check if ALL servers in cluster support secondary writes.
|
|
310
|
+
is_write_supported = cluster.servers.reduce(true) do |res, server|
|
|
311
|
+
res && server.features.merge_out_on_secondary_enabled?
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
if is_write_supported
|
|
315
|
+
# 2. If all servers support secondary writes, we respect read preference.
|
|
316
|
+
suitable_servers(cluster)
|
|
317
|
+
else
|
|
318
|
+
# 3. Otherwise we fallback to primary for replica set.
|
|
319
|
+
[cluster.servers.detect(&:primary?)]
|
|
320
|
+
end
|
|
321
|
+
else
|
|
322
|
+
suitable_servers(cluster)
|
|
323
|
+
end
|
|
302
324
|
|
|
303
325
|
# This list of servers may be ordered in a specific way
|
|
304
326
|
# by the selector (e.g. for secondary preferred, the first
|
data/lib/mongo/session.rb
CHANGED
|
@@ -56,10 +56,16 @@ module Mongo
|
|
|
56
56
|
# - *:mode* -- the read preference as a string or symbol; valid values are
|
|
57
57
|
# *:primary*, *:primary_preferred*, *:secondary*, *:secondary_preferred*
|
|
58
58
|
# and *:nearest*.
|
|
59
|
+
# @option options [ true | false ] :snapshot Set up the session for
|
|
60
|
+
# snapshot reads.
|
|
59
61
|
#
|
|
60
62
|
# @since 2.5.0
|
|
61
63
|
# @api private
|
|
62
64
|
def initialize(server_session, client, options = {})
|
|
65
|
+
if options[:causal_consistency] && options[:snapshot]
|
|
66
|
+
raise ArgumentError, ':causal_consistency and :snapshot options cannot be both set on a session'
|
|
67
|
+
end
|
|
68
|
+
|
|
63
69
|
@server_session = server_session
|
|
64
70
|
options = options.dup
|
|
65
71
|
|
|
@@ -83,6 +89,12 @@ module Mongo
|
|
|
83
89
|
@client.cluster
|
|
84
90
|
end
|
|
85
91
|
|
|
92
|
+
# @return [ true | false ] Whether the session is configured for snapshot
|
|
93
|
+
# reads.
|
|
94
|
+
def snapshot?
|
|
95
|
+
!!options[:snapshot]
|
|
96
|
+
end
|
|
97
|
+
|
|
86
98
|
# @return [ BSON::Timestamp ] The latest seen operation time for this session.
|
|
87
99
|
#
|
|
88
100
|
# @since 2.5.0
|
|
@@ -506,6 +518,10 @@ module Mongo
|
|
|
506
518
|
=end
|
|
507
519
|
end
|
|
508
520
|
|
|
521
|
+
if snapshot?
|
|
522
|
+
raise Mongo::Error::SnapshotSessionTransactionProhibited
|
|
523
|
+
end
|
|
524
|
+
|
|
509
525
|
check_if_ended!
|
|
510
526
|
|
|
511
527
|
if within_states?(STARTING_TRANSACTION_STATE, TRANSACTION_IN_PROGRESS_STATE)
|
|
@@ -1024,6 +1040,9 @@ module Mongo
|
|
|
1024
1040
|
@server_session.txn_num
|
|
1025
1041
|
end
|
|
1026
1042
|
|
|
1043
|
+
# @api private
|
|
1044
|
+
attr_accessor :snapshot_timestamp
|
|
1045
|
+
|
|
1027
1046
|
private
|
|
1028
1047
|
|
|
1029
1048
|
# Get the read concern the session will use when starting a transaction.
|
|
@@ -21,8 +21,7 @@ module Mongo
|
|
|
21
21
|
# This module caches OCSP responses for their indicated validity time.
|
|
22
22
|
#
|
|
23
23
|
# The key is the CertificateId used for the OCSP request.
|
|
24
|
-
# The value is the SingleResponse
|
|
25
|
-
# emulation of it on Ruby 2.3.
|
|
24
|
+
# The value is the SingleResponse.
|
|
26
25
|
#
|
|
27
26
|
# @api private
|
|
28
27
|
module OcspCache
|
|
@@ -40,7 +39,7 @@ module Mongo
|
|
|
40
39
|
# expire by the time caller uses them. The caller should not perform
|
|
41
40
|
# update time checks on the returned response.
|
|
42
41
|
#
|
|
43
|
-
# @return [ OpenSSL::OCSP::SingleResponse
|
|
42
|
+
# @return [ OpenSSL::OCSP::SingleResponse ] The previously
|
|
44
43
|
# retrieved response.
|
|
45
44
|
module_function def get(cert_id)
|
|
46
45
|
resp = responses.detect do |resp|
|
data/lib/mongo/socket.rb
CHANGED
|
@@ -362,11 +362,7 @@ module Mongo
|
|
|
362
362
|
end
|
|
363
363
|
|
|
364
364
|
def allocate_string(capacity)
|
|
365
|
-
|
|
366
|
-
String.new('', :capacity => capacity, :encoding => 'BINARY')
|
|
367
|
-
else
|
|
368
|
-
('x'*capacity).force_encoding('BINARY')
|
|
369
|
-
end
|
|
365
|
+
String.new('', :capacity => capacity, :encoding => 'BINARY')
|
|
370
366
|
end
|
|
371
367
|
|
|
372
368
|
def read_buffer_size
|
data/lib/mongo/utils.rb
CHANGED
|
@@ -101,11 +101,5 @@ module Mongo
|
|
|
101
101
|
module_function def monotonic_time
|
|
102
102
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
103
103
|
end
|
|
104
|
-
|
|
105
|
-
# Hash#compact implementation for Ruby 2.3/2.4
|
|
106
|
-
# Implementation based on activesupport 5.2.3
|
|
107
|
-
module_function def slice_hash(hash, *keys)
|
|
108
|
-
keys.each_with_object({}) { |k, res| res[k] = hash[k] if hash.key?(k) }
|
|
109
|
-
end
|
|
110
104
|
end
|
|
111
105
|
end
|
data/lib/mongo/version.rb
CHANGED
data/mongo.gemspec
CHANGED
|
@@ -45,16 +45,6 @@ describe 'Read preference' do
|
|
|
45
45
|
{}
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
shared_examples_for 'sends expected read preference when reading' do
|
|
49
|
-
it 'sends expected read preference when reading' do
|
|
50
|
-
read_operation
|
|
51
|
-
|
|
52
|
-
event = subscriber.single_command_started_event('find')
|
|
53
|
-
actual_preference = event.command['$readPreference']
|
|
54
|
-
expect(actual_preference).to eq(expected_read_preference)
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
48
|
shared_examples_for 'does not send read preference when reading' do
|
|
59
49
|
it 'does not send read preference when reading' do
|
|
60
50
|
read_operation
|
|
@@ -95,7 +85,17 @@ describe 'Read preference' do
|
|
|
95
85
|
context 'server supporting OP_MSG' do
|
|
96
86
|
min_server_fcv '3.6'
|
|
97
87
|
|
|
98
|
-
|
|
88
|
+
it 'sends expected read preference when reading' do
|
|
89
|
+
read_operation
|
|
90
|
+
|
|
91
|
+
event = subscriber.single_command_started_event('find')
|
|
92
|
+
actual_preference = event.command['$readPreference']
|
|
93
|
+
if expected_read_preference&.[]("mode") == "primary"
|
|
94
|
+
expect(actual_preference).to be_nil
|
|
95
|
+
else
|
|
96
|
+
expect(actual_preference).to eq(expected_read_preference)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
99
|
end
|
|
100
100
|
end
|
|
101
101
|
|
|
@@ -307,7 +307,11 @@ describe 'Read preference' do
|
|
|
307
307
|
|
|
308
308
|
event = subscriber.single_command_started_event('find')
|
|
309
309
|
actual_preference = event.command['$readPreference']
|
|
310
|
-
|
|
310
|
+
if expected_read_preference&.[]("mode") == "primary"
|
|
311
|
+
expect(actual_preference).to be_nil
|
|
312
|
+
else
|
|
313
|
+
expect(actual_preference).to eq(expected_read_preference)
|
|
314
|
+
end
|
|
311
315
|
end
|
|
312
316
|
end
|
|
313
317
|
end
|
data/spec/lite_spec_helper.rb
CHANGED
|
@@ -157,13 +157,6 @@ RSpec.configure do |config|
|
|
|
157
157
|
end
|
|
158
158
|
|
|
159
159
|
if SpecConfig.instance.active_support?
|
|
160
|
-
require "active_support/version"
|
|
161
|
-
if ActiveSupport.version >= Gem::Version.new(7)
|
|
162
|
-
# ActiveSupport wants us to require ALL of it all of the time.
|
|
163
|
-
# See: https://github.com/rails/rails/issues/43851,
|
|
164
|
-
# https://github.com/rails/rails/issues/43889, etc.
|
|
165
|
-
require 'active_support'
|
|
166
|
-
end
|
|
167
160
|
require "active_support/time"
|
|
168
161
|
require 'mongo/active_support'
|
|
169
162
|
end
|
|
@@ -29,8 +29,16 @@ describe Mongo::Collection::View::Aggregation do
|
|
|
29
29
|
described_class.new(view, pipeline, options)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
let(:server) do
|
|
33
|
+
double('server')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
let(:session) do
|
|
37
|
+
double('session')
|
|
38
|
+
end
|
|
39
|
+
|
|
32
40
|
let(:aggregation_spec) do
|
|
33
|
-
aggregation.send(:aggregate_spec,
|
|
41
|
+
aggregation.send(:aggregate_spec, server, session, nil)
|
|
34
42
|
end
|
|
35
43
|
|
|
36
44
|
before do
|
|
@@ -351,15 +359,15 @@ describe Mongo::Collection::View::Aggregation do
|
|
|
351
359
|
|
|
352
360
|
describe '#aggregate_spec' do
|
|
353
361
|
|
|
354
|
-
context 'when
|
|
362
|
+
context 'when a read preference is given' do
|
|
355
363
|
|
|
356
364
|
let(:read_preference) do
|
|
357
|
-
{mode: :secondary}
|
|
365
|
+
BSON::Document.new({mode: :secondary})
|
|
358
366
|
end
|
|
359
367
|
|
|
360
368
|
it 'includes the read preference in the spec' do
|
|
361
|
-
|
|
362
|
-
expect(
|
|
369
|
+
spec = aggregation.send(:aggregate_spec, server, session, read_preference)
|
|
370
|
+
expect(spec[:read]).to eq(read_preference)
|
|
363
371
|
end
|
|
364
372
|
end
|
|
365
373
|
|
|
@@ -570,109 +578,77 @@ describe Mongo::Collection::View::Aggregation do
|
|
|
570
578
|
end
|
|
571
579
|
|
|
572
580
|
context 'when $out is in the pipeline' do
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
"
|
|
578
|
-
|
|
581
|
+
[['$out', 'string'], [:$out, 'symbol']].each do |op, type|
|
|
582
|
+
context "when #{op} is a #{type}" do
|
|
583
|
+
let(:pipeline) do
|
|
584
|
+
[{
|
|
585
|
+
"$group" => {
|
|
586
|
+
"_id" => "$city",
|
|
587
|
+
"totalpop" => { "$sum" => "$pop" }
|
|
588
|
+
}
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
op => 'output_collection'
|
|
579
592
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
'$out' => 'output_collection'
|
|
583
|
-
}
|
|
584
|
-
]
|
|
585
|
-
end
|
|
586
|
-
|
|
587
|
-
before do
|
|
588
|
-
authorized_client['output_collection'].delete_many
|
|
589
|
-
end
|
|
590
|
-
|
|
591
|
-
context 'when $out is a string' do
|
|
592
|
-
|
|
593
|
-
it 'does not allow the operation on a secondary' do
|
|
594
|
-
expect(aggregation.send(:secondary_ok?)).to be(false)
|
|
595
|
-
end
|
|
596
|
-
end
|
|
597
|
-
|
|
598
|
-
context 'when $out is a symbol' do
|
|
599
|
-
|
|
600
|
-
let(:pipeline) do
|
|
601
|
-
[{
|
|
602
|
-
"$group" => {
|
|
603
|
-
"_id" => "$city",
|
|
604
|
-
"totalpop" => { "$sum" => "$pop" }
|
|
605
|
-
}
|
|
606
|
-
},
|
|
607
|
-
{
|
|
608
|
-
:$out => 'output_collection'
|
|
609
|
-
}
|
|
610
|
-
]
|
|
611
|
-
end
|
|
612
|
-
|
|
613
|
-
it 'does not allow the operation on a secondary' do
|
|
614
|
-
expect(aggregation.send(:secondary_ok?)).to be(false)
|
|
615
|
-
end
|
|
616
|
-
end
|
|
593
|
+
]
|
|
594
|
+
end
|
|
617
595
|
|
|
596
|
+
before do
|
|
597
|
+
authorized_client['output_collection'].delete_many
|
|
598
|
+
end
|
|
618
599
|
|
|
619
|
-
|
|
600
|
+
let(:features) do
|
|
601
|
+
double()
|
|
602
|
+
end
|
|
620
603
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
end
|
|
604
|
+
let(:server) do
|
|
605
|
+
double().tap do |server|
|
|
606
|
+
allow(server).to receive(:features).and_return(features)
|
|
607
|
+
end
|
|
608
|
+
end
|
|
627
609
|
|
|
628
|
-
|
|
610
|
+
context 'when the view has a write concern' do
|
|
629
611
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
end
|
|
612
|
+
let(:collection) do
|
|
613
|
+
authorized_collection.with(write: INVALID_WRITE_CONCERN)
|
|
614
|
+
end
|
|
634
615
|
|
|
635
|
-
|
|
616
|
+
let(:view) do
|
|
617
|
+
Mongo::Collection::View.new(collection, selector, view_options)
|
|
618
|
+
end
|
|
636
619
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
end
|
|
620
|
+
context 'when the server supports write concern on the aggregate command' do
|
|
621
|
+
min_server_fcv '3.4'
|
|
640
622
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
623
|
+
it 'uses the write concern' do
|
|
624
|
+
expect {
|
|
625
|
+
aggregation.to_a
|
|
626
|
+
}.to raise_exception(Mongo::Error::OperationFailure)
|
|
627
|
+
end
|
|
628
|
+
end
|
|
644
629
|
|
|
645
|
-
|
|
646
|
-
|
|
630
|
+
context 'when the server does not support write concern on the aggregation command' do
|
|
631
|
+
max_server_version '3.2'
|
|
647
632
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
633
|
+
let(:documents) do
|
|
634
|
+
[
|
|
635
|
+
{ city: "Berlin", pop: 18913, neighborhood: "Kreuzberg" },
|
|
636
|
+
{ city: "Berlin", pop: 84143, neighborhood: "Mitte" },
|
|
637
|
+
{ city: "New York", pop: 40270, neighborhood: "Brooklyn" }
|
|
638
|
+
]
|
|
639
|
+
end
|
|
654
640
|
|
|
655
|
-
|
|
656
|
-
|
|
641
|
+
before do
|
|
642
|
+
authorized_collection.insert_many(documents)
|
|
643
|
+
aggregation.to_a
|
|
644
|
+
end
|
|
657
645
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
end
|
|
665
|
-
|
|
666
|
-
before do
|
|
667
|
-
authorized_collection.insert_many(documents)
|
|
668
|
-
aggregation.to_a
|
|
669
|
-
end
|
|
670
|
-
|
|
671
|
-
it 'does not apply the write concern' do
|
|
672
|
-
expect(authorized_client['output_collection'].find.count).to eq(2)
|
|
673
|
-
end
|
|
674
|
-
end
|
|
675
|
-
end
|
|
646
|
+
it 'does not apply the write concern' do
|
|
647
|
+
expect(authorized_client['output_collection'].find.count).to eq(2)
|
|
648
|
+
end
|
|
649
|
+
end
|
|
650
|
+
end
|
|
651
|
+
end
|
|
676
652
|
end
|
|
677
653
|
end
|
|
678
654
|
end
|
|
@@ -56,7 +56,7 @@ describe Mongo::Collection::View::ChangeStream do
|
|
|
56
56
|
|
|
57
57
|
let(:command_spec) do
|
|
58
58
|
change_stream.send(:instance_variable_set, '@resuming', false)
|
|
59
|
-
change_stream.send(:aggregate_spec, double('session'))
|
|
59
|
+
change_stream.send(:aggregate_spec, double('server'), double('session'), nil)
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
let(:cursor) do
|
|
@@ -60,6 +60,14 @@ describe Mongo::Collection::View::MapReduce do
|
|
|
60
60
|
described_class.new(view, map, reduce, options)
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
+
describe '#initialize' do
|
|
64
|
+
it 'warns of deprecation' do
|
|
65
|
+
Mongo::Logger.logger.should receive(:warn).with('MONGODB | The map_reduce operation is deprecated, please use the aggregation pipeline instead')
|
|
66
|
+
|
|
67
|
+
map_reduce
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
63
71
|
describe '#map_function' do
|
|
64
72
|
|
|
65
73
|
it 'returns the map function' do
|
|
@@ -672,7 +680,12 @@ describe Mongo::Collection::View::MapReduce do
|
|
|
672
680
|
end
|
|
673
681
|
|
|
674
682
|
it 'does not reroute the operation to a primary' do
|
|
675
|
-
|
|
683
|
+
# We produce a deprecation warning, but there shouldn't be
|
|
684
|
+
# the reroute warning.
|
|
685
|
+
expect(Mongo::Logger.logger).to receive(:warn).once do |msg|
|
|
686
|
+
expect(msg).not_to include('Rerouting the MapReduce operation to the primary server')
|
|
687
|
+
end
|
|
688
|
+
|
|
676
689
|
map_reduce.to_a
|
|
677
690
|
end
|
|
678
691
|
end
|
|
@@ -865,20 +878,4 @@ describe Mongo::Collection::View::MapReduce do
|
|
|
865
878
|
end
|
|
866
879
|
end
|
|
867
880
|
end
|
|
868
|
-
|
|
869
|
-
describe '#map_reduce_spec' do
|
|
870
|
-
context 'when read preference is given' do
|
|
871
|
-
let(:view_options) do
|
|
872
|
-
{ read: {mode: :secondary} }
|
|
873
|
-
end
|
|
874
|
-
|
|
875
|
-
context 'selector' do
|
|
876
|
-
# For compatibility with released versions of Mongoid, this method
|
|
877
|
-
# must return read preference under the :read key.
|
|
878
|
-
it 'contains read preference' do
|
|
879
|
-
map_reduce_spec[:selector][:read].should == {'mode' => :secondary}
|
|
880
|
-
end
|
|
881
|
-
end
|
|
882
|
-
end
|
|
883
|
-
end
|
|
884
881
|
end
|