mongo 2.18.0.beta1 → 2.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/mongo/bulk_write.rb +8 -2
  4. data/lib/mongo/client.rb +19 -5
  5. data/lib/mongo/client_encryption.rb +86 -4
  6. data/lib/mongo/cluster.rb +6 -4
  7. data/lib/mongo/collection/view/aggregation.rb +3 -0
  8. data/lib/mongo/collection/view/change_stream.rb +9 -0
  9. data/lib/mongo/collection/view/iterable.rb +1 -0
  10. data/lib/mongo/collection/view/readable.rb +11 -3
  11. data/lib/mongo/collection.rb +9 -1
  12. data/lib/mongo/config.rb +11 -0
  13. data/lib/mongo/crypt/auto_encrypter.rb +49 -21
  14. data/lib/mongo/crypt/binding.rb +73 -48
  15. data/lib/mongo/crypt/data_key_context.rb +6 -1
  16. data/lib/mongo/crypt/encryption_io.rb +66 -0
  17. data/lib/mongo/crypt/explicit_encrypter.rb +116 -5
  18. data/lib/mongo/crypt/explicit_encryption_context.rb +3 -8
  19. data/lib/mongo/crypt/handle.rb +26 -8
  20. data/lib/mongo/crypt/kms/aws.rb +11 -3
  21. data/lib/mongo/crypt/kms/azure.rb +14 -6
  22. data/lib/mongo/crypt/kms/gcp.rb +12 -5
  23. data/lib/mongo/crypt/kms/kmip.rb +15 -9
  24. data/lib/mongo/crypt/kms/local.rb +9 -1
  25. data/lib/mongo/crypt/kms/master_key_document.rb +1 -1
  26. data/lib/mongo/crypt/rewrap_many_data_key_context.rb +46 -0
  27. data/lib/mongo/crypt/rewrap_many_data_key_result.rb +37 -0
  28. data/lib/mongo/crypt/status.rb +8 -2
  29. data/lib/mongo/crypt.rb +2 -0
  30. data/lib/mongo/database.rb +10 -27
  31. data/lib/mongo/error/missing_file_chunk.rb +8 -2
  32. data/lib/mongo/grid/stream/read.rb +6 -0
  33. data/lib/mongo/index/view.rb +1 -0
  34. data/lib/mongo/operation/create/op_msg.rb +1 -13
  35. data/lib/mongo/operation/distinct/op_msg.rb +4 -1
  36. data/lib/mongo/protocol/msg.rb +0 -16
  37. data/lib/mongo/server/connection_pool.rb +5 -4
  38. data/lib/mongo/server/monitor/connection.rb +10 -4
  39. data/lib/mongo/server/monitor.rb +4 -0
  40. data/lib/mongo/server/push_monitor.rb +4 -0
  41. data/lib/mongo/version.rb +1 -1
  42. data/lib/mongo.rb +2 -0
  43. data/spec/README.md +14 -0
  44. data/spec/integration/change_stream_spec.rb +1 -1
  45. data/spec/integration/client_construction_spec.rb +73 -7
  46. data/spec/integration/client_side_encryption/auto_encryption_command_monitoring_spec.rb +165 -164
  47. data/spec/integration/client_side_encryption/decryption_events_prose_spec.rb +158 -0
  48. data/spec/integration/client_side_encryption/explicit_queryable_encryption_spec.rb +5 -5
  49. data/spec/integration/client_side_encryption/kms_tls_options_spec.rb +50 -8
  50. data/spec/integration/client_side_encryption/unique_index_on_key_alt_names_prose_spec.rb +85 -0
  51. data/spec/integration/ocsp_verifier_spec.rb +1 -1
  52. data/spec/integration/reconnect_spec.rb +2 -0
  53. data/spec/integration/sdam_events_spec.rb +40 -0
  54. data/spec/integration/srv_monitoring_spec.rb +1 -0
  55. data/spec/integration/srv_spec.rb +1 -0
  56. data/spec/lite_spec_helper.rb +5 -4
  57. data/spec/mongo/bulk_write_spec.rb +13 -0
  58. data/spec/mongo/client_construction_spec.rb +45 -2
  59. data/spec/mongo/client_encryption_spec.rb +0 -12
  60. data/spec/mongo/client_spec.rb +1 -1
  61. data/spec/mongo/collection/view/aggregation_spec.rb +119 -0
  62. data/spec/mongo/collection/view/readable_spec.rb +630 -5
  63. data/spec/mongo/collection_spec.rb +32 -0
  64. data/spec/mongo/crypt/auto_encrypter_spec.rb +110 -0
  65. data/spec/mongo/crypt/binding/context_spec.rb +3 -35
  66. data/spec/mongo/crypt/data_key_context_spec.rb +1 -1
  67. data/spec/mongo/crypt/explicit_encryption_context_spec.rb +8 -3
  68. data/spec/mongo/crypt/handle_spec.rb +39 -3
  69. data/spec/mongo/crypt/kms/credentials_spec.rb +0 -47
  70. data/spec/mongo/index/view_spec.rb +56 -0
  71. data/spec/mongo/operation/create/op_msg_spec.rb +0 -42
  72. data/spec/mongo/server/connection_pool_spec.rb +26 -4
  73. data/spec/mongo/socket/ssl_spec.rb +3 -3
  74. data/spec/runners/crud/requirement.rb +6 -1
  75. data/spec/runners/crud/test.rb +1 -1
  76. data/spec/runners/transactions/spec.rb +2 -2
  77. data/spec/runners/transactions/test.rb +4 -20
  78. data/spec/runners/transactions.rb +2 -2
  79. data/spec/runners/unified/assertions.rb +32 -2
  80. data/spec/runners/unified/change_stream_operations.rb +3 -0
  81. data/spec/runners/unified/client_side_encryption_operations.rb +83 -0
  82. data/spec/runners/unified/crud_operations.rb +17 -2
  83. data/spec/runners/unified/ddl_operations.rb +27 -2
  84. data/spec/runners/unified/grid_fs_operations.rb +21 -0
  85. data/spec/runners/unified/test.rb +59 -1
  86. data/spec/shared/lib/mrss/docker_runner.rb +2 -0
  87. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  88. data/spec/shared/lib/mrss/lite_constraints.rb +10 -2
  89. data/spec/shared/shlib/set_env.sh +3 -0
  90. data/spec/solo/clean_exit_spec.rb +5 -0
  91. data/spec/spec_tests/client_side_encryption_spec.rb +1 -1
  92. data/spec/spec_tests/client_side_encryption_unified_spec.rb +16 -0
  93. data/spec/spec_tests/data/change_streams_unified/change-streams-showExpandedEvents.yml +298 -0
  94. data/spec/spec_tests/data/client_side_encryption/create-and-createIndexes.yml +58 -0
  95. data/spec/spec_tests/data/client_side_encryption/fle2-Delete.yml +1 -1
  96. data/spec/spec_tests/data/client_side_encryption/fle2-EncryptedFields-vs-jsonSchema.yml +1 -1
  97. data/spec/spec_tests/data/client_side_encryption/fle2-FindOneAndUpdate.yml +2 -2
  98. data/spec/spec_tests/data/client_side_encryption/fle2-InsertFind-Indexed.yml +1 -1
  99. data/spec/spec_tests/data/client_side_encryption/fle2-Update.yml +2 -2
  100. data/spec/spec_tests/data/client_side_encryption/unified/addKeyAltName.yml +194 -0
  101. data/spec/spec_tests/data/client_side_encryption/unified/createDataKey-kms_providers-invalid.yml +67 -0
  102. data/spec/spec_tests/data/client_side_encryption/unified/createDataKey.yml +309 -0
  103. data/spec/spec_tests/data/client_side_encryption/unified/deleteKey.yml +159 -0
  104. data/spec/spec_tests/data/client_side_encryption/unified/getKey.yml +105 -0
  105. data/spec/spec_tests/data/client_side_encryption/unified/getKeyByAltName.yml +104 -0
  106. data/spec/spec_tests/data/client_side_encryption/unified/getKeys.yml +122 -0
  107. data/spec/spec_tests/data/client_side_encryption/unified/removeKeyAltName.yml +157 -0
  108. data/spec/spec_tests/data/client_side_encryption/unified/rewrapManyDataKey-decrypt_failure.yml +69 -0
  109. data/spec/spec_tests/data/client_side_encryption/unified/rewrapManyDataKey-encrypt_failure.yml +122 -0
  110. data/spec/spec_tests/data/client_side_encryption/unified/rewrapManyDataKey.yml +432 -0
  111. data/spec/spec_tests/data/client_side_encryption/validatorAndPartialFieldExpression.yml +166 -0
  112. data/spec/spec_tests/data/command_monitoring_unified/bulkWrite.yml +68 -0
  113. data/spec/spec_tests/data/command_monitoring_unified/command.yml +50 -0
  114. data/spec/spec_tests/data/command_monitoring_unified/deleteMany.yml +79 -0
  115. data/spec/spec_tests/data/command_monitoring_unified/deleteOne.yml +79 -0
  116. data/spec/spec_tests/data/command_monitoring_unified/find.yml +254 -0
  117. data/spec/spec_tests/data/command_monitoring_unified/insertMany.yml +79 -0
  118. data/spec/spec_tests/data/command_monitoring_unified/insertOne.yml +77 -0
  119. data/spec/spec_tests/data/command_monitoring_unified/unacknowledgedBulkWrite.yml +55 -0
  120. data/spec/spec_tests/data/command_monitoring_unified/updateMany.yml +87 -0
  121. data/spec/spec_tests/data/command_monitoring_unified/updateOne.yml +118 -0
  122. data/spec/spec_tests/data/crud_unified/distinct-comment.yml +98 -0
  123. data/spec/spec_tests/data/gridfs_unified/delete.yml +198 -0
  124. data/spec/spec_tests/data/gridfs_unified/download.yml +241 -0
  125. data/spec/spec_tests/data/gridfs_unified/downloadByName.yml +159 -0
  126. data/spec/spec_tests/data/gridfs_unified/upload-disableMD5.yml +92 -0
  127. data/spec/spec_tests/data/gridfs_unified/upload.yml +288 -0
  128. data/spec/spec_tests/gridfs_unified_spec.rb +13 -0
  129. data/spec/stress/connection_pool_timing_spec.rb +2 -2
  130. data/spec/support/background_thread_registry.rb +3 -13
  131. data/spec/support/certificates/atlas-ocsp-ca.crt +40 -47
  132. data/spec/support/certificates/atlas-ocsp.crt +101 -106
  133. data/spec/support/crypt.rb +57 -13
  134. data/spec/support/macros.rb +10 -0
  135. data/spec/support/spec_config.rb +4 -0
  136. data.tar.gz.sig +0 -0
  137. metadata +1271 -1219
  138. metadata.gz.sig +0 -0
  139. data/spec/spec_tests/command_monitoring_spec.rb +0 -71
  140. data/spec/spec_tests/data/command_monitoring/bulkWrite.yml +0 -49
  141. data/spec/spec_tests/data/command_monitoring/command.yml +0 -61
  142. data/spec/spec_tests/data/command_monitoring/deleteMany.yml +0 -55
  143. data/spec/spec_tests/data/command_monitoring/deleteOne.yml +0 -55
  144. data/spec/spec_tests/data/command_monitoring/find.yml +0 -266
  145. data/spec/spec_tests/data/command_monitoring/insertMany.yml +0 -75
  146. data/spec/spec_tests/data/command_monitoring/insertOne.yml +0 -51
  147. data/spec/spec_tests/data/command_monitoring/unacknowledgedBulkWrite.yml +0 -34
  148. data/spec/spec_tests/data/command_monitoring/updateMany.yml +0 -65
  149. data/spec/spec_tests/data/command_monitoring/updateOne.yml +0 -90
