mongo 2.18.0 → 2.18.1
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/lib/mongo/bulk_write.rb +1 -1
- data/lib/mongo/crypt/auto_encrypter.rb +30 -9
- data/lib/mongo/crypt/binding.rb +93 -1
- data/lib/mongo/crypt/explicit_encrypter.rb +5 -1
- data/lib/mongo/crypt/handle.rb +33 -0
- data/lib/mongo/cursor.rb +6 -1
- data/lib/mongo/operation/shared/sessions_supported.rb +7 -3
- data/lib/mongo/version.rb +1 -1
- data/spec/README.md +5 -1
- data/spec/integration/bulk_write_spec.rb +16 -0
- data/spec/integration/ocsp_verifier_spec.rb +2 -0
- data/spec/mongo/crypt/auto_encrypter_spec.rb +41 -6
- data/spec/mongo/crypt/binding/version_spec.rb +8 -0
- data/spec/mongo/crypt/handle_spec.rb +102 -0
- data/spec/mongo/cursor_spec.rb +50 -0
- data/spec/shared/lib/mrss/event_subscriber.rb +15 -5
- data/spec/spec_tests/data/change_streams_unified/change-streams-resume-errorLabels.yml +3 -0
- data/spec/spec_tests/data/client_side_encryption/unified/rewrapManyDataKey.yml +3 -3
- data/spec/spec_tests/data/sdam_integration/hello-command-error.yml +6 -14
- data/spec/spec_tests/data/sdam_integration/hello-network-error.yml +4 -14
- data/spec/spec_tests/data/sdam_integration/hello-timeout.yml +8 -14
- data/spec/spec_tests/data/transactions_unified/do-not-retry-read-in-transaction.yml +64 -0
- data/spec/spec_tests/data/transactions_unified/retryable-abort-handshake.yml +118 -0
- data/spec/spec_tests/data/transactions_unified/retryable-commit-handshake.yml +118 -0
- data/spec/support/certificates/retrieve-atlas-cert +38 -0
- data/spec/support/spec_config.rb +4 -0
- data.tar.gz.sig +0 -0
- metadata +10 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 664d381d4746fb4ff6282069f909a91a58f497220bae57656c265f52c5d99040
|
4
|
+
data.tar.gz: 85fa7fbf071c3e8fc4c1beb2215b3297a3af560130204dbd0f916adb272987f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2dcf66e773da4e2bdaf0a22d15a06eadbc5ab2bccffc29f012e2ae863e8148b597550ee680dc2556b40408f4c759b78b159b678cf494cf619c0975044d72d662
|
7
|
+
data.tar.gz: c120607792132931a54511db0a4ef62653393138e9da3fcf0ca0f0a85fde3aefe6b04782fd09125b0fe3085e50c66b1cd2f6e0c4743ae40e7094dc8e7892587a
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/lib/mongo/bulk_write.rb
CHANGED
@@ -221,7 +221,7 @@ module Mongo
|
|
221
221
|
def split_execute(name, values, connection, context, operation_id, result_combiner, session, txn_num)
|
222
222
|
execute_operation(name, values.shift(values.size / 2), connection, context, operation_id, result_combiner, session, txn_num)
|
223
223
|
|
224
|
-
txn_num = session.next_txn_num if txn_num
|
224
|
+
txn_num = session.next_txn_num if txn_num && !session.in_transaction?
|
225
225
|
execute_operation(name, values, connection, context, operation_id, result_combiner, session, txn_num)
|
226
226
|
end
|
227
227
|
|
@@ -81,6 +81,12 @@ module Mongo
|
|
81
81
|
# and schemaMap, an error will be raised.
|
82
82
|
# @option options [ Boolean | nil ] :bypass_query_analysis When true
|
83
83
|
# disables automatic analysis of outgoing commands.
|
84
|
+
# @option options [ String | nil ] :crypt_shared_lib_path Path that should
|
85
|
+
# be the used to load the crypt shared library. Providing this option
|
86
|
+
# overrides default crypt shared library load paths for libmongocrypt.
|
87
|
+
# @option options [ Boolean | nil ] :crypt_shared_lib_required Whether
|
88
|
+
# crypt shared library is required. If 'true', an error will be raised
|
89
|
+
# if a crypt_shared library cannot be loaded by libmongocrypt.
|
84
90
|
#
|
85
91
|
# @raise [ ArgumentError ] If required options are missing or incorrectly
|
86
92
|
# formatted.
|
@@ -95,17 +101,32 @@ module Mongo
|
|
95
101
|
schema_map: @options[:schema_map],
|
96
102
|
schema_map_path: @options[:schema_map_path],
|
97
103
|
encrypted_fields_map: @options[:encrypted_fields_map],
|
98
|
-
bypass_query_analysis: @options[:bypass_query_analysis]
|
104
|
+
bypass_query_analysis: @options[:bypass_query_analysis],
|
105
|
+
crypt_shared_lib_path: @options[:extra_options][:crypt_shared_lib_path],
|
106
|
+
crypt_shared_lib_required: @options[:extra_options][:crypt_shared_lib_required],
|
99
107
|
)
|
100
108
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
server_selection_timeout: 10,
|
107
|
-
database: @options[:client].options[:database]
|
109
|
+
@mongocryptd_options = @options[:extra_options].slice(
|
110
|
+
:mongocryptd_uri,
|
111
|
+
:mongocryptd_bypass_spawn,
|
112
|
+
:mongocryptd_spawn_path,
|
113
|
+
:mongocryptd_spawn_args
|
108
114
|
)
|
115
|
+
@mongocryptd_options[:mongocryptd_bypass_spawn] = @options[:bypass_auto_encryption] ||
|
116
|
+
@options[:extra_options][:mongocryptd_bypass_spawn] ||
|
117
|
+
@crypt_handle.crypt_shared_lib_available? ||
|
118
|
+
@options[:extra_options][:crypt_shared_lib_required]
|
119
|
+
|
120
|
+
if !@options[:extra_options][:crypt_shared_lib_required]
|
121
|
+
# Set server selection timeout to 1 to prevent the client waiting for a
|
122
|
+
# long timeout before spawning mongocryptd
|
123
|
+
@mongocryptd_client = Client.new(
|
124
|
+
@options[:extra_options][:mongocryptd_uri],
|
125
|
+
monitoring_io: @options[:client].options[:monitoring_io],
|
126
|
+
server_selection_timeout: 10,
|
127
|
+
database: @options[:client].options[:database]
|
128
|
+
)
|
129
|
+
end
|
109
130
|
|
110
131
|
begin
|
111
132
|
@encryption_io = EncryptionIO.new(
|
@@ -118,7 +139,7 @@ module Mongo
|
|
118
139
|
)
|
119
140
|
rescue
|
120
141
|
begin
|
121
|
-
@mongocryptd_client
|
142
|
+
@mongocryptd_client&.close
|
122
143
|
rescue => e
|
123
144
|
log_warn("Error closing mongocryptd client in auto encrypter's constructor: #{e.class}: #{e}")
|
124
145
|
# Drop this exception so that the original exception is raised
|
data/lib/mongo/crypt/binding.rb
CHANGED
@@ -83,7 +83,7 @@ module Mongo
|
|
83
83
|
# will cause a `LoadError`.
|
84
84
|
#
|
85
85
|
# @api private
|
86
|
-
MIN_LIBMONGOCRYPT_VERSION = Gem::Version.new("1.5.
|
86
|
+
MIN_LIBMONGOCRYPT_VERSION = Gem::Version.new("1.5.2")
|
87
87
|
|
88
88
|
# @!method self.mongocrypt_version(len)
|
89
89
|
# @api private
|
@@ -107,6 +107,24 @@ module Mongo
|
|
107
107
|
raise LoadError, "libmongocrypt version #{MIN_LIBMONGOCRYPT_VERSION} or above is required, " +
|
108
108
|
"but version #{actual_version} was found."
|
109
109
|
end
|
110
|
+
rescue ArgumentError => e
|
111
|
+
# Some lmc versions cannot be parsed with Gem::Version class,
|
112
|
+
# so we fall back to regex.
|
113
|
+
match = lmc_version.match(/\A(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)?(-[A-Za-z\+\d]+)?\z/)
|
114
|
+
if match.nil?
|
115
|
+
raise ArgumentError.new("Malformed version number string #{lmc_version}")
|
116
|
+
end
|
117
|
+
actual_version = Gem::Version.new(
|
118
|
+
[
|
119
|
+
match[:major],
|
120
|
+
match[:minor],
|
121
|
+
match[:patch]
|
122
|
+
].join('.')
|
123
|
+
)
|
124
|
+
if actual_version < MIN_LIBMONGOCRYPT_VERSION
|
125
|
+
raise LoadError, "libmongocrypt version #{MIN_LIBMONGOCRYPT_VERSION} or above is required, " +
|
126
|
+
"but version #{actual_version} was found."
|
127
|
+
end
|
110
128
|
end
|
111
129
|
|
112
130
|
validate_version(mongocrypt_version(nil))
|
@@ -1385,6 +1403,80 @@ module Mongo
|
|
1385
1403
|
end
|
1386
1404
|
end
|
1387
1405
|
|
1406
|
+
# @!method self.mongocrypt_setopt_append_crypt_shared_lib_search_path(crypt, path)
|
1407
|
+
# @api private
|
1408
|
+
#
|
1409
|
+
# Append an additional search directory to the search path for loading
|
1410
|
+
# the crypt_shared dynamic library.
|
1411
|
+
#
|
1412
|
+
# @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object.
|
1413
|
+
# @param [ String ] path A path to search for the crypt shared library. If the leading element of
|
1414
|
+
# the path is the literal string "$ORIGIN", that substring will be replaced
|
1415
|
+
# with the directory path containing the executable libmongocrypt module. If
|
1416
|
+
# the path string is literal "$SYSTEM", then libmongocrypt will defer to the
|
1417
|
+
# system's library resolution mechanism to find the crypt_shared library.
|
1418
|
+
attach_function(
|
1419
|
+
:mongocrypt_setopt_append_crypt_shared_lib_search_path,
|
1420
|
+
[
|
1421
|
+
:pointer,
|
1422
|
+
:string,
|
1423
|
+
],
|
1424
|
+
:void
|
1425
|
+
)
|
1426
|
+
|
1427
|
+
# Append an additional search directory to the search path for loading
|
1428
|
+
# the crypt_shared dynamic library.
|
1429
|
+
#
|
1430
|
+
# @param [ Mongo::Crypt::Handle ] handle
|
1431
|
+
# @param [ String ] path A search path for the crypt shared library.
|
1432
|
+
def self.setopt_append_crypt_shared_lib_search_path(handle, path)
|
1433
|
+
check_status(handle) do
|
1434
|
+
mongocrypt_setopt_append_crypt_shared_lib_search_path(handle.ref, path)
|
1435
|
+
end
|
1436
|
+
end
|
1437
|
+
|
1438
|
+
# @!method self.mongocrypt_setopt_set_crypt_shared_lib_path_override(crypt, path)
|
1439
|
+
# @api private
|
1440
|
+
#
|
1441
|
+
# Set a single override path for loading the crypt shared library.
|
1442
|
+
#
|
1443
|
+
# @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object.
|
1444
|
+
# @param [ String ] path A path to crypt shared library file. If the leading element of
|
1445
|
+
# the path is the literal string "$ORIGIN", that substring will be replaced
|
1446
|
+
# with the directory path containing the executable libmongocrypt module.
|
1447
|
+
attach_function(
|
1448
|
+
:mongocrypt_setopt_set_crypt_shared_lib_path_override,
|
1449
|
+
[
|
1450
|
+
:pointer,
|
1451
|
+
:string,
|
1452
|
+
],
|
1453
|
+
:void
|
1454
|
+
)
|
1455
|
+
|
1456
|
+
# Set a single override path for loading the crypt shared library.
|
1457
|
+
#
|
1458
|
+
# @param [ Mongo::Crypt::Handle ] handle
|
1459
|
+
# @param [ String ] path A path to crypt shared library file.
|
1460
|
+
def self.setopt_set_crypt_shared_lib_path_override(handle, path)
|
1461
|
+
check_status(handle) do
|
1462
|
+
mongocrypt_setopt_set_crypt_shared_lib_path_override(handle.ref, path)
|
1463
|
+
end
|
1464
|
+
end
|
1465
|
+
|
1466
|
+
# MONGOCRYPT_EXPORT
|
1467
|
+
# uint64_t
|
1468
|
+
# mongocrypt_crypt_shared_lib_version (const mongocrypt_t *crypt);
|
1469
|
+
attach_function(
|
1470
|
+
:mongocrypt_crypt_shared_lib_version,
|
1471
|
+
[ :pointer ],
|
1472
|
+
:uint64
|
1473
|
+
)
|
1474
|
+
|
1475
|
+
def self.crypt_shared_lib_version(handle)
|
1476
|
+
mongocrypt_crypt_shared_lib_version(handle.ref)
|
1477
|
+
end
|
1478
|
+
|
1479
|
+
|
1388
1480
|
# @!method self.mongocrypt_ctx_setopt_query_type(ctx, mongocrypt_query_type)
|
1389
1481
|
# @api private
|
1390
1482
|
#
|
@@ -36,7 +36,11 @@ module Mongo
|
|
36
36
|
# should be hashes of TLS connection options. The options are equivalent
|
37
37
|
# to TLS connection options of Mongo::Client.
|
38
38
|
def initialize(key_vault_client, key_vault_namespace, kms_providers, kms_tls_options)
|
39
|
-
@crypt_handle = Handle.new(
|
39
|
+
@crypt_handle = Handle.new(
|
40
|
+
kms_providers,
|
41
|
+
kms_tls_options,
|
42
|
+
explicit_encryption_only: true
|
43
|
+
)
|
40
44
|
@encryption_io = EncryptionIO.new(
|
41
45
|
key_vault_client: key_vault_client,
|
42
46
|
metadata_client: nil,
|
data/lib/mongo/crypt/handle.rb
CHANGED
@@ -50,6 +50,15 @@ module Mongo
|
|
50
50
|
# and schemaMap, an error will be raised.
|
51
51
|
# @option options [ Boolean | nil ] :bypass_query_analysis When true
|
52
52
|
# disables automatic analysis of outgoing commands.
|
53
|
+
# @option options [ String | nil ] :crypt_shared_lib_path Path that should
|
54
|
+
# be the used to load the crypt shared library. Providing this option
|
55
|
+
# overrides default crypt shared library load paths for libmongocrypt.
|
56
|
+
# @option options [ Boolean | nil ] :crypt_shared_lib_required Whether
|
57
|
+
# crypt_shared library is required. If 'true', an error will be raised
|
58
|
+
# if a crypt_shared library cannot be loaded by libmongocrypt.
|
59
|
+
# @option options [ Boolean | nil ] :explicit_encryption_only Whether this
|
60
|
+
# handle is going to be used only for explicit encryption. If true,
|
61
|
+
# libmongocrypt is instructed not to load crypt shared library.
|
53
62
|
# @option options [ Logger ] :logger A Logger object to which libmongocrypt logs
|
54
63
|
# will be sent
|
55
64
|
def initialize(kms_providers, kms_tls_options, options={})
|
@@ -70,13 +79,29 @@ module Mongo
|
|
70
79
|
@bypass_query_analysis = options[:bypass_query_analysis]
|
71
80
|
set_bypass_query_analysis if @bypass_query_analysis
|
72
81
|
|
82
|
+
@crypt_shared_lib_path = options[:crypt_shared_lib_path]
|
83
|
+
@explicit_encryption_only = options[:explicit_encryption_only]
|
84
|
+
if @crypt_shared_lib_path
|
85
|
+
Binding.setopt_set_crypt_shared_lib_path_override(self, @crypt_shared_lib_path)
|
86
|
+
elsif !@bypass_query_analysis && !@explicit_encryption_only
|
87
|
+
Binding.setopt_append_crypt_shared_lib_search_path(self, "$SYSTEM")
|
88
|
+
end
|
89
|
+
|
73
90
|
@logger = options[:logger]
|
74
91
|
set_logger_callback if @logger
|
75
92
|
|
76
93
|
set_crypto_hooks
|
77
94
|
|
78
95
|
Binding.setopt_kms_providers(self, kms_providers.to_document)
|
96
|
+
|
79
97
|
initialize_mongocrypt
|
98
|
+
|
99
|
+
@crypt_shared_lib_required = !!options[:crypt_shared_lib_required]
|
100
|
+
if @crypt_shared_lib_required && crypt_shared_lib_version == 0
|
101
|
+
raise Mongo::Error::CryptError.new(
|
102
|
+
"Crypt shared library is required, but cannot be loaded according to libmongocrypt"
|
103
|
+
)
|
104
|
+
end
|
80
105
|
end
|
81
106
|
|
82
107
|
# Return the reference to the underlying @mongocrypt object
|
@@ -96,6 +121,14 @@ module Mongo
|
|
96
121
|
@kms_tls_options.fetch(provider, {})
|
97
122
|
end
|
98
123
|
|
124
|
+
def crypt_shared_lib_version
|
125
|
+
Binding.crypt_shared_lib_version(self)
|
126
|
+
end
|
127
|
+
|
128
|
+
def crypt_shared_lib_available?
|
129
|
+
crypt_shared_lib_version != 0
|
130
|
+
end
|
131
|
+
|
99
132
|
private
|
100
133
|
|
101
134
|
# Set the schema map option on the underlying mongocrypt_t object
|
data/lib/mongo/cursor.rb
CHANGED
@@ -251,7 +251,12 @@ module Mongo
|
|
251
251
|
#
|
252
252
|
# @since 2.2.0
|
253
253
|
def batch_size
|
254
|
-
@view.batch_size && @view.batch_size > 0 ? @view.batch_size : limit
|
254
|
+
value = @view.batch_size && @view.batch_size > 0 ? @view.batch_size : limit
|
255
|
+
if value == 0
|
256
|
+
nil
|
257
|
+
else
|
258
|
+
value
|
259
|
+
end
|
255
260
|
end
|
256
261
|
|
257
262
|
# Is the cursor closed?
|
@@ -257,10 +257,14 @@ module Mongo
|
|
257
257
|
super.tap do |message|
|
258
258
|
if session = context.session
|
259
259
|
# Serialize the message to detect client-side problems,
|
260
|
-
# such as invalid BSON keys
|
260
|
+
# such as invalid BSON keys or too large messages.
|
261
|
+
# The message will be serialized again
|
261
262
|
# later prior to being sent to the connection.
|
262
|
-
|
263
|
-
|
263
|
+
buf = BSON::ByteBuffer.new
|
264
|
+
message.serialize(buf)
|
265
|
+
if buf.length > connection.max_message_size
|
266
|
+
raise Error::MaxMessageSize.new(connection.max_message_size)
|
267
|
+
end
|
264
268
|
session.update_state!
|
265
269
|
end
|
266
270
|
end
|
data/lib/mongo/version.rb
CHANGED
data/spec/README.md
CHANGED
@@ -408,7 +408,8 @@ The client-side encryption tests require the mongocryptd binary to be in the
|
|
408
408
|
system path.
|
409
409
|
|
410
410
|
Download enterprise versions of MongoDB here: https://www.mongodb.com/download-center/enterprise
|
411
|
-
|
411
|
+
Download the Automatic Encryption Shared Library https://www.mongodb.com/docs/manual/core/queryable-encryption/reference/shared-library/#std-label-qe-reference-shared-library-download
|
412
|
+
Install and Configure mongocryptd: https://www.mongodb.com/docs/manual/core/queryable-encryption/reference/mongocryptd/
|
412
413
|
|
413
414
|
Install libmongocrypt on your machine:
|
414
415
|
|
@@ -426,6 +427,9 @@ Option 1: Download a pre-built binary
|
|
426
427
|
Option 2: Build from source
|
427
428
|
- To build libmongocrypt from source, follow the instructions in the README on the libmongocrypt GitHub repo: https://github.com/mongodb/libmongocrypt
|
428
429
|
|
430
|
+
Option 3: Use libmongocrypt-helper gem (Linux only)
|
431
|
+
- Run command `FLE=helper bundle install`
|
432
|
+
|
429
433
|
Create AWS KMS keys
|
430
434
|
Many of the Client-Side Encryption tests require that you have an encryption
|
431
435
|
master key hosted on AWS's Key Management Service. Set up a master key by following
|
@@ -18,6 +18,22 @@ describe 'Bulk writes' do
|
|
18
18
|
authorized_collection.bulk_write(operations)
|
19
19
|
end.not_to raise_error
|
20
20
|
end
|
21
|
+
|
22
|
+
context 'in transaction' do
|
23
|
+
require_transaction_support
|
24
|
+
min_server_version "4.4"
|
25
|
+
|
26
|
+
it 'succeeds' do
|
27
|
+
authorized_collection.create
|
28
|
+
expect do
|
29
|
+
authorized_collection.client.start_session do |session|
|
30
|
+
session.with_transaction do
|
31
|
+
authorized_collection.bulk_write(operations, { session: session })
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end.not_to raise_error
|
35
|
+
end
|
36
|
+
end
|
21
37
|
end
|
22
38
|
|
23
39
|
context 'when bulk write needs to be split' do
|
@@ -335,6 +335,8 @@ describe Mongo::Socket::OcspVerifier do
|
|
335
335
|
# have a path in the OCSP URI (which the test also asserts).
|
336
336
|
# Note that these certificates expire in 3 months and need to be replaced
|
337
337
|
# with a more permanent solution.
|
338
|
+
# Use the spec/support/certificates/retrieve-atlas-cert script to retrieve
|
339
|
+
# current certificates from Atlas.
|
338
340
|
let(:cert_path) { File.join(File.dirname(__FILE__), '../support/certificates/atlas-ocsp.crt') }
|
339
341
|
let(:ca_cert_path) { File.join(File.dirname(__FILE__), '../support/certificates/atlas-ocsp-ca.crt') }
|
340
342
|
let(:cert_store) do
|
@@ -16,12 +16,16 @@ describe Mongo::Crypt::AutoEncrypter do
|
|
16
16
|
described_class.new(
|
17
17
|
auto_encryption_options.merge(
|
18
18
|
client: authorized_client.use(:auto_encryption),
|
19
|
-
|
20
|
-
extra_options: extra_options
|
19
|
+
extra_options: auto_encrypter_extra_options
|
21
20
|
)
|
22
21
|
)
|
23
22
|
end
|
24
23
|
|
24
|
+
let(:auto_encrypter_extra_options) do
|
25
|
+
# Spawn mongocryptd on non-default port for sharded cluster tests
|
26
|
+
extra_options
|
27
|
+
end
|
28
|
+
|
25
29
|
let(:client) { authorized_client }
|
26
30
|
|
27
31
|
let(:db_name) { 'auto_encryption' }
|
@@ -155,7 +159,7 @@ describe Mongo::Crypt::AutoEncrypter do
|
|
155
159
|
end
|
156
160
|
end
|
157
161
|
|
158
|
-
|
162
|
+
shared_examples 'with schema map in auto encryption commands' do
|
159
163
|
include_context 'without jsonSchema validator'
|
160
164
|
|
161
165
|
let(:auto_encryption_options) do
|
@@ -193,7 +197,7 @@ describe Mongo::Crypt::AutoEncrypter do
|
|
193
197
|
end
|
194
198
|
end
|
195
199
|
|
196
|
-
|
200
|
+
shared_examples 'with schema map file in auto encryption commands' do
|
197
201
|
include_context 'without jsonSchema validator'
|
198
202
|
|
199
203
|
let(:schema_map_file) do
|
@@ -246,7 +250,7 @@ describe Mongo::Crypt::AutoEncrypter do
|
|
246
250
|
end
|
247
251
|
end
|
248
252
|
|
249
|
-
|
253
|
+
shared_examples 'with schema map collection validator' do
|
250
254
|
include_context 'with jsonSchema validator'
|
251
255
|
|
252
256
|
let(:auto_encryption_options) do
|
@@ -302,7 +306,7 @@ describe Mongo::Crypt::AutoEncrypter do
|
|
302
306
|
end
|
303
307
|
end
|
304
308
|
|
305
|
-
|
309
|
+
shared_examples 'with no validator or client option' do
|
306
310
|
include_context 'without jsonSchema validator'
|
307
311
|
|
308
312
|
let(:auto_encryption_options) do
|
@@ -403,4 +407,35 @@ describe Mongo::Crypt::AutoEncrypter do
|
|
403
407
|
end
|
404
408
|
end
|
405
409
|
end
|
410
|
+
|
411
|
+
context 'when using crypt shared library' do
|
412
|
+
min_server_version '6.0.0'
|
413
|
+
|
414
|
+
let(:auto_encrypter_extra_options) do
|
415
|
+
{
|
416
|
+
crypt_shared_lib_path: SpecConfig.instance.crypt_shared_lib_path
|
417
|
+
}
|
418
|
+
end
|
419
|
+
|
420
|
+
let(:auto_encryption_options) do
|
421
|
+
{
|
422
|
+
kms_providers: kms_providers,
|
423
|
+
kms_tls_options: kms_tls_options,
|
424
|
+
key_vault_namespace: key_vault_namespace,
|
425
|
+
schema_map: { "#{db_name}.#{collection_name}": schema_map },
|
426
|
+
}
|
427
|
+
end
|
428
|
+
|
429
|
+
it_behaves_like 'with schema map in auto encryption commands'
|
430
|
+
it_behaves_like 'with schema map file in auto encryption commands'
|
431
|
+
it_behaves_like 'with schema map collection validator'
|
432
|
+
it_behaves_like 'with no validator or client option'
|
433
|
+
end
|
434
|
+
|
435
|
+
context 'when using mongocryptd' do
|
436
|
+
it_behaves_like 'with schema map in auto encryption commands'
|
437
|
+
it_behaves_like 'with schema map file in auto encryption commands'
|
438
|
+
it_behaves_like 'with schema map collection validator'
|
439
|
+
it_behaves_like 'with no validator or client option'
|
440
|
+
end
|
406
441
|
end
|
@@ -41,5 +41,13 @@ describe 'Mongo::Crypt::Binding' do
|
|
41
41
|
end.not_to raise_error(LoadError, /libmongocrypt version .* or above is required, but version .* was found./)
|
42
42
|
end
|
43
43
|
end
|
44
|
+
|
45
|
+
context 'when in a non-parsable format' do
|
46
|
+
it 'does not raise ArgumentError' do
|
47
|
+
expect do
|
48
|
+
Mongo::Crypt::Binding.validate_version("1.5.3-dev+20220730git8f8675fa11")
|
49
|
+
end.not_to raise_error(ArgumentError, /Malformed version number string/)
|
50
|
+
end
|
51
|
+
end
|
44
52
|
end
|
45
53
|
end
|
@@ -18,6 +18,10 @@ describe Mongo::Crypt::Handle do
|
|
18
18
|
kms_tls_options,
|
19
19
|
schema_map: schema_map,
|
20
20
|
schema_map_path: schema_map_path,
|
21
|
+
bypass_query_analysis: bypass_query_analysis,
|
22
|
+
crypt_shared_lib_path: crypt_shared_lib_path,
|
23
|
+
crypt_shared_lib_required: crypt_shared_lib_required,
|
24
|
+
explicit_encryption_only: explicit_encryption_only,
|
21
25
|
)
|
22
26
|
end
|
23
27
|
|
@@ -29,6 +33,22 @@ describe Mongo::Crypt::Handle do
|
|
29
33
|
nil
|
30
34
|
end
|
31
35
|
|
36
|
+
let(:bypass_query_analysis) do
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:crypt_shared_lib_path) do
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
|
44
|
+
let(:crypt_shared_lib_required) do
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
48
|
+
let(:explicit_encryption_only) do
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
32
52
|
shared_examples 'a functioning Mongo::Crypt::Handle' do
|
33
53
|
context 'with valid schema map' do
|
34
54
|
it 'does not raise an exception' do
|
@@ -73,6 +93,88 @@ describe Mongo::Crypt::Handle do
|
|
73
93
|
expect { handle }.not_to raise_error
|
74
94
|
end
|
75
95
|
end
|
96
|
+
|
97
|
+
context 'with crypt_shared_lib_path' do
|
98
|
+
min_server_version '6.0.0'
|
99
|
+
|
100
|
+
context 'with correct path' do
|
101
|
+
let(:crypt_shared_lib_path) do
|
102
|
+
SpecConfig.instance.crypt_shared_lib_path
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'loads the crypt shared lib' do
|
106
|
+
expect(handle.crypt_shared_lib_version).not_to eq(0)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'with incorrect path' do
|
111
|
+
let(:crypt_shared_lib_path) do
|
112
|
+
'/some/bad/path/mongo_crypt_v1.so'
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'raises an exception' do
|
116
|
+
expect { handle }.to raise_error(Mongo::Error::CryptError)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'with crypt_shared_lib_required' do
|
122
|
+
min_server_version '6.0.0'
|
123
|
+
|
124
|
+
context 'set to true' do
|
125
|
+
let(:crypt_shared_lib_required) do
|
126
|
+
true
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'when shared lib is available' do
|
130
|
+
let(:crypt_shared_lib_path) do
|
131
|
+
SpecConfig.instance.crypt_shared_lib_path
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'does not raise an exception' do
|
135
|
+
expect { handle }.not_to raise_error
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'when shared lib is not available' do
|
140
|
+
let(:crypt_shared_lib_path) do
|
141
|
+
'/some/bad/path/mongo_crypt_v1.so'
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'raises an exception' do
|
145
|
+
expect { handle }.to raise_error(Mongo::Error::CryptError)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'if bypass_query_analysis is true' do
|
152
|
+
min_server_version '6.0.0'
|
153
|
+
|
154
|
+
let(:bypass_query_analysis) do
|
155
|
+
true
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'does not load the crypt shared lib' do
|
159
|
+
expect_any_instance_of(Binding).not_to receive(:setopt_append_crypt_shared_lib_search_path)
|
160
|
+
|
161
|
+
expect(handle.crypt_shared_lib_version).to eq(0)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'if explicit_encryption_only is true' do
|
166
|
+
min_server_version '6.0.0'
|
167
|
+
|
168
|
+
let(:explicit_encryption_only) do
|
169
|
+
true
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'does not load the crypt shared lib' do
|
173
|
+
expect_any_instance_of(Binding).not_to receive(:setopt_append_crypt_shared_lib_search_path)
|
174
|
+
|
175
|
+
expect(handle.crypt_shared_lib_version).to eq(0)
|
176
|
+
end
|
177
|
+
end
|
76
178
|
end
|
77
179
|
|
78
180
|
context 'local' do
|
data/spec/mongo/cursor_spec.rb
CHANGED
@@ -734,4 +734,54 @@ describe Mongo::Cursor do
|
|
734
734
|
end
|
735
735
|
end
|
736
736
|
end
|
737
|
+
|
738
|
+
describe '#batch_size' do
|
739
|
+
let(:subscriber) { Mrss::EventSubscriber.new }
|
740
|
+
|
741
|
+
let(:subscribed_client) do
|
742
|
+
authorized_client.tap do |client|
|
743
|
+
client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
|
744
|
+
end
|
745
|
+
end
|
746
|
+
|
747
|
+
let(:collection) do
|
748
|
+
subscribed_client[TEST_COLL]
|
749
|
+
end
|
750
|
+
|
751
|
+
let(:view) do
|
752
|
+
collection.find({}, limit: limit)
|
753
|
+
end
|
754
|
+
|
755
|
+
before do
|
756
|
+
collection.drop
|
757
|
+
collection.insert_many([].fill({ "bar": "baz" }, 0, 102))
|
758
|
+
end
|
759
|
+
|
760
|
+
context 'when limit is 0 and batch_size is not set' do
|
761
|
+
let(:limit) do
|
762
|
+
0
|
763
|
+
end
|
764
|
+
|
765
|
+
it 'does not set batch_size' do
|
766
|
+
view.to_a
|
767
|
+
get_more_commands = subscriber.started_events.select { |e| e.command_name == 'getMore' }
|
768
|
+
expect(get_more_commands.length).to eq(1)
|
769
|
+
expect(get_more_commands.first.command.keys).not_to include('batchSize')
|
770
|
+
end
|
771
|
+
end
|
772
|
+
|
773
|
+
context 'when limit is not zero and batch_size is not set' do
|
774
|
+
let(:limit) do
|
775
|
+
1000
|
776
|
+
end
|
777
|
+
|
778
|
+
it 'sets batch_size' do
|
779
|
+
view.to_a
|
780
|
+
get_more_commands = subscriber.started_events.select { |e| e.command_name == 'getMore' }
|
781
|
+
|
782
|
+
expect(get_more_commands.length).to eq(1)
|
783
|
+
expect(get_more_commands.first.command.keys).to include('batchSize')
|
784
|
+
end
|
785
|
+
end
|
786
|
+
end
|
737
787
|
end
|
@@ -84,22 +84,32 @@ module Mrss
|
|
84
84
|
|
85
85
|
# Locates command stated events for the specified command name,
|
86
86
|
# asserts that there is exactly one such event, and returns it.
|
87
|
-
def single_command_started_event(command_name, include_auth: false)
|
87
|
+
def single_command_started_event(command_name, include_auth: false, database_name: nil)
|
88
88
|
events = if include_auth
|
89
89
|
started_events
|
90
90
|
else
|
91
91
|
non_auth_command_started_events
|
92
92
|
end
|
93
|
-
events
|
94
|
-
|
93
|
+
get_one_event(events, command_name, 'started', database_name: database_name)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Locates command succeeded events for the specified command name,
|
97
|
+
# asserts that there is exactly one such event, and returns it.
|
98
|
+
def single_command_succeeded_event(command_name, database_name: nil)
|
99
|
+
get_one_event(succeeded_events, command_name, 'succeeded', database_name: database_name)
|
100
|
+
end
|
101
|
+
|
102
|
+
def get_one_event(events, command_name, kind, database_name: nil)
|
103
|
+
events = events.select do |event|
|
104
|
+
event.command_name == command_name and
|
105
|
+
database_name.nil? || database_name == event.database_name
|
95
106
|
end
|
96
107
|
if events.length != 1
|
97
|
-
raise "Expected a single #{command_name} event but we have #{events.length}"
|
108
|
+
raise "Expected a single '#{command_name}' #{kind} event#{database_name ? " for '#{database_name}'" : ''} but we have #{events.length}"
|
98
109
|
end
|
99
110
|
events.first
|
100
111
|
end
|
101
112
|
|
102
|
-
|
103
113
|
# Get the first succeeded event published for the name, and then delete it.
|
104
114
|
#
|
105
115
|
# @param [ String ] name The event name.
|
@@ -745,6 +745,9 @@ tests:
|
|
745
745
|
databaseName: *database0
|
746
746
|
|
747
747
|
- description: change stream resumes after StaleShardVersion
|
748
|
+
runOnRequirements:
|
749
|
+
# StaleShardVersion is obsolete as of 6.1 and is no longer marked as resumable.
|
750
|
+
- maxServerVersion: "6.0.99"
|
748
751
|
operations:
|
749
752
|
- name: failPoint
|
750
753
|
object: testRunner
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# commands sort the resulting documents in ascending order by the single-element
|
3
3
|
# keyAltNames array to ensure alphabetic order by original KMS provider as
|
4
4
|
# defined in initialData.
|
5
|
-
description: rewrapManyDataKey
|
5
|
+
description: rewrapManyDataKey
|
6
6
|
|
7
7
|
schemaVersion: "1.8"
|
8
8
|
|
@@ -50,7 +50,7 @@ initialData:
|
|
50
50
|
region: us-east-1
|
51
51
|
- _id: &azure_key_id { $binary: { base64: YXp1cmVhenVyZWF6dXJlYQ==, subType: "04" } }
|
52
52
|
keyAltNames: ["azure_key"]
|
53
|
-
keyMaterial: { $binary: { base64:
|
53
|
+
keyMaterial: { $binary: { base64: pr01l7qDygUkFE/0peFwpnNlv3iIy8zrQK38Q9i12UCN2jwZHDmfyx8wokiIKMb9kAleeY+vnt3Cf1MKu9kcDmI+KxbNDd+V3ytAAGzOVLDJr77CiWjF9f8ntkXRHrAY9WwnVDANYkDwXlyU0Y2GQFTiW65jiQhUtYLYH63Tk48SsJuQvnWw1Q+PzY8ga+QeVec8wbcThwtm+r2IHsCFnc72Gv73qq7weISw+O4mN08z3wOp5FOS2ZM3MK7tBGmPdBcktW7F8ODGsOQ1FU53OrWUnyX2aTi2ftFFFMWVHqQo7EYuBZHru8RRODNKMyQk0BFfKovAeTAVRv9WH9QU7g==, subType: "00" } }
|
54
54
|
creationDate: { $date: { $numberLong: "1641024000000" } }
|
55
55
|
updateDate: { $date: { $numberLong: "1641024000000" } }
|
56
56
|
status: 1
|
@@ -72,7 +72,7 @@ initialData:
|
|
72
72
|
keyName: key-name-csfle
|
73
73
|
- _id: &kmip_key_id { $binary: { base64: a21pcGttaXBrbWlwa21pcA==, subType: "04" } }
|
74
74
|
keyAltNames: ["kmip_key"]
|
75
|
-
keyMaterial: { $binary: { base64:
|
75
|
+
keyMaterial: { $binary: { base64: CklVctHzke4mcytd0TxGqvepkdkQN8NUF4+jV7aZQITAKdz6WjdDpq3lMt9nSzWGG2vAEfvRb3mFEVjV57qqGqxjq2751gmiMRHXz0btStbIK3mQ5xbY9kdye4tsixlCryEwQONr96gwlwKKI9Nubl9/8+uRF6tgYjje7Q7OjauEf1SrJwKcoQ3WwnjZmEqAug0kImCpJ/irhdqPzivRiA==, subType: "00" } }
|
76
76
|
creationDate: { $date: { $numberLong: "1641024000000" } }
|
77
77
|
updateDate: { $date: { $numberLong: "1641024000000" } }
|
78
78
|
status: 1
|
@@ -86,9 +86,9 @@ tests:
|
|
86
86
|
documents:
|
87
87
|
- _id: 1
|
88
88
|
- _id: 2
|
89
|
-
# Configure the next streaming hello check to fail with a command
|
90
|
-
#
|
91
|
-
#
|
89
|
+
# Configure the next streaming hello check to fail with a command error.
|
90
|
+
# Must use "times: 2" here. For a longer on explanation on why, check out
|
91
|
+
# https://jira.mongodb.org/browse/RUBY-3050.
|
92
92
|
- name: configureFailPoint
|
93
93
|
object: testRunner
|
94
94
|
arguments:
|
@@ -121,17 +121,9 @@ tests:
|
|
121
121
|
documents:
|
122
122
|
- _id: 3
|
123
123
|
- _id: 4
|
124
|
-
#
|
125
|
-
|
126
|
-
|
127
|
-
arguments:
|
128
|
-
event: ServerMarkedUnknownEvent
|
129
|
-
count: 1
|
130
|
-
- name: assertEventCount
|
131
|
-
object: testRunner
|
132
|
-
arguments:
|
133
|
-
event: PoolClearedEvent
|
134
|
-
count: 1
|
124
|
+
# We cannot assert the server was marked Unknown and pool was cleared an
|
125
|
+
# exact number of times because the RTT hello may have triggered this
|
126
|
+
# failpoint one or many times as well.
|
135
127
|
|
136
128
|
expectations:
|
137
129
|
- command_started_event:
|
@@ -44,16 +44,6 @@ tests:
|
|
44
44
|
# We cannot assert the server was marked Unknown and pool was cleared an
|
45
45
|
# exact number of times because the RTT hello may or may not have
|
46
46
|
# triggered this failpoint as well.
|
47
|
-
# - name: assertEventCount
|
48
|
-
# object: testRunner
|
49
|
-
# arguments:
|
50
|
-
# event: ServerMarkedUnknownEvent
|
51
|
-
# count: 1
|
52
|
-
# - name: assertEventCount
|
53
|
-
# object: testRunner
|
54
|
-
# arguments:
|
55
|
-
# event: PoolClearedEvent
|
56
|
-
# count: 1
|
57
47
|
|
58
48
|
expectations:
|
59
49
|
- command_started_event:
|
@@ -86,8 +76,8 @@ tests:
|
|
86
76
|
- _id: 1
|
87
77
|
- _id: 2
|
88
78
|
# Configure the next streaming hello check to fail with a non-timeout
|
89
|
-
# network error.
|
90
|
-
#
|
79
|
+
# network error. Must use "times: 2" here. For a longer on explanation
|
80
|
+
# on why, check out https://jira.mongodb.org/browse/RUBY-3050.
|
91
81
|
- name: configureFailPoint
|
92
82
|
object: testRunner
|
93
83
|
arguments:
|
@@ -118,8 +108,8 @@ tests:
|
|
118
108
|
- _id: 3
|
119
109
|
- _id: 4
|
120
110
|
# We cannot assert the server was marked Unknown and pool was cleared an
|
121
|
-
# exact number of times because the RTT hello may
|
122
|
-
#
|
111
|
+
# exact number of times because the RTT hello may have triggered this
|
112
|
+
# failpoint one or many times as well.
|
123
113
|
# - name: assertEventCount
|
124
114
|
# object: testRunner
|
125
115
|
# arguments:
|
@@ -86,14 +86,16 @@ tests:
|
|
86
86
|
documents:
|
87
87
|
- _id: 1
|
88
88
|
- _id: 2
|
89
|
-
# Configure the next streaming hello check to fail with a timeout
|
90
|
-
# Use times:
|
89
|
+
# Configure the next streaming hello check to fail with a timeout.
|
90
|
+
# Use "times: 4" to increase the probability that the Monitor check times
|
91
|
+
# out since the RTT hello may trigger this failpoint one or many times as
|
92
|
+
# well.
|
91
93
|
- name: configureFailPoint
|
92
94
|
object: testRunner
|
93
95
|
arguments:
|
94
96
|
failPoint:
|
95
97
|
configureFailPoint: failCommand
|
96
|
-
mode: { times:
|
98
|
+
mode: { times: 4 }
|
97
99
|
data:
|
98
100
|
failCommands: ["hello", "isMaster"]
|
99
101
|
appName: timeoutMonitorCheckTest
|
@@ -121,17 +123,9 @@ tests:
|
|
121
123
|
documents:
|
122
124
|
- _id: 3
|
123
125
|
- _id: 4
|
124
|
-
#
|
125
|
-
|
126
|
-
|
127
|
-
arguments:
|
128
|
-
event: ServerMarkedUnknownEvent
|
129
|
-
count: 1
|
130
|
-
- name: assertEventCount
|
131
|
-
object: testRunner
|
132
|
-
arguments:
|
133
|
-
event: PoolClearedEvent
|
134
|
-
count: 1
|
126
|
+
# We cannot assert the server was marked Unknown and pool was cleared an
|
127
|
+
# exact number of times because the RTT hello may have triggered this
|
128
|
+
# failpoint one or many times as well.
|
135
129
|
|
136
130
|
expectations:
|
137
131
|
- command_started_event:
|
@@ -0,0 +1,64 @@
|
|
1
|
+
description: "do not retry read in a transaction"
|
2
|
+
|
3
|
+
schemaVersion: "1.4"
|
4
|
+
|
5
|
+
runOnRequirements:
|
6
|
+
- minServerVersion: "4.0.0"
|
7
|
+
topologies: [ replicaset ]
|
8
|
+
- minServerVersion: "4.2.0"
|
9
|
+
topologies: [ sharded, load-balanced ]
|
10
|
+
|
11
|
+
createEntities:
|
12
|
+
- client:
|
13
|
+
id: &client0 client0
|
14
|
+
useMultipleMongoses: false
|
15
|
+
observeEvents: [commandStartedEvent]
|
16
|
+
uriOptions: { retryReads: true }
|
17
|
+
- database:
|
18
|
+
id: &database0 database0
|
19
|
+
client: *client0
|
20
|
+
databaseName: &databaseName retryable-read-in-transaction-test
|
21
|
+
- collection:
|
22
|
+
id: &collection0 collection0
|
23
|
+
database: *database0
|
24
|
+
collectionName: &collectionName coll
|
25
|
+
- session:
|
26
|
+
id: &session0 session0
|
27
|
+
client: *client0
|
28
|
+
|
29
|
+
tests:
|
30
|
+
- description: "find does not retry in a transaction"
|
31
|
+
operations:
|
32
|
+
|
33
|
+
- name: startTransaction
|
34
|
+
object: *session0
|
35
|
+
|
36
|
+
- name: failPoint # fail the following find command
|
37
|
+
object: testRunner
|
38
|
+
arguments:
|
39
|
+
client: *client0
|
40
|
+
failPoint:
|
41
|
+
configureFailPoint: failCommand
|
42
|
+
mode: { times: 1 }
|
43
|
+
data:
|
44
|
+
failCommands: [find]
|
45
|
+
closeConnection: true
|
46
|
+
|
47
|
+
- name: find
|
48
|
+
object: *collection0
|
49
|
+
arguments:
|
50
|
+
filter: {}
|
51
|
+
session: *session0
|
52
|
+
expectError:
|
53
|
+
isError: true
|
54
|
+
errorLabelsContain: ["TransientTransactionError"]
|
55
|
+
expectEvents:
|
56
|
+
- client: *client0
|
57
|
+
events:
|
58
|
+
- commandStartedEvent:
|
59
|
+
command:
|
60
|
+
find: *collectionName
|
61
|
+
filter: {}
|
62
|
+
startTransaction: true
|
63
|
+
commandName: find
|
64
|
+
databaseName: *databaseName
|
@@ -0,0 +1,118 @@
|
|
1
|
+
description: "retryable abortTransaction on handshake errors"
|
2
|
+
|
3
|
+
schemaVersion: "1.4"
|
4
|
+
|
5
|
+
runOnRequirements:
|
6
|
+
- minServerVersion: "4.2"
|
7
|
+
topologies: [replicaset, sharded, load-balanced]
|
8
|
+
serverless: "forbid"
|
9
|
+
auth: true
|
10
|
+
|
11
|
+
createEntities:
|
12
|
+
- client:
|
13
|
+
id: &client0 client0
|
14
|
+
useMultipleMongoses: false
|
15
|
+
observeEvents: [commandStartedEvent, connectionCheckOutStartedEvent]
|
16
|
+
- database:
|
17
|
+
id: &database0 database0
|
18
|
+
client: *client0
|
19
|
+
databaseName: &databaseName retryable-handshake-tests
|
20
|
+
- collection:
|
21
|
+
id: &collection0 collection0
|
22
|
+
database: *database0
|
23
|
+
collectionName: &collectionName coll
|
24
|
+
- session:
|
25
|
+
# This session will be used to execute the transaction
|
26
|
+
id: &session0 session0
|
27
|
+
client: *client0
|
28
|
+
- session:
|
29
|
+
# This session will be used to create the failPoint, and empty the pool
|
30
|
+
id: &session1 session1
|
31
|
+
client: *client0
|
32
|
+
|
33
|
+
initialData:
|
34
|
+
- collectionName: *collectionName
|
35
|
+
databaseName: *databaseName
|
36
|
+
documents:
|
37
|
+
- { _id: 1, x: 11 }
|
38
|
+
|
39
|
+
tests:
|
40
|
+
- description: "AbortTransaction succeeds after handshake network error"
|
41
|
+
skipReason: "DRIVERS-2032: Pinned servers need to be checked if they are still selectable"
|
42
|
+
operations:
|
43
|
+
|
44
|
+
- name: startTransaction
|
45
|
+
object: *session0
|
46
|
+
|
47
|
+
- name: insertOne
|
48
|
+
object: *collection0
|
49
|
+
arguments:
|
50
|
+
session: *session0
|
51
|
+
document: { _id: 2, x: 22 }
|
52
|
+
|
53
|
+
# The following failPoint and ping utilize session1 so that
|
54
|
+
# the transaction won't be failed by the intentional erroring of ping
|
55
|
+
# and it will have an empty pool when it goes to run abortTransaction
|
56
|
+
- name: failPoint # fail the next connection establishment
|
57
|
+
object: testRunner
|
58
|
+
arguments:
|
59
|
+
client: *client0
|
60
|
+
session: *session1
|
61
|
+
failPoint:
|
62
|
+
configureFailPoint: failCommand
|
63
|
+
mode: { times: 2 }
|
64
|
+
data:
|
65
|
+
# use saslContinue here to avoid SDAM errors
|
66
|
+
# this failPoint itself will create a usable connection in the connection pool
|
67
|
+
# so we run a ping (with closeConnection: true) in order to discard the connection
|
68
|
+
# before testing that abortTransaction will fail a handshake but will get retried
|
69
|
+
failCommands: [saslContinue, ping]
|
70
|
+
closeConnection: true
|
71
|
+
|
72
|
+
- name: runCommand
|
73
|
+
object: *database0
|
74
|
+
arguments:
|
75
|
+
commandName: ping
|
76
|
+
command: { ping: 1 }
|
77
|
+
session: *session1
|
78
|
+
expectError:
|
79
|
+
isError: true
|
80
|
+
|
81
|
+
- name: abortTransaction
|
82
|
+
object: *session0
|
83
|
+
|
84
|
+
expectEvents:
|
85
|
+
- client: *client0
|
86
|
+
eventType: cmap
|
87
|
+
events:
|
88
|
+
- { connectionCheckOutStartedEvent: {} } # startTransaction
|
89
|
+
- { connectionCheckOutStartedEvent: {} } # insertOne
|
90
|
+
- { connectionCheckOutStartedEvent: {} } # failPoint
|
91
|
+
- { connectionCheckOutStartedEvent: {} } # abortTransaction
|
92
|
+
- { connectionCheckOutStartedEvent: {} } # abortTransaction retry
|
93
|
+
- client: *client0
|
94
|
+
events:
|
95
|
+
- commandStartedEvent:
|
96
|
+
command:
|
97
|
+
insert: *collectionName
|
98
|
+
documents: [{ _id: 2, x: 22 }]
|
99
|
+
startTransaction: true
|
100
|
+
commandName: insert
|
101
|
+
databaseName: *databaseName
|
102
|
+
- commandStartedEvent:
|
103
|
+
command:
|
104
|
+
ping: 1
|
105
|
+
databaseName: *databaseName
|
106
|
+
- commandStartedEvent:
|
107
|
+
command:
|
108
|
+
abortTransaction: 1
|
109
|
+
lsid:
|
110
|
+
$$sessionLsid: *session0
|
111
|
+
commandName: abortTransaction
|
112
|
+
databaseName: admin
|
113
|
+
|
114
|
+
outcome:
|
115
|
+
- collectionName: *collectionName
|
116
|
+
databaseName: *databaseName
|
117
|
+
documents:
|
118
|
+
- { _id: 1, x: 11 }
|
@@ -0,0 +1,118 @@
|
|
1
|
+
description: "retryable commitTransaction on handshake errors"
|
2
|
+
|
3
|
+
schemaVersion: "1.4"
|
4
|
+
|
5
|
+
runOnRequirements:
|
6
|
+
- minServerVersion: "4.2"
|
7
|
+
topologies: [replicaset, sharded, load-balanced]
|
8
|
+
serverless: "forbid"
|
9
|
+
auth: true
|
10
|
+
|
11
|
+
createEntities:
|
12
|
+
- client:
|
13
|
+
id: &client0 client0
|
14
|
+
useMultipleMongoses: false
|
15
|
+
observeEvents: [commandStartedEvent, connectionCheckOutStartedEvent]
|
16
|
+
uriOptions: { retryWrites: false } # commitTransaction is retryable regardless of this option being set
|
17
|
+
- database:
|
18
|
+
id: &database0 database0
|
19
|
+
client: *client0
|
20
|
+
databaseName: &databaseName retryable-handshake-tests
|
21
|
+
- collection:
|
22
|
+
id: &collection0 collection0
|
23
|
+
database: *database0
|
24
|
+
collectionName: &collectionName coll
|
25
|
+
- session:
|
26
|
+
id: &session0 session0
|
27
|
+
client: *client0
|
28
|
+
- session:
|
29
|
+
id: &session1 session1
|
30
|
+
client: *client0
|
31
|
+
|
32
|
+
initialData:
|
33
|
+
- collectionName: *collectionName
|
34
|
+
databaseName: *databaseName
|
35
|
+
documents:
|
36
|
+
- { _id: 1, x: 11 }
|
37
|
+
|
38
|
+
tests:
|
39
|
+
- description: "CommitTransaction succeeds after handshake network error"
|
40
|
+
skipReason: "DRIVERS-2032: Pinned servers need to be checked if they are still selectable"
|
41
|
+
operations:
|
42
|
+
|
43
|
+
- name: startTransaction
|
44
|
+
object: *session0
|
45
|
+
|
46
|
+
- name: insertOne
|
47
|
+
object: *collection0
|
48
|
+
arguments:
|
49
|
+
session: *session0
|
50
|
+
document: { _id: 2, x: 22 }
|
51
|
+
|
52
|
+
# The following failPoint and ping utilize session1 so that
|
53
|
+
# the transaction won't be failed by the intentional erroring of ping
|
54
|
+
# and it will have an empty pool when it goes to run commitTransaction
|
55
|
+
- name: failPoint # fail the next connection establishment
|
56
|
+
object: testRunner
|
57
|
+
arguments:
|
58
|
+
client: *client0
|
59
|
+
session: *session1
|
60
|
+
failPoint:
|
61
|
+
configureFailPoint: failCommand
|
62
|
+
mode: { times: 2 }
|
63
|
+
data:
|
64
|
+
# use saslContinue here to avoid SDAM errors
|
65
|
+
# this failPoint itself will create a usable connection in the connection pool
|
66
|
+
# so we run a ping (that also fails) in order to discard the connection
|
67
|
+
# before testing that commitTransaction gets retried
|
68
|
+
failCommands: [saslContinue, ping]
|
69
|
+
closeConnection: true
|
70
|
+
|
71
|
+
- name: runCommand
|
72
|
+
object: *database0
|
73
|
+
arguments:
|
74
|
+
commandName: ping
|
75
|
+
command: { ping: 1 }
|
76
|
+
session: *session1
|
77
|
+
expectError:
|
78
|
+
isError: true
|
79
|
+
|
80
|
+
- name: commitTransaction
|
81
|
+
object: *session0
|
82
|
+
|
83
|
+
expectEvents:
|
84
|
+
- client: *client0
|
85
|
+
eventType: cmap
|
86
|
+
events:
|
87
|
+
- { connectionCheckOutStartedEvent: {} } # startTransaction
|
88
|
+
- { connectionCheckOutStartedEvent: {} } # insertOne
|
89
|
+
- { connectionCheckOutStartedEvent: {} } # failPoint
|
90
|
+
- { connectionCheckOutStartedEvent: {} } # commitTransaction
|
91
|
+
- { connectionCheckOutStartedEvent: {} } # commitTransaction retry
|
92
|
+
- client: *client0
|
93
|
+
events:
|
94
|
+
- commandStartedEvent:
|
95
|
+
command:
|
96
|
+
insert: *collectionName
|
97
|
+
documents: [{ _id: 2, x: 22 }]
|
98
|
+
startTransaction: true
|
99
|
+
commandName: insert
|
100
|
+
databaseName: *databaseName
|
101
|
+
- commandStartedEvent:
|
102
|
+
command:
|
103
|
+
ping: 1
|
104
|
+
databaseName: *databaseName
|
105
|
+
- commandStartedEvent:
|
106
|
+
command:
|
107
|
+
commitTransaction: 1
|
108
|
+
lsid:
|
109
|
+
$$sessionLsid: *session0
|
110
|
+
commandName: commitTransaction
|
111
|
+
databaseName: admin
|
112
|
+
|
113
|
+
outcome:
|
114
|
+
- collectionName: *collectionName
|
115
|
+
databaseName: *databaseName
|
116
|
+
documents:
|
117
|
+
- { _id: 1, x: 11 }
|
118
|
+
- { _id: 2, x: 22 } # The write was still applied
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
host = 'freecluster-shard-00-00-oztdp.mongodb-dev.net'
|
6
|
+
|
7
|
+
output = `openssl s_client -showcerts -servername #{host} -connect #{host}:27017 </dev/null`
|
8
|
+
|
9
|
+
if output.empty?
|
10
|
+
raise 'Something bad happened'
|
11
|
+
end
|
12
|
+
|
13
|
+
certs = output.scan(/(-----BEGIN CERTIFICATE(.|\n)+?END CERTIFICATE-----)/)
|
14
|
+
cert, ca_cert = certs.map { |g| g.first }
|
15
|
+
|
16
|
+
Dir.mktmpdir do |path|
|
17
|
+
cert_path = File.join(path, 'cert.pem')
|
18
|
+
File.open(cert_path, 'w') do |f|
|
19
|
+
f << cert
|
20
|
+
end
|
21
|
+
output = `openssl x509 -noout -text -in #{cert_path}`
|
22
|
+
File.open('atlas-ocsp.crt', 'w') do |f|
|
23
|
+
f << output
|
24
|
+
f << "\n"
|
25
|
+
f << cert
|
26
|
+
end
|
27
|
+
|
28
|
+
cert_path = File.join(path, 'cert.pem')
|
29
|
+
File.open(cert_path, 'w') do |f|
|
30
|
+
f << ca_cert
|
31
|
+
end
|
32
|
+
output = `openssl x509 -noout -text -in #{cert_path}`
|
33
|
+
File.open('atlas-ocsp-ca.crt', 'w') do |f|
|
34
|
+
f << output
|
35
|
+
f << "\n"
|
36
|
+
f << ca_cert
|
37
|
+
end
|
38
|
+
end
|
data/spec/support/spec_config.rb
CHANGED
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.18.
|
4
|
+
version: 2.18.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tyler Brock
|
@@ -32,7 +32,7 @@ cert_chain:
|
|
32
32
|
+WyKQ+QTIdtDiyf2LQmxWnxt/W1CmScjdLS7/yXGkkB/D9Uy+sJD747O/B9P238Q
|
33
33
|
XnerrtyOu04RsWDvaZkCwSDVzoqfICh4CP1mlde73Ts=
|
34
34
|
-----END CERTIFICATE-----
|
35
|
-
date: 2022-
|
35
|
+
date: 2022-08-02 00:00:00.000000000 Z
|
36
36
|
dependencies:
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: bson
|
@@ -1667,7 +1667,10 @@ files:
|
|
1667
1667
|
- spec/spec_tests/data/transactions_api/commit-writeconcernerror.yml
|
1668
1668
|
- spec/spec_tests/data/transactions_api/commit.yml
|
1669
1669
|
- spec/spec_tests/data/transactions_api/transaction-options.yml
|
1670
|
+
- spec/spec_tests/data/transactions_unified/do-not-retry-read-in-transaction.yml
|
1670
1671
|
- spec/spec_tests/data/transactions_unified/mongos-unpin.yml
|
1672
|
+
- spec/spec_tests/data/transactions_unified/retryable-abort-handshake.yml
|
1673
|
+
- spec/spec_tests/data/transactions_unified/retryable-commit-handshake.yml
|
1671
1674
|
- spec/spec_tests/data/unified/invalid/expectedEventsForClient-ignoreExtraEvents-type.yml
|
1672
1675
|
- spec/spec_tests/data/unified/valid-fail/operation-failure.yml
|
1673
1676
|
- spec/spec_tests/data/unified/valid-fail/operation-unsupported.yml
|
@@ -1754,6 +1757,7 @@ files:
|
|
1754
1757
|
- spec/support/certificates/crl_client_revoked.pem
|
1755
1758
|
- spec/support/certificates/multi-ca.crt
|
1756
1759
|
- spec/support/certificates/python-ca.crt
|
1760
|
+
- spec/support/certificates/retrieve-atlas-cert
|
1757
1761
|
- spec/support/certificates/server-int.crt
|
1758
1762
|
- spec/support/certificates/server-second-level-bundle.pem
|
1759
1763
|
- spec/support/certificates/server-second-level.crt
|
@@ -2816,6 +2820,9 @@ test_files:
|
|
2816
2820
|
- spec/spec_tests/data/unified/valid-fail/operation-unsupported.yml
|
2817
2821
|
- spec/spec_tests/data/unified/valid-fail/operation-failure.yml
|
2818
2822
|
- spec/spec_tests/data/unified/invalid/expectedEventsForClient-ignoreExtraEvents-type.yml
|
2823
|
+
- spec/spec_tests/data/transactions_unified/retryable-commit-handshake.yml
|
2824
|
+
- spec/spec_tests/data/transactions_unified/retryable-abort-handshake.yml
|
2825
|
+
- spec/spec_tests/data/transactions_unified/do-not-retry-read-in-transaction.yml
|
2819
2826
|
- spec/spec_tests/data/transactions_unified/mongos-unpin.yml
|
2820
2827
|
- spec/spec_tests/data/collection_management/createCollection-pre_and_post_images.yml
|
2821
2828
|
- spec/spec_tests/data/collection_management/clustered-indexes.yml
|
@@ -3084,6 +3091,7 @@ test_files:
|
|
3084
3091
|
- spec/support/certificates/multi-ca.crt
|
3085
3092
|
- spec/support/certificates/crl.pem
|
3086
3093
|
- spec/support/certificates/client-encrypted.key
|
3094
|
+
- spec/support/certificates/retrieve-atlas-cert
|
3087
3095
|
- spec/support/certificates/client-int.crt
|
3088
3096
|
- spec/support/certificates/client-x509.pem
|
3089
3097
|
- spec/support/certificates/server-second-level-bundle.pem
|
metadata.gz.sig
CHANGED
Binary file
|