mongo 2.18.1 → 2.18.3

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 (139) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +1 -1
  4. data/lib/mongo/bulk_write.rb +6 -4
  5. data/lib/mongo/client.rb +1 -1
  6. data/lib/mongo/collection/view/iterable.rb +15 -0
  7. data/lib/mongo/collection/view/writable.rb +0 -2
  8. data/lib/mongo/collection/view.rb +1 -0
  9. data/lib/mongo/collection.rb +150 -45
  10. data/lib/mongo/crypt/auto_encrypter.rb +1 -0
  11. data/lib/mongo/crypt/explicit_encrypter.rb +1 -0
  12. data/lib/mongo/crypt/kms.rb +0 -1
  13. data/lib/mongo/crypt.rb +11 -0
  14. data/lib/mongo/error/invalid_read_option.rb +1 -1
  15. data/lib/mongo/grid/file/chunk.rb +2 -1
  16. data/lib/mongo/grid/file/info.rb +2 -1
  17. data/lib/mongo/operation/aggregate.rb +1 -2
  18. data/lib/mongo/operation/collections_info.rb +3 -15
  19. data/lib/mongo/operation/command.rb +1 -2
  20. data/lib/mongo/operation/count.rb +1 -2
  21. data/lib/mongo/operation/create.rb +1 -2
  22. data/lib/mongo/operation/create_index.rb +1 -2
  23. data/lib/mongo/operation/create_user.rb +1 -2
  24. data/lib/mongo/operation/delete.rb +0 -1
  25. data/lib/mongo/operation/distinct.rb +1 -2
  26. data/lib/mongo/operation/drop.rb +1 -2
  27. data/lib/mongo/operation/drop_database.rb +1 -2
  28. data/lib/mongo/operation/drop_index.rb +1 -2
  29. data/lib/mongo/operation/explain.rb +1 -3
  30. data/lib/mongo/operation/find/builder.rb +0 -1
  31. data/lib/mongo/operation/find.rb +1 -3
  32. data/lib/mongo/operation/get_more.rb +1 -3
  33. data/lib/mongo/operation/indexes.rb +1 -17
  34. data/lib/mongo/operation/insert.rb +0 -1
  35. data/lib/mongo/operation/kill_cursors.rb +1 -2
  36. data/lib/mongo/operation/list_collections.rb +1 -2
  37. data/lib/mongo/operation/map_reduce.rb +1 -2
  38. data/lib/mongo/operation/parallel_scan.rb +1 -2
  39. data/lib/mongo/operation/remove_user.rb +1 -2
  40. data/lib/mongo/operation/shared/{polymorphic_operation.rb → op_msg_executable.rb} +11 -6
  41. data/lib/mongo/operation/update.rb +0 -1
  42. data/lib/mongo/operation/update_user.rb +1 -2
  43. data/lib/mongo/operation/users_info.rb +1 -2
  44. data/lib/mongo/operation/write_command.rb +1 -2
  45. data/lib/mongo/operation.rb +1 -3
  46. data/lib/mongo/protocol/bit_vector.rb +3 -1
  47. data/lib/mongo/protocol/caching_hash.rb +3 -20
  48. data/lib/mongo/protocol/message.rb +4 -8
  49. data/lib/mongo/protocol/msg.rb +1 -0
  50. data/lib/mongo/protocol/serializers.rb +24 -17
  51. data/lib/mongo/protocol.rb +0 -3
  52. data/lib/mongo/query_cache.rb +20 -20
  53. data/lib/mongo/server/app_metadata/environment.rb +255 -0
  54. data/lib/mongo/server/app_metadata/truncator.rb +142 -0
  55. data/lib/mongo/server/app_metadata.rb +29 -42
  56. data/lib/mongo/session.rb +1 -1
  57. data/lib/mongo/version.rb +1 -1
  58. data/spec/integration/command_spec.rb +1 -23
  59. data/spec/integration/connection/faas_env_spec.rb +63 -0
  60. data/spec/integration/find_options_spec.rb +227 -0
  61. data/spec/integration/ocsp_verifier_spec.rb +1 -1
  62. data/spec/lite_spec_helper.rb +9 -0
  63. data/spec/mongo/address_spec.rb +1 -1
  64. data/spec/mongo/client_construction_spec.rb +7 -7
  65. data/spec/mongo/client_spec.rb +1 -9
  66. data/spec/mongo/cluster_spec.rb +2 -2
  67. data/spec/mongo/collection_crud_spec.rb +56 -0
  68. data/spec/mongo/collection_spec.rb +11 -1
  69. data/spec/mongo/crypt/kms_spec.rb +12 -9
  70. data/spec/mongo/crypt_spec.rb +21 -0
  71. data/spec/mongo/index/view_spec.rb +1 -0
  72. data/spec/mongo/protocol/caching_hash_spec.rb +0 -45
  73. data/spec/mongo/protocol/msg_spec.rb +2 -4
  74. data/spec/mongo/server/app_metadata/environment_spec.rb +193 -0
  75. data/spec/mongo/server/app_metadata/truncator_spec.rb +158 -0
  76. data/spec/mongo/server/app_metadata_spec.rb +33 -47
  77. data/spec/mongo/socket/ssl_spec.rb +2 -8
  78. data/spec/runners/crud/requirement.rb +2 -2
  79. data/spec/shared/lib/mrss/docker_runner.rb +4 -0
  80. data/spec/shared/lib/mrss/lite_constraints.rb +8 -0
  81. data/spec/shared/lib/mrss/server_version_registry.rb +16 -23
  82. data/spec/shared/share/Dockerfile.erb +24 -19
  83. data/spec/shared/shlib/server.sh +31 -7
  84. data/spec/shared/shlib/set_env.sh +4 -4
  85. data/spec/solo/clean_exit_spec.rb +3 -10
  86. data/spec/spec_tests/data/change_streams_unified/change-streams-showExpandedEvents.yml +15 -6
  87. data/spec/spec_tests/data/command_monitoring_unified/redacted-commands.yml +8 -0
  88. data/spec/support/aws_utils.rb +3 -3
  89. data/spec/support/certificates/atlas-ocsp-ca.crt +67 -67
  90. data/spec/support/certificates/atlas-ocsp.crt +103 -103
  91. data/spec/support/shared/app_metadata.rb +14 -2
  92. data.tar.gz.sig +0 -0
  93. metadata +1203 -1239
  94. metadata.gz.sig +0 -0
  95. data/lib/mongo/operation/aggregate/command.rb +0 -55
  96. data/lib/mongo/operation/collections_info/command.rb +0 -48
  97. data/lib/mongo/operation/command/command.rb +0 -41
  98. data/lib/mongo/operation/count/command.rb +0 -47
  99. data/lib/mongo/operation/create/command.rb +0 -47
  100. data/lib/mongo/operation/create_index/command.rb +0 -61
  101. data/lib/mongo/operation/create_user/command.rb +0 -46
  102. data/lib/mongo/operation/delete/command.rb +0 -52
  103. data/lib/mongo/operation/distinct/command.rb +0 -47
  104. data/lib/mongo/operation/drop/command.rb +0 -41
  105. data/lib/mongo/operation/drop_database/command.rb +0 -41
  106. data/lib/mongo/operation/drop_index/command.rb +0 -45
  107. data/lib/mongo/operation/explain/command.rb +0 -58
  108. data/lib/mongo/operation/explain/legacy.rb +0 -52
  109. data/lib/mongo/operation/find/builder/legacy.rb +0 -123
  110. data/lib/mongo/operation/find/command.rb +0 -51
  111. data/lib/mongo/operation/find/legacy/result.rb +0 -46
  112. data/lib/mongo/operation/find/legacy.rb +0 -52
  113. data/lib/mongo/operation/get_more/command.rb +0 -43
  114. data/lib/mongo/operation/get_more/legacy.rb +0 -39
  115. data/lib/mongo/operation/indexes/command.rb +0 -42
  116. data/lib/mongo/operation/indexes/legacy.rb +0 -48
  117. data/lib/mongo/operation/insert/command.rb +0 -55
  118. data/lib/mongo/operation/kill_cursors/command.rb +0 -48
  119. data/lib/mongo/operation/list_collections/command.rb +0 -46
  120. data/lib/mongo/operation/map_reduce/command.rb +0 -51
  121. data/lib/mongo/operation/parallel_scan/command.rb +0 -57
  122. data/lib/mongo/operation/remove_user/command.rb +0 -46
  123. data/lib/mongo/operation/shared/op_msg_or_command.rb +0 -41
  124. data/lib/mongo/operation/shared/op_msg_or_find_command.rb +0 -44
  125. data/lib/mongo/operation/update/command.rb +0 -53
  126. data/lib/mongo/operation/update_user/command.rb +0 -45
  127. data/lib/mongo/operation/users_info/command.rb +0 -46
  128. data/lib/mongo/operation/write_command/command.rb +0 -51
  129. data/lib/mongo/protocol/delete.rb +0 -172
  130. data/lib/mongo/protocol/insert.rb +0 -181
  131. data/lib/mongo/protocol/update.rb +0 -214
  132. data/spec/mongo/operation/delete/command_spec.rb +0 -115
  133. data/spec/mongo/operation/find/legacy_spec.rb +0 -131
  134. data/spec/mongo/operation/get_more_spec.rb +0 -63
  135. data/spec/mongo/operation/insert/command_spec.rb +0 -118
  136. data/spec/mongo/operation/update/command_spec.rb +0 -122
  137. data/spec/mongo/protocol/delete_spec.rb +0 -185
  138. data/spec/mongo/protocol/insert_spec.rb +0 -179
  139. data/spec/mongo/protocol/update_spec.rb +0 -204