@@ -24,11 +24,15 @@ module Mongo
24
24
  #
25
25
  # @api private
26
26
  class Credentials
27
+ extend Forwardable
27
28
  include KMS::Validations
28
29
 
29
30
  # @return [ String ] KMIP KMS endpoint with optional port.
30
31
  attr_reader :endpoint
31
32
 
33
+ # @api private
34
+ def_delegator :@opts, :empty?
35
+
32
36
  FORMAT_HINT = "KMIP KMS provider options must be in the format: " +
33
37
  "{ endpoint: 'ENDPOINT' }"
34
38
 
@@ -41,13 +45,17 @@ module Mongo
41
45
  # @raise [ ArgumentError ] If required options are missing or incorrectly
42
46
  # formatted.
43
47
  def initialize(opts)
44
- @endpoint = validate_param(:endpoint, opts, FORMAT_HINT)
48
+ @opts = opts
49
+ unless empty?
50
+ @endpoint = validate_param(:endpoint, opts, FORMAT_HINT)
51
+ end
45
52
  end
46
53
 
47
54
  # Convert credentials object to a BSON document in libmongocrypt format.
48
55
  #
49
56
  # @return [ BSON::Document ] Local KMS credentials in libmongocrypt format.
50
57
  def to_document
58
+ return BSON::Document.new({}) if empty?
51
59
  BSON::Document.new({
52
60
  endpoint: endpoint,
53
61
  })
