mongo 2.18.0 → 2.18.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|