@@ -15,6 +15,9 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
+ require 'mongo/server/app_metadata/environment'
19
+ require 'mongo/server/app_metadata/truncator'
20
+
18
21
  module Mongo
19
22
  class Server
20
23
  # Application metadata that is sent to the server during a handshake,
@@ -26,11 +29,6 @@ module Mongo
26
29
  class AppMetadata
27
30
  extend Forwardable
28
31
 
29
- # The max application metadata document byte size.
30
- #
31
- # @since 2.4.0
32
- MAX_DOCUMENT_SIZE = 512.freeze
33
-
34
32
  # The max application name byte size.
35
33
  #
36
34
  # @since 2.4.0
@@ -139,6 +137,23 @@ module Mongo
139
137
  document
140
138
  end
141
139
 
140
+ # Get BSON::Document to be used as value for `client` key in
141
+ # handshake document.
142
+ #
143
+ # @return [BSON::Document] Document describing client for handshake.
144
+ #
145
+ # @api private
146
+ def client_document
147
+ @client_document ||=
148
+ BSON::Document.new.tap do |doc|
149
+ doc[:application] = { name: @app_name } if @app_name
150
+ doc[:driver] = driver_doc
151
+ doc[:os] = os_doc
152
+ doc[:platform] = platform
153
+ env_doc.tap { |env| doc[:env] = env if env }
154
+ end
155
+ end
156
+
142
157
  private