@@ -74,17 +82,17 @@ module Mongo
74
82
  #
75
83
  # @param [ Hash ] opts A hash that contains master key options for
76
84
  # KMIP KMS provider
77
- # @option opts [ String ] :key_id KMIP Unique Identifier to
85
+ # @option opts [ String | nil ] :key_id KMIP Unique Identifier to
78
86
  # a 96 byte KMIP Secret Data managed object, optional. If key_id
79
87
  # is omitted, the driver creates a random 96 byte identifier.
80
- # @option opts [ String ] :endpoint KMIP endpoint, optional.
88
+ # @option opts [ String | nil ] :endpoint KMIP endpoint, optional.
81
89
  #
82
90
  # @raise [ ArgumentError ] If required options are missing or incorrectly
83
91
  # formatted.
84
- def initialize(opts)
92
+ def initialize(opts = {})
85
93
  @key_id = validate_param(
86
94
  :key_id, opts, FORMAT_HINT, required: false
87
- ) || SecureRandom.alphanumeric(96)
95
+ )
88
96
  @endpoint = validate_param(
89
97
  :endpoint, opts, FORMAT_HINT, required: false
90
98
  )
@@ -96,11 +104,9 @@ module Mongo
96
104
  def to_document
97
105
  BSON::Document.new({
98
106
  provider: 'kmip',
99
- keyId: key_id
100
107
  }).tap do |bson|
