mongo 2.18.0 → 2.18.1

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