143
158
 
144
159
  # Check whether it is possible to build a valid app metadata document
@@ -152,20 +167,6 @@ module Mongo
152
167
  true
153
168
  end
154
169
 
155
- # Get BSON::Document to be used as value for `client` key in
156
- # handshake document.
157
- #
158
- # @return [BSON::Document] Document describing client for handshake.
159
- def full_client_document
160
- BSON::Document.new.tap do |doc|
161
- doc[:application] = { name: @app_name } if @app_name
162
- doc[:driver] = driver_doc
163
- doc[:os] = os_doc
164
- doc[:platform] = platform
165
- end
166
- end
167
-
168
-
169
170
  # Get the metadata as BSON::Document to be sent to
170
171
  # as part of the handshake. The document should
171
172
  # be appended to a suitable handshake command.
@@ -173,30 +174,11 @@ module Mongo
173
174
  # @return [BSON::Document] Document for connection's handshake.
174
175
  def document
175
176
  @document ||= begin
176
- client_document = full_client_document
177
- while client_document.to_bson.to_s.size > MAX_DOCUMENT_SIZE do
178
- if client_document[:os][:name] || client_document[:os][:architecture]
179
- client_document[:os].delete(:name)
180
- client_document[:os].delete(:architecture)
181
- elsif client_document[:platform]
182
- client_document.delete(:platform)
183
- else
184
- client_document = nil
185
- end
177
+ client = Truncator.new(client_document).document
178
+ BSON::Document.new(compression: @compressors, client: client).tap do |doc|
179
+ doc[:saslSupportedMechs] = @request_auth_mech if @request_auth_mech
180
+ doc.update(Utils.transform_server_api(@server_api)) if @server_api
186
181
  end