101
- unless endpoint.nil?
102
- bson.update({ endpoint: endpoint })
103
- end
108
+ bson.update({ endpoint: endpoint }) unless endpoint.nil?
109
+ bson.update({ keyId: key_id }) unless key_id.nil?
104
110
  end
105
111
  end
106
112
  end
@@ -23,11 +23,15 @@ module Mongo
23
23
  #
24
24
  # @api private
25
25
  class Credentials
26
+ extend Forwardable
26
27
  include KMS::Validations
27
28
 
28
29
  # @return [ String ] Master key.
29
30
  attr_reader :key
30
31
 
32
+ # @api private
33
+ def_delegator :@opts, :empty?
34
+
31
35
  FORMAT_HINT = "Local KMS provider options must be in the format: " +
32
36
  "{ key: 'MASTER-KEY' }"
33
37
 
@@ -40,11 +44,15 @@ module Mongo
40
44
  # @raise [ ArgumentError ] If required options are missing or incorrectly
41
45
  # formatted.
42
46
  def initialize(opts)
43
- @key = validate_param(:key, opts, FORMAT_HINT)
47
+ @opts = opts
48
+ unless empty?
49
+ @key = validate_param(:key, opts, FORMAT_HINT)
50
+ end
44
51
  end
45
52
 
46
53
  # @return [ BSON::Document ] Local KMS credentials in libmongocrypt format.
47
54
  def to_document
55
+ return BSON::Document.new({}) if empty?
48
56
  BSON::Document.new({
49
57
  key: BSON::Binary.new(@key, :generic),
50
58
  })
@@ -41,7 +41,7 @@ module Mongo
41
41
  if options.nil?
42
42
  raise ArgumentError.new('Key document options must not be nil')
43
43
  end
44
- master_key = options[:master_key]
44
+ master_key = options.fetch(:master_key, {})
45
45
  @key_document = case kms_provider.to_s
46
46
  when 'aws' then KMS::AWS::MasterKeyDocument.new(master_key)
47
47
  when 'azure' then KMS::Azure::MasterKeyDocument.new(master_key)
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ # Copyright (C) 2019-2020 MongoDB Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ module Mongo
19
+ module Crypt
20
+
21
+ # A Context object initialized specifically for the purpose of rewrapping
22
+ # data keys (decrypting and re-rencryting using a new KEK).
23
+ #
24
+ # @api private
25
+ class RewrapManyDataKeyContext < Context
26
+
27
+ # Create a new RewrapManyDataKeyContext object
28
+ #
29
+ # @param [ Mongo::Crypt::Handle ] mongocrypt a Handle that
30
+ # wraps a mongocrypt_t object used to create a new mongocrypt_ctx_t
31
+ # @param [ Mongo::Crypt::EncryptionIO ] io An object that performs all
32
+ # driver I/O on behalf of libmongocrypt
33
+ # @param [ Hash ] filter Filter used to find keys to be updated.
34
+ # alternate names for the new data key.
35
+ # @param [ Mongo::Crypt::KMS::MasterKeyDocument | nil ] master_key_document The optional master
36
+ # key document that contains master encryption key parameters.
37
+ def initialize(mongocrypt, io, filter, master_key_document)
38
+ super(mongocrypt, io)
39
+ if master_key_document
40
+ Binding.ctx_setopt_key_encryption_key(self, master_key_document.to_document)
41
+ end
42
+ Binding.ctx_rewrap_many_datakey_init(self, filter)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ # Copyright (C) 2019-2022 MongoDB Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ module Mongo
19
+ module Crypt
20
+ # Represent result of the rewrap many data ke operation.
21
+ #
22
+ # @api semiprivate
23
+ class RewrapManyDataKeyResult
24
+
25
+ # @returns [ BulkWrite::Result ] the result of the bulk write operation
26
+ # used to update the key vault collection with rewrapped data keys.
27
+ attr_reader :bulk_write_result
28
+
29
+ # @param [ BulkWrite::Result | nil ] bulk_write_result The result of the
30
+ # bulk write operation used to update the key vault collection
31
+ # with rewrapped data keys.
32
+ def initialize(bulk_write_result)
33
+ @bulk_write_result = bulk_write_result
34
+ end
35
+ end
36
+ end
37
+ end
@@ -118,10 +118,16 @@ module Mongo
118
118
  # information stored in this status
119
119
  #
120
120
  # Does nothing if self.ok? is true
121
- def raise_crypt_error
121
+ #
122
+ # @param kms [ true | false ] Whether the operation was against the KMS.
123
+ #
124
+ # @note If kms parameter is false, the error may still have come from a
125
+ # KMS. The kms parameter simply forces all errors to be treated as
126
+ # KMS errors.
127
+ def raise_crypt_error(kms: false)
122
128
  return if ok?
123
129
 
124
- if label == :error_kms
130
+ if kms || label == :error_kms
125
131
  error = Error::KmsError.new(message, code: code)
126
132
  else
127
133
  error = Error::CryptError.new(message, code: code)
data/lib/mongo/crypt.rb CHANGED
@@ -29,6 +29,8 @@ module Mongo
29
29
  autoload(:AutoEncryptionContext, 'mongo/crypt/auto_encryption_context')
30
30
  autoload(:ExplicitDecryptionContext, 'mongo/crypt/explicit_decryption_context')
31
31
  autoload(:AutoDecryptionContext, 'mongo/crypt/auto_decryption_context')
32
+ autoload(:RewrapManyDataKeyContext, 'mongo/crypt/rewrap_many_data_key_context')
33
+ autoload(:RewrapManyDataKeyResult, 'mongo/crypt/rewrap_many_data_key_result')
32
34
  autoload(:EncryptionIO, 'mongo/crypt/encryption_io')
33
35
  autoload(:ExplicitEncrypter, 'mongo/crypt/explicit_encrypter')
34
36
  autoload(:AutoEncrypter, 'mongo/crypt/auto_encrypter')
@@ -225,33 +225,8 @@ module Mongo
225
225
 
226
226
  client.send(:with_session, opts) do |session|
227
227
  server = selector.select_server(cluster, nil, session)
228
- # This code MUST be removed as soon as server starts accepting
229
- # contention as int32.
230
- _operation = operation.dup
231
- if _operation['encryptedFields'] && _operation['encryptedFields'].key?('fields')
232
- _operation['encryptedFields']['fields'] = _operation['encryptedFields']['fields'].map do |field|
233
- if field['queries'] && field['queries'].key?('contention')
234
- field['queries']['contention'] = BSON::Int64.new(field['queries']['contention'])
235
- end
236
- field
237
- end
238
- end
239
- if schema = _operation.dig('encryptionInformation', 'schema')
240
- _operation['encryptionInformation']['schema'] = schema.map do |coll, params|
241
- if params['fields']
242
- params['fields'] = params['fields'].map do |field|
243
- if contention = field.dig('queries', 'contention')
244
- field['queries']['contention'] = BSON::Int64.new(contention)
245
- end
246
- field
247
- end
248
- end
249
- [coll, params]
250
- end.to_h
251
- end
252
- # End of code to be removed
253
228
  op = Operation::Command.new(
254
- :selector => _operation,
229
+ :selector => operation,
255
230
  :db_name => name,
256
231
  :read => selector,
257
232
  :session => session
@@ -481,6 +456,11 @@ module Mongo
481
456
  # Only recognized by server versions 4.0+.
482
457
  # @option options [ Object ] :comment A user-provided
483
458
  # comment to attach to this command.
459
+ # @option options [ Boolean ] :show_expanded_events Enables the server to
460
+ # send the 'expanded' list of change stream events. The list of additional
461
+ # events included with this flag set are: createIndexes, dropIndexes,
462
+ # modify, create, shardCollection, reshardCollection,
463
+ # refineCollectionShardKey.
484
464
  #
485
465
  # @note A change stream only allows 'majority' read concern.
486
466
  # @note This helper method is preferable to running a raw aggregation with a $changeStream
@@ -490,8 +470,11 @@ module Mongo
490
470
  #
491
471
  # @since 2.6.0
492
472
  def watch(pipeline = [], options = {})
473
+ view_options = options.dup
474
+ view_options[:await_data] = true if options[:max_await_time_ms]
475
+
493
476
  Mongo::Collection::View::ChangeStream.new(
494
- Mongo::Collection::View.new(collection("#{COMMAND}.aggregate")),
477
+ Mongo::Collection::View.new(collection("#{COMMAND}.aggregate"), {}, view_options),
495
478
  pipeline,
496
479
  Mongo::Collection::View::ChangeStream::DATABASE,
497
480
  options)
@@ -30,11 +30,17 @@ module Mongo
30
30
  # Mongo::Error::MissingFileChunk.new(expected_n, chunk)
31
31
  #
32
32
  # @param [ Integer ] expected_n The expected index value.
33
- # @param [ Grid::File::Chunk ] chunk The chunk read from GridFS.
33
+ # @param [ Grid::File::Chunk | Integer ] chunk The chunk read from GridFS.
34
34
  #
35
35
  # @since 2.1.0
36
+ #
37
+ # @api private
36
38
  def initialize(expected_n, chunk)
37
- super("Unexpected chunk in sequence. Expected next chunk to have index #{expected_n} but it has index #{chunk.n}")
39
+ if chunk.is_a?(Integer)
40
+ super("Missing chunk(s). Expected #{expected_n} chunks but got #{chunk}.")
41
+ else
42
+ super("Unexpected chunk in sequence. Expected next chunk to have index #{expected_n} but it has index #{chunk.n}")
43
+ end
38
44
  end
39
45
  end
40
46
  end
@@ -79,13 +79,19 @@ module Mongo
79
79
  ensure_readable!
80
80
  info = file_info
81
81
  num_chunks = (info.length + info.chunk_size - 1) / info.chunk_size
82
+ num_read = 0
82
83
  if block_given?
83
84
  view.each_with_index.reduce(0) do |length_read, (doc, index)|
84
85
  chunk = Grid::File::Chunk.new(doc)
85
86
  validate!(index, num_chunks, chunk, length_read)
86
87
  data = chunk.data.data
87
88
  yield data
89
+ num_read += 1
88
90
  length_read += data.size
91
+ end.tap do
92
+ if num_read < num_chunks
93
+ raise Error::MissingFileChunk.new(num_chunks, num_read)
94
+ end
89
95
  end
90
96
  else
91
97
  view.to_enum
@@ -71,6 +71,7 @@ module Mongo
71
71
  :weights => :weights,
72
72
  :collation => :collation,
73
73
  :comment => :comment,
74
+ :wildcard_projection => :wildcardProjection,
74
75
  }.freeze
75
76
 
76
77
  # Drop an index by its name.
@@ -34,19 +34,7 @@ module Mongo
34
34
  spec[:selector].merge(
35
35
  collation: spec[:collation],
36
36
  encryptedFields: spec[:encrypted_fields],
37
- ).compact.tap do |sel|
38
- # This code MUST be removed as soon as server starts accepting
39
- # contention as int32.
40
- if sel[:encryptedFields] && sel[:encryptedFields].key?('fields')
41
- sel[:encryptedFields]['fields'] = sel[:encryptedFields]['fields'].map do |field|
42
- if field['queries'] && field['queries'].key?('contention')
43
- field['queries']['contention'] = BSON::Int64.new(field['queries']['contention'])
44
- end
45
- field
46
- end
47
- end
48
- # End of code to be removed
49
- end
37
+ ).compact
50
38
  end
51
39
  end
52
40
  end
@@ -32,7 +32,10 @@ module Mongo
32
32
 
33
33
  def selector(connection)
34
34
  # Collation is always supported on 3.6+ servers that would use OP_MSG.
35
- spec[:selector].merge(collation: spec[:collation]).compact
35
+ spec[:selector].merge(
36
+ collation: spec[:collation],
37
+ comment: spec[:comment],
38
+ ).compact
36
39
  end
37
40
  end
38
41
  end
@@ -229,22 +229,6 @@ module Mongo
229
229
  if cmd.key?('$db') && !enc_cmd.key?('$db')
230
230
  enc_cmd['$db'] = cmd['$db']
231
231
  end
232
- # This code MUST be removed as soon as server starts accepting
233
- # contention as int32.
234
- if schema = enc_cmd.dig('encryptionInformation', 'schema')
235
- enc_cmd['encryptionInformation']['schema'] = schema.map do |coll, params|
236
- if params['fields']
237
- params['fields'] = params['fields'].map do |field|
238
- if contention = field.dig('queries', 'contention')
239
- field['queries']['contention'] = BSON::Int64.new(contention)
240
- end
241
- field
242
- end
243
- end
244
- [coll, params]
245
- end.to_h
246
- end
247
- # End of code to be removed
248
232
 
249
233
  Msg.new(@flags, @options, enc_cmd)
250
234
  else
@@ -29,7 +29,7 @@ module Mongo
29
29
  # The default max size for the connection pool.
30
30
  #
31
31
  # @since 2.9.0
32
- DEFAULT_MAX_SIZE = 5.freeze
32
+ DEFAULT_MAX_SIZE = 20.freeze
33
33
 
34
34
  # The default min size for the connection pool.
35
35
  #
@@ -59,7 +59,8 @@ module Mongo
59
59
  # @param [ Server ] server The server which this connection pool is for.
60
60
  # @param [ Hash ] options The connection pool options.
61
61
  #
62
- # @option options [ Integer ] :max_size The maximum pool size.
62
+ # @option options [ Integer ] :max_size The maximum pool size. Setting
63
+ # this option to zero creates an unlimited connection pool.
63
64
  # @option options [ Integer ] :max_pool_size Deprecated.
64
65
  # The maximum pool size. If max_size is also given, max_size and
65
66
  # max_pool_size must be identical.
@@ -98,7 +99,7 @@ module Mongo
98
99
  options[:max_size] ||= options[:max_pool_size]
99
100
  options.delete(:max_pool_size)
100
101
  if options[:min_size] && options[:max_size] &&
101
- options[:min_size] > options[:max_size]
102
+ (options[:max_size] != 0 && options[:min_size] > options[:max_size])
102
103
  then
103
104
  raise ArgumentError, "Cannot have min size #{options[:min_size]} exceed max size #{options[:max_size]}"
104
105
  end
@@ -377,7 +378,7 @@ module Mongo
377
378
  #
378
379
  # Ruby does not allow a thread to lock a mutex which it already
379
380
  # holds.
380
- if unsynchronized_size < max_size
381
+ if max_size == 0 || unsynchronized_size < max_size
381
382
  connection = create_connection
382
383
  @pending_connections << connection
383
384
  throw(:done)
@@ -228,15 +228,21 @@ module Mongo
228
228
  # @api private
229
229
  def check_document
230
230
  server_api = @app_metadata.server_api || options[:server_api]
231
- if hello_ok? || server_api
232
- doc = HELLO_DOC
231
+ doc = if hello_ok? || server_api
232
+ _doc = HELLO_DOC
233
233
  if server_api
234
- doc = doc.merge(Utils.transform_server_api(server_api))
234
+ _doc = _doc.merge(Utils.transform_server_api(server_api))
235
235
  end
236
- doc
236
+ _doc
237
237
  else
238
238
  LEGACY_HELLO_DOC
239
239
  end
240
+ # compressors must be set to maintain correct compression status
241
+ # in the server description. See RUBY-2427
242
+ if compressors = options[:compressors]
243
+ doc = doc.merge(compression: compressors)
244
+ end
245
+ doc
240
246
  end
241
247
 
242
248
  private
@@ -268,6 +268,10 @@ module Mongo
268
268
  end
269
269
  end
270
270
 
271
+ def to_s
272
+ "#<#{self.class.name}:#{object_id} #{server.address}>"
273
+ end
274
+
271
275
  private
272
276
 
273
277
  def pre_stop
@@ -196,6 +196,10 @@ module Mongo
196
196
  end
197
197
  end
198
198
 
199
+ def to_s
200
+ "#<#{self.class.name}:#{object_id} #{server.address}>"
201
+ end
202
+
199
203
  end
200
204
  end
201
205
  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.beta1'.freeze
23
+ VERSION = '2.18.0'.freeze
24
24
  end
data/lib/mongo.rb CHANGED
@@ -94,6 +94,8 @@ module Mongo
94
94
  # Take all the public instance methods from the Config singleton and allow
95
95
  # them to be accessed through the Mongo module directly.
96
96
  def_delegators Config, :options=
97
+ delegate_option Config, :broken_view_aggregate
98
+ delegate_option Config, :broken_view_options
97
99
  delegate_option Config, :validate_update_replace
98
100
  end
99
101
 
data/spec/README.md CHANGED
@@ -713,3 +713,17 @@ To break into the debugger on JRuby, call:
713
713
 
714
714
  require 'ruby-debug'
715
715
  debugger
716
+
717
+ ## Testing against load balancer locally
718
+
719
+ 1. Install mongodb server v5.2+.
720
+ 2. Install haproxy.
721
+ 3. Install mongo-orchestration - https://github.com/10gen/mongo-orchestration/
722
+ 4. Install drivers-evergreen-tools - https://github.com/mongodb-labs/drivers-evergreen-tools. In ruby driver it is installed as git submodule under `.mod/drivers-evergreen-tools/`.
723
+ 5. Start mongo-orchestration: `mongo-orchestration start`.
724
+ 6. Start the cluster: `http PUT http://localhost:8889/v1/sharded_clusters/myCluster @.mod/drivers-evergreen-tools/.evergreen/orchestration/configs/sharded_clusters/basic-load-balancer.json` (this example uses httpie client, can be done with curl).
725
+ 7. Start load balancer: `MONGODB_URI="mongodb://localhost:27017,localhost:27018/" .mod/drivers-evergreen-tools/.evergreen/run-load-balancer.sh start`.
726
+ 8. Run tests: `TOPOLOGY=load-balanced MONGODB_URI='mongodb://127.0.0.1:8000/?loadBalanced=true' be rspec spec/`.
727
+ 9. Stop load balancer: `MONGODB_URI="mongodb://localhost:27017,localhost:27018/" .mod/drivers-evergreen-tools/.evergreen/run-load-balancer.sh stop`.
728
+ 10. Stop the cluster: `http DELETE http://localhost:8889/v1/sharded_clusters/myCluster`
729
+ 11. Stop mongo-orchestration: `mongo-orchestration stop`.
@@ -4,7 +4,7 @@
4
4
  require 'spec_helper'
5
5
 
6
6
  describe 'Change stream integration' do
7
- retry_test 4
7
+ retry_test tries: 4
8
8
  require_mri
9
9
  max_example_run_time 7
10
10
  min_server_fcv '3.6'
@@ -191,16 +191,82 @@ describe 'Client construction' do
191
191
  context 'with default key vault client' do
192
192
  let(:key_vault_client) { nil }
193
193
 
194
- it 'creates a working key vault client' do
195
- key_vault_client = client.encrypter.key_vault_client
194
+ shared_examples 'creates a working key vault client' do
195
+ it 'creates a working key vault client' do
196
+ key_vault_client = client.encrypter.key_vault_client
196
197
 
197
- result = key_vault_client[:test].insert_one(test: 1)
198
- expect(result).to be_ok
198
+ result = key_vault_client[:test].insert_one(test: 1)
199
+ expect(result).to be_ok
200
+ end
199
201
  end
200
202
 
201
- it 'creates a key vault client with the same cluster as the existing client' do
202
- key_vault_client = client.encrypter.key_vault_client
203
- expect(key_vault_client.cluster).to eq(client.cluster)
203
+ context 'when top-level max pool size is not 0' do
204
+ include_examples 'creates a working key vault client'
205
+
206
+ shared_examples 'limited connection pool' do
207
+ it 'creates a key vault client with a different cluster than the existing client' do
208
+ key_vault_client = client.encrypter.key_vault_client
209
+ expect(key_vault_client.cluster).not_to eq(client.cluster)
210
+ end
211
+
212
+ # min pool size for the key vault client can be greater than 0
213
+ # when the key vault client is the same as the top-level client.
214
+ # This is OK because we aren't making any more connections for FLE,
215
+ # the minimum was requested by application for its own needs.
216
+ it 'uses min pool size 0 for key vault client' do
217
+ key_vault_client = client.encrypter.key_vault_client
218
+ key_vault_client.options[:min_pool_size].should be 0
219
+ end
220
+ end
221
+
222
+ context 'when top-level max pool size is not specified' do
223
+ before do
224
+ client.options[:max_pool_size].should be nil
225
+ end
226
+
227
+ include_examples 'limited connection pool'
228
+
229
+ it 'uses unspecified max pool size for key vault client' do
230
+ key_vault_client = client.encrypter.key_vault_client
231
+ key_vault_client.options[:max_pool_size].should be nil
232
+ end
233
+ end
234
+
235
+ context 'when top-level max pool size is specified' do
236
+ let(:options) do
237
+ {
238
+ auto_encryption_options: auto_encryption_options,
239
+ max_pool_size: 42,
240
+ }
241
+ end
242
+
243
+ include_examples 'limited connection pool'
244
+
245
+ it 'uses the same max pool size for key vault client' do
246
+ key_vault_client = client.encrypter.key_vault_client
247
+ key_vault_client.options[:max_pool_size].should be 42
248
+ end
249
+ end
250
+ end
251
+
252
+ context 'when top-level max pool size is 0' do
253
+ let(:options) do
254
+ {
255
+ auto_encryption_options: auto_encryption_options,
256
+ max_pool_size: 0,
257
+ }
258
+ end
259
+
260
+ before do
261
+ client.options[:max_pool_size].should be 0
262
+ end
263
+
264
+ include_examples 'creates a working key vault client'
265
+
266
+ it 'creates a key vault client with the same cluster as the existing client' do
267
+ key_vault_client = client.encrypter.key_vault_client
268
+ expect(key_vault_client.cluster).to eq(client.cluster)
269
+ end
204
270
  end
205
271
  end
206
272
  end