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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/mongo/bulk_write.rb +1 -1
  4. data/lib/mongo/crypt/auto_encrypter.rb +30 -9
  5. data/lib/mongo/crypt/binding.rb +93 -1
  6. data/lib/mongo/crypt/explicit_encrypter.rb +5 -1
  7. data/lib/mongo/crypt/handle.rb +33 -0
  8. data/lib/mongo/cursor.rb +6 -1
  9. data/lib/mongo/operation/shared/sessions_supported.rb +7 -3
  10. data/lib/mongo/version.rb +1 -1
  11. data/spec/README.md +5 -1
  12. data/spec/integration/bulk_write_spec.rb +16 -0
  13. data/spec/integration/ocsp_verifier_spec.rb +2 -0
  14. data/spec/mongo/crypt/auto_encrypter_spec.rb +41 -6
  15. data/spec/mongo/crypt/binding/version_spec.rb +8 -0
  16. data/spec/mongo/crypt/handle_spec.rb +102 -0
  17. data/spec/mongo/cursor_spec.rb +50 -0
  18. data/spec/shared/lib/mrss/event_subscriber.rb +15 -5
  19. data/spec/spec_tests/data/change_streams_unified/change-streams-resume-errorLabels.yml +3 -0
  20. data/spec/spec_tests/data/client_side_encryption/unified/rewrapManyDataKey.yml +3 -3
  21. data/spec/spec_tests/data/sdam_integration/hello-command-error.yml +6 -14
  22. data/spec/spec_tests/data/sdam_integration/hello-network-error.yml +4 -14
  23. data/spec/spec_tests/data/sdam_integration/hello-timeout.yml +8 -14
  24. data/spec/spec_tests/data/transactions_unified/do-not-retry-read-in-transaction.yml +64 -0
  25. data/spec/spec_tests/data/transactions_unified/retryable-abort-handshake.yml +118 -0
  26. data/spec/spec_tests/data/transactions_unified/retryable-commit-handshake.yml +118 -0
  27. data/spec/support/certificates/retrieve-atlas-cert +38 -0
  28. data/spec/support/spec_config.rb +4 -0
  29. data.tar.gz.sig +0 -0
  30. metadata +10 -2
  31. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1a032a8e48c1bc78d55d09cf8b607ec98402fb5f5e4a9a3fd11c566ee74b84f
4
- data.tar.gz: 4ed2f33af97f4e5ab3da1b6acad5c90f3d7bfd0baee576d8e1df1b246b60637e
3
+ metadata.gz: 664d381d4746fb4ff6282069f909a91a58f497220bae57656c265f52c5d99040
4
+ data.tar.gz: 85fa7fbf071c3e8fc4c1beb2215b3297a3af560130204dbd0f916adb272987f7
5
5
  SHA512:
6
- metadata.gz: 148a1228124e7895b96ef7931d7ba480748464f730e42c384da5ee64806bc173691db11d278cf7f189fefb4b06c1fe6999ac7cad1934f9dfdbd84a4cb89427a8
7
- data.tar.gz: e9d7cc2c3dd95b8e2cdbc0017d12fcf7d10df4416999356709029c466f74f8ac07cbe5a868a3bd0392ea6a9d380f8cdba73ad0970fe249048832ad0a11983f47
6
+ metadata.gz: 2dcf66e773da4e2bdaf0a22d15a06eadbc5ab2bccffc29f012e2ae863e8148b597550ee680dc2556b40408f4c759b78b159b678cf494cf619c0975044d72d662
7
+ data.tar.gz: c120607792132931a54511db0a4ef62653393138e9da3fcf0ca0f0a85fde3aefe6b04782fd09125b0fe3085e50c66b1cd2f6e0c4743ae40e7094dc8e7892587a
checksums.yaml.gz.sig CHANGED
Binary file
@@ -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
- # Set server selection timeout to 1 to prevent the client waiting for a
102
- # long timeout before spawning mongocryptd
103
- @mongocryptd_client = Client.new(
104
- @options[:extra_options][:mongocryptd_uri],
105
- monitoring_io: @options[:client].options[:monitoring_io],
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.close
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
@@ -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.0.alpha")
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(kms_providers, kms_tls_options)
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,
@@ -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. The message will be serialized again
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
- message.serialize(BSON::ByteBuffer.new)
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
@@ -20,5 +20,5 @@ module Mongo
20
20
  # The current version of the driver.
21
21
  #
22
22
  # @since 2.0.0
23
- VERSION = '2.18.0'.freeze
23
+ VERSION = '2.18.1'.freeze
24
24
  end
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
- Read more about installing mongocryptd here: https://mongodb.com/docs/manual/reference/security-client-side-encryption-appendix/#mongocryptd
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
- # Spawn mongocryptd on non-default port for sharded cluster tests
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
- context 'with schema map in auto encryption commands' do
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
- context 'with schema map file in auto encryption commands' do
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
- context 'with schema map collection validator' do
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
- context 'with no validator or client option' do
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
@@ -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.select! do |event|
94
- event.command[command_name]
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-kms_providers
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: AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEGkNTybTc7Eyif0f+qqE0lAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDB2j78AeuIQxcRh8cQIBEIB7vj9buHEaT7XHFIsKBJiyzZRmNnjvqMK5LSdzonKdx97jlqauvPvTDXSsdQDcspUs5oLrGmAXpbFResscxmbwZoKgUtWiuIOpeAcYuszCiMKt15s1WIMLDXUhYtfCmhRhekvgHnRAaK4HJMlGE+lKJXYI84E0b86Cd/g+, subType: "00" } }
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: VoI9J8HusQ3u2gT9i8Awgg/6W4/igvLwRzn3SRDGx0Dl/1ayDMubphOw0ONPVKfuvS6HL3e4gAoCJ/uEz2KLFTVsEqYCpMhfAhgXxm8Ena8vDcOkCzFX+euvN/N2ES3wpzAD18b3qIH0MbBwKJP82d5GQ4pVfGnPW8Ujp9aO1qC/s0EqNqYyzJ1SyzhV9lAjHHGIENYJx+bBrekg2EeZBA==, subType: "00" } }
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
- # error.
91
- # Use times: 2 so that the RTT hello is blocked as well.
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
- # Assert the server was marked Unknown and pool was cleared exactly once.
125
- - name: assertEventCount
126
- object: testRunner
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. Use times: 2 to ensure that the the Monitor check fails
90
- # since the RTT hello may trigger this failpoint as well.
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 or may not have
122
- # triggered this failpoint as well.
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: 2 so that the RTT hello is blocked as well.
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: 2 }
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
- # Assert the server was marked Unknown and pool was cleared exactly once.
125
- - name: assertEventCount
126
- object: testRunner
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
@@ -471,6 +471,10 @@ EOT
471
471
  end
472
472
  end
473
473
 
474
+ def crypt_shared_lib_path
475
+ ENV['MONGO_RUBY_DRIVER_CRYPT_SHARED_LIB_PATH']
476
+ end
477
+
474
478
  def auth?
475
479
  x509_auth? || user
476
480
  end
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.0
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-07-19 00:00:00.000000000 Z
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