187
- document = BSON::Document.new(
188
- {
189
- compression: @compressors,
190
- client: client_document,
191
- }
192
- )
193
- document[:saslSupportedMechs] = @request_auth_mech if @request_auth_mech
194
- if @server_api
195
- document.update(
196
- Utils.transform_server_api(@server_api)
197
- )
198
- end
199
- document
200
182
  end
201
183
  end
202
184
 
@@ -223,6 +205,11 @@ module Mongo
223
205
  }
224
206
  end
225
207
 
208
+ def env_doc
209
+ env = Environment.new
210
+ env.faas? ? env.to_h : nil
211
+ end
212
+
226
213
  def type
227
214
  (RbConfig::CONFIG && RbConfig::CONFIG['host_os']) ?
228
215
  RbConfig::CONFIG['host_os'].split('_').first[/[a-z]+/i].downcase : 'unknown'
data/lib/mongo/session.rb CHANGED
@@ -522,7 +522,7 @@ module Mongo
522
522
  #
523
523
  # @option options [ Integer ] :max_commit_time_ms The maximum amount of
524
524
  # time to allow a single commitTransaction command to run, in milliseconds.
525
- # @option options [ Hash ] read_concern The read concern options hash,
525
+ # @option options [ Hash ] :read_concern The read concern options hash,
526
526
  # with the following optional keys:
527
527
  # - *:level* -- the read preference level as a symbol; valid values
528
528
  # are *:local*, *:majority*, and *:snapshot*
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.1'.freeze
23
+ VERSION = '2.18.3'.freeze
24
24
  end
@@ -12,7 +12,7 @@ describe 'Command' do
12
12
 
13
13
  let(:payload) do
14
14
  server.with_connection do |connection|
15
- command.send(:final_operation, connection).send(:message, connection).payload.dup.tap do |payload|
15
+ command.send(:final_operation).send(:message, connection).payload.dup.tap do |payload|
16
16
  if payload['request_id'].is_a?(Integer)
17
17
  payload['request_id'] = 42
18
18
  end
@@ -150,28 +150,6 @@ describe 'Command' do
150
150
  expect(payload).to eq(expected_payload)
151
151
  end
152
152
  end
153
-
154
- # Servers using legacy wire protocol message do not have $db in payload.
155
- # $db is added to the payload later when the command monitoring event is
156
- # published.
157
- context 'pre-OP_MSG servers' do
158
- max_server_version '3.4'
159
-
160
- let(:expected_payload) do
161
- {
162
- 'command' => {
163
- 'find' => 'collection_name',
164
- },
165
- 'command_name' => 'find',
166
- 'database_name' => 'foo',
167
- 'request_id' => 42,
168
- }
169
- end
170
-
171
- it 'returns expected payload' do
172
- expect(payload).to eq(expected_payload)
173
- end
174
- end
175
153
  end
176
154
 
177
155
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ # Test Plan scenarios from the handshake spec
6
+ SCENARIOS = {
7
+ 'Valid AWS' => {
8
+ 'AWS_EXECUTION_ENV' => 'AWS_Lambda_ruby2.7',
9
+ 'AWS_REGION' => 'us-east-2',
10
+ 'AWS_LAMBDA_FUNCTION_MEMORY_SIZE' => '1024',
11
+ },
12
+
13
+ 'Valid Azure' => {
14
+ 'FUNCTIONS_WORKER_RUNTIME' => 'ruby',
15
+ },
16
+
17
+ 'Valid GCP' => {
18
+ 'K_SERVICE' => 'servicename',
19
+ 'FUNCTION_MEMORY_MB' => '1024',
20
+ 'FUNCTION_TIMEOUT_SEC' => '60',
21
+ 'FUNCTION_REGION' => 'us-central1',
22
+ },
23
+
24
+ 'Valid Vercel' => {
25
+ 'VERCEL' => '1',
26
+ 'VERCEL_URL' => '*.vercel.app',
27
+ 'VERCEL_REGION' => 'cdg1',
28
+ },
29
+
30
+ 'Invalid - multiple providers' => {
31
+ 'AWS_EXECUTION_ENV' => 'AWS_Lambda_ruby2.7',
32
+ 'AWS_REGION' => 'us-east-2',
33
+ 'AWS_LAMBDA_FUNCTION_MEMORY_SIZE' => '1024',
34
+ 'FUNCTIONS_WORKER_RUNTIME' => 'ruby',
35
+ },
36
+
37
+ 'Invalid - long string' => {
38
+ 'AWS_EXECUTION_ENV' => 'AWS_Lambda_ruby2.7',
39
+ 'AWS_REGION' => 'a' * 512,
40
+ 'AWS_LAMBDA_FUNCTION_MEMORY_SIZE' => '1024',
41
+ },
42
+
43
+ 'Invalid - wrong types' => {
44
+ 'AWS_EXECUTION_ENV' => 'AWS_Lambda_ruby2.7',
45
+ 'AWS_REGION' => 'us-east-2',
46
+ 'AWS_LAMBDA_FUNCTION_MEMORY_SIZE' => 'big',
47
+ },
48
+ }.freeze
49
+
50
+ describe 'Connect under FaaS Env' do
51
+ clean_slate
52
+
53
+ SCENARIOS.each do |name, env|
54
+ context "when given #{name}" do
55
+ local_env(env)
56
+
57
+ it 'connects successfully' do
58
+ resp = authorized_client.database.command(ping: 1)
59
+ expect(resp).to be_a(Mongo::Operation::Result)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,227 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'Find operation options' do
6
+ require_mri
7
+ require_no_auth
8
+ min_server_fcv '4.4'
9
+
10
+ let(:subscriber) { Mrss::EventSubscriber.new }
11
+
12
+ let(:seeds) do
13
+ [ SpecConfig.instance.addresses.first ]
14
+ end
15
+
16
+ let(:client_options) do
17
+ {}
18
+ end
19
+
20
+ let(:collection_options) do
21
+ {}
22
+ end
23
+
24
+ let(:client) do
25
+ ClientRegistry.instance.new_local_client(
26
+ seeds,
27
+ SpecConfig.instance.test_options
28
+ .merge(database: SpecConfig.instance.test_db)
29
+ .merge(client_options)
30
+ ).tap do |client|
31
+ client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
32
+ end
33
+ end
34
+
35
+ let(:collection) do
36
+ client['find_options', collection_options]
37
+ end
38
+
39
+ let(:find_command) do
40
+ subscriber.started_events.find { |cmd| cmd.command_name == 'find' }
41
+ end
42
+
43
+ let(:should_create_collection) { true }
44
+
45
+ before do
46
+ client['find_options'].drop
47
+ collection.create if should_create_collection
48
+ collection.insert_many([ { a: 1 }, { a: 2 }, { a: 3 } ])
49
+ end
50
+
51
+ describe 'collation' do
52
+ let(:client_options) do
53
+ {}
54
+ end
55
+
56
+ let(:collation) do
57
+ { 'locale' => 'en_US' }
58
+ end
59
+
60
+ context 'when defined on the collection' do
61
+ let(:collection_options) do
62
+ { collation: collation }
63
+ end
64
+
65
+ it 'uses the collation defined on the collection' do
66
+ collection.find.to_a
67
+ expect(find_command.command['collation']).to be_nil
68
+ end
69
+ end
70
+
71
+ context 'when defined on the operation' do
72
+ let(:collection_options) do
73
+ {}
74
+ end
75
+
76
+ it 'uses the collation defined on the collection' do
77
+ collection.find({}, collation: collation).to_a
78
+ expect(find_command.command['collation']).to eq(collation)
79
+ end
80
+ end
81
+
82
+ context 'when defined on both collection and operation' do
83
+ let(:collection_options) do
84
+ { 'locale' => 'de_AT' }
85
+ end
86
+
87
+ let(:should_create_collection) { false }
88
+
89
+ it 'uses the collation defined on the collection' do
90
+ collection.find({}, collation: collation).to_a
91
+ expect(find_command.command['collation']).to eq(collation)
92
+ end
93
+ end
94
+ end
95
+
96
+ describe 'read concern' do
97
+ context 'when defined on the client' do
98
+ let(:client_options) do
99
+ { read_concern: { level: :local } }
100
+ end
101
+
102
+ let(:collection_options) do
103
+ {}
104
+ end
105
+
106
+ it 'uses the read concern defined on the client' do
107
+ collection.find.to_a
108
+ expect(find_command.command['readConcern']).to eq('level' => 'local')
109
+ end
110
+
111
+ context 'when defined on the collection' do
112
+ let(:collection_options) do
113
+ { read_concern: { level: :majority } }
114
+ end
115
+
116
+ it 'uses the read concern defined on the collection' do
117
+ collection.find.to_a
118
+ expect(find_command.command['readConcern']).to eq('level' => 'majority')
119
+ end
120
+
121
+ context 'when defined on the operation' do
122
+ let(:operation_read_concern) do
123
+ { level: :available }
124
+ end
125
+
126
+ it 'uses the read concern defined on the operation' do
127
+ collection.find({}, read_concern: operation_read_concern).to_a
128
+ expect(find_command.command['readConcern']).to eq('level' => 'available')
129
+ end
130
+ end
131
+ end
132
+
133
+ context 'when defined on the operation' do
134
+ let(:collection_options) do
135
+ {}
136
+ end
137
+
138
+ let(:operation_read_concern) do
139
+ { level: :available }
140
+ end
141
+
142
+ it 'uses the read concern defined on the operation' do
143
+ collection.find({}, read_concern: operation_read_concern).to_a
144
+ expect(find_command.command['readConcern']).to eq('level' => 'available')
145
+ end
146
+ end
147
+ end
148
+
149
+ context 'when defined on the collection' do
150
+ let(:client_options) do
151
+ {}
152
+ end
153
+
154
+ let(:collection_options) do
155
+ { read_concern: { level: :majority } }
156
+ end
157
+
158
+ it 'uses the read concern defined on the collection' do
159
+ collection.find.to_a
160
+ expect(find_command.command['readConcern']).to eq('level' => 'majority')
161
+ end
162
+
163
+ context 'when defined on the operation' do
164
+ let(:operation_read_concern) do
165
+ { level: :available }
166
+ end
167
+
168
+ it 'uses the read concern defined on the operation' do
169
+ collection.find({}, read_concern: operation_read_concern).to_a
170
+ expect(find_command.command['readConcern']).to eq('level' => 'available')
171
+ end
172
+ end
173
+ end
174
+ end
175
+
176
+ describe 'read preference' do
177
+ require_topology :replica_set
178
+
179
+ context 'when defined on the client' do
180
+ let(:client_options) do
181
+ { read: { mode: :secondary } }
182
+ end
183
+
184
+ let(:collection_options) do
185
+ {}
186
+ end
187
+
188
+ it 'uses the read preference defined on the client' do
189
+ collection.find.to_a
190
+ expect(find_command.command['$readPreference']).to eq('mode' => 'secondary')
191
+ end
192
+
193
+ context 'when defined on the collection' do
194
+ let(:collection_options) do
195
+ { read: { mode: :secondary_preferred } }
196
+ end
197
+
198
+ it 'uses the read concern defined on the collection' do
199
+ collection.find.to_a
200
+ expect(find_command.command['$readPreference']).to eq('mode' => 'secondaryPreferred')
201
+ end
202
+ end
203
+ end
204
+ end
205
+
206
+ describe 'cursor type' do
207
+ let(:collection_options) do
208
+ { capped: true, size: 1000 }
209
+ end
210
+
211
+ context 'when cursor type is :tailable' do
212
+ it 'sets the cursor type to tailable' do
213
+ collection.find({}, cursor_type: :tailable).first
214
+ expect(find_command.command['tailable']).to be true
215
+ expect(find_command.command['awaitData']).to be_falsey
216
+ end
217
+ end
218
+
219
+ context 'when cursor type is :tailable_await' do
220
+ it 'sets the cursor type to tailable' do
221
+ collection.find({}, cursor_type: :tailable_await).first
222
+ expect(find_command.command['tailable']).to be true
223
+ expect(find_command.command['awaitData']).to be true
224
+ end
225
+ end
226
+ end
227
+ end
@@ -352,7 +352,7 @@ describe Mongo::Socket::OcspVerifier do
352
352
 
353
353
  it 'verifies' do
354
354
  # TODO This test will fail if the certificate expires
355
- verifier.verify.should be true
355
+ expect(verifier.verify).to be(true), "If atlas-ocsp certificates have expired, run spec/support/certificates/retrieve-atlas-cert to get a new ones"
356
356
  end
357
357
  end
358
358
  end
@@ -110,6 +110,15 @@ RSpec.configure do |config|
110
110
  config.include(MongosMacros)
111
111
  config.extend(Mongo::Macros)
112
112
 
113
+ # Used for spec/solo/*
114
+ def require_solo
115
+ before(:all) do
116
+ unless %w(1 true yes).include?(ENV['SOLO'])
117
+ skip 'Set SOLO=1 in environment to run solo tests'
118
+ end
119
+ end
120
+ end
121
+
113
122
  if SpecConfig.instance.ci?
114
123
  SdamFormatterIntegration.subscribe
115
124
  config.add_formatter(JsonExtFormatter, File.join(File.dirname(__FILE__), '../tmp/rspec.json'))
@@ -305,7 +305,7 @@ describe Mongo::Address do
305
305
  RSpec::Mocks.with_temporary_scope do
306
306
  resolved_address = double('address')
307
307
  # This test's expectation
308
- expect(resolved_address).to receive(:socket).with(0, connect_timeout: 10)
308
+ expect(resolved_address).to receive(:socket).with(0, { connect_timeout: 10 })
309
309
 
310
310
  expect(Mongo::Address::IPv4).to receive(:new).and_return(resolved_address)
311
311
 
@@ -953,7 +953,7 @@ describe Mongo::Client do
953
953
  end
954
954
 
955
955
  it 'includes the platform info in the app metadata' do
956
- expect(app_metadata.send(:full_client_document)[:platform]).to match(/mongoid-6\.0\.2/)
956
+ expect(app_metadata.client_document[:platform]).to match(/mongoid-6\.0\.2/)
957
957
  end
958
958
  end
959
959
 
@@ -980,7 +980,7 @@ describe Mongo::Client do
980
980
  end
981
981
 
982
982
  it 'does not include the platform info in the app metadata' do
983
- expect(app_metadata.send(:full_client_document)[:platform]).to eq(platform_string)
983
+ expect(app_metadata.client_document[:platform]).to eq(platform_string)
984
984
  end
985
985
  end
986
986
 
@@ -999,7 +999,7 @@ describe Mongo::Client do
999
999
  end
1000
1000
 
1001
1001
  it 'does not include the platform info in the app metadata' do
1002
- expect(app_metadata.send(:full_client_document)[:platform]).to eq(platform_string)
1002
+ expect(app_metadata.client_document[:platform]).to eq(platform_string)
1003
1003
  end
1004
1004
  end
1005
1005
  end
@@ -1773,28 +1773,28 @@ describe Mongo::Client do
1773
1773
  expect do
1774
1774
  client = new_local_client_nmio(['127.0.0.1:27017'],
1775
1775
  :read => {:mode => :bogus})
1776
- end.to raise_error(Mongo::Error::InvalidReadOption, 'Invalid read option: {"mode"=>:bogus}: mode bogus is not one of recognized modes')
1776
+ end.to raise_error(Mongo::Error::InvalidReadOption, 'Invalid read preference value: {"mode"=>:bogus}: mode bogus is not one of recognized modes')
1777
1777
  end
1778
1778
 
1779
1779
  it 'rejects bogus read preference as string' do
1780
1780
  expect do
1781
1781
  client = new_local_client_nmio(['127.0.0.1:27017'],
1782
1782
  :read => {:mode => 'bogus'})
1783
- end.to raise_error(Mongo::Error::InvalidReadOption, 'Invalid read option: {"mode"=>"bogus"}: mode bogus is not one of recognized modes')
1783
+ end.to raise_error(Mongo::Error::InvalidReadOption, 'Invalid read preference value: {"mode"=>"bogus"}: mode bogus is not one of recognized modes')
1784
1784
  end
1785
1785
 
1786
1786
  it 'rejects read option specified as a string' do
1787
1787
  expect do
1788
1788
  client = new_local_client_nmio(['127.0.0.1:27017'],
1789
1789
  :read => 'primary')
1790
- end.to raise_error(Mongo::Error::InvalidReadOption, 'Invalid read option: primary: must be a hash')
1790
+ end.to raise_error(Mongo::Error::InvalidReadOption, 'Invalid read preference value: "primary": the read preference must be specified as a hash: { mode: "primary" }')
1791
1791
  end
1792
1792
 
1793
1793
  it 'rejects read option specified as a symbol' do
1794
1794
  expect do
1795
1795
  client = new_local_client_nmio(['127.0.0.1:27017'],
1796
1796
  :read => :primary)
1797
- end.to raise_error(Mongo::Error::InvalidReadOption, 'Invalid read option: primary: must be a hash')
1797
+ end.to raise_error(Mongo::Error::InvalidReadOption, "Invalid read preference value: :primary: the read preference must be specified as a hash: { mode: :primary }")
1798
1798
  end
1799
1799
  end
1800
1800
  end
@@ -947,7 +947,7 @@ describe Mongo::Client do
947
947
  before do
948
948
  sessions_checked_out = 0
949
949
 
950
- allow_any_instance_of(Mongo::Server).to receive(:with_connection).and_wrap_original do |m, *args, &block|
950
+ allow_any_instance_of(Mongo::Server).to receive(:with_connection).and_wrap_original do |m, *args, **kwargs, &block|
951
951
  m.call(*args) do |connection|
952
952
  sessions_checked_out = 0
953
953
  res = block.call(connection)
@@ -955,14 +955,6 @@ describe Mongo::Client do
955
955
  res
956
956
  end
957
957
  end
958
-
959
- allow_any_instance_of(Mongo::Session).to receive(:materialize).and_wrap_original do |m, *args|
960
- sessions_checked_out += 1
961
- m.call(*args).tap do
962
- checked_out_connections = args[0].connection_pool.instance_variable_get("@checked_out_connections")
963
- expect(checked_out_connections.length).to eq 1
964
- end
965
- end
966
958
  end
967
959
 
968
960
  it 'doesn\'t have any live sessions' do
@@ -480,7 +480,7 @@ describe Mongo::Cluster do
480
480
  end
481
481
 
482
482
  it 'constructs an AppMetadata object with the app_name' do
483
- expect(cluster.app_metadata.send(:full_client_document)[:application]).to eq('name' => 'cluster_test')
483
+ expect(cluster.app_metadata.client_document[:application]).to eq('name' => 'cluster_test')
484
484
  end
485
485
  end
486
486
 
@@ -491,7 +491,7 @@ describe Mongo::Cluster do
491
491
  end
492
492
 
493
493
  it 'constructs an AppMetadata object with no app_name' do
494
- expect(cluster.app_metadata.send(:full_client_document)[:application]).to be_nil
494
+ expect(cluster.app_metadata.client_document[:application]).to be_nil
495
495
  end
496
496
  end
497
497
  end
@@ -362,6 +362,42 @@ describe Mongo::Collection do
362
362
  expect(result.inserted_ids.size).to eq(2)
363
363
  end
364
364
 
365
+ context 'when an enumerable is used instead of an array' do
366
+
367
+ context 'when the enumerable is not empty' do
368
+
369
+ let(:source_data) do
370
+ [{ name: 'test1' }, { name: 'test2' }]
371
+ end
372
+
373
+ let(:result) do
374
+ authorized_collection.insert_many(source_data.lazy)
375
+ end
376
+
377
+ it 'should accepts them without raising an error' do
378
+ expect { result }.to_not raise_error
379
+ expect(result.inserted_count).to eq(source_data.size)
380
+ end
381
+ end
382
+
383
+ context 'when the enumerable is empty' do
384
+
385
+ let(:source_data) do
386
+ []
387
+ end
388
+
389
+ let(:result) do
390
+ authorized_collection.insert_many(source_data.lazy)
391
+ end
392
+
393
+ it 'should raise ArgumentError' do
394
+ expect do
395
+ result
396
+ end.to raise_error(ArgumentError, /Bulk write requests cannot be empty/)
397
+ end
398
+ end
399
+ end
400
+
365
401
  context 'when a session is provided' do
366
402
 
367
403
  let(:session) do
@@ -4412,4 +4448,24 @@ describe Mongo::Collection do
4412
4448
  expect(result).to be_nil
4413
4449
  end
4414
4450
  end
4451
+
4452
+ context "when creating collection with view_on and pipeline" do
4453
+ before do
4454
+ authorized_client["my_view"].drop
4455
+ authorized_collection.insert_one({ bar: "here!" })
4456
+ authorized_client["my_view",
4457
+ view_on: authorized_collection.name,
4458
+ pipeline: [ { :'$project' => { "baz": "$bar" } } ]
4459
+ ].create
4460
+ end
4461
+
4462
+ it "the view has a document" do
4463
+ expect(authorized_client["my_view"].find.to_a.length).to eq(1)
4464
+ end
4465
+
4466
+ it "applies the pipeline" do
4467
+ expect(authorized_client["my_view"].find.first).to have_key("baz")
4468
+ expect(authorized_client["my_view"].find.first["baz"]).to eq("here!")
4469
+ end
4470
+ end
4415
4471
  end