mongo 2.18.0.beta1 → 2.18.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -87,7 +87,7 @@ describe Mongo::Collection::View::Readable do
87
87
 
88
88
  describe '#aggregate' do
89
89
 
90
- let(:documents) do
90
+ let(:documents) do
91
91
  [
92
92
  { city: "Berlin", pop: 18913, neighborhood: "Kreuzberg" },
93
93
  { city: "Berlin", pop: 84143, neighborhood: "Mitte" },
@@ -151,6 +151,159 @@ describe Mongo::Collection::View::Readable do
151
151
  expect(aggregation.options[:max_time_ms]).to eq(agg_options[:max_time_ms])
152
152
  end
153
153
  end
154
+
155
+ context "when using methods to set aggregate options" do
156
+
157
+ context "when the broken_view_options flag is off" do
158
+ config_override :broken_view_options, false
159
+
160
+ let(:aggregate) do
161
+ view.send(opt, param).aggregate(pipeline, options)
162
+ end
163
+
164
+ context "when a :allow_disk_use is given" do
165
+ let(:aggregate) do
166
+ view.allow_disk_use.aggregate(pipeline, options)
167
+ end
168
+ let(:opt) { :allow_disk_use }
169
+
170
+ it "sets the option correctly" do
171
+ expect(aggregate.options[opt]).to eq(true)
172
+ end
173
+ end
174
+
175
+ context "when a :batch_size is given" do
176
+ let(:opt) { :batch_size }
177
+ let(:param) { 2 }
178
+
179
+ it "sets the option correctly" do
180
+ expect(aggregate.options[opt]).to eq(param)
181
+ end
182
+ end
183
+
184
+ context "when a :max_time_ms is given" do
185
+ let(:opt) { :max_time_ms }
186
+ let(:param) { 2 }
187
+
188
+ it "sets the option correctly" do
189
+ expect(aggregate.options[opt]).to eq(param)
190
+ end
191
+ end
192
+
193
+ context "when a :max_await_time_ms is given" do
194
+ let(:opt) { :max_await_time_ms }
195
+ let(:param) { 2 }
196
+
197
+ it "sets the option correctly" do
198
+ expect(aggregate.options[opt]).to eq(param)
199
+ end
200
+ end
201
+
202
+ context "when a :comment is given" do
203
+ let(:opt) { :comment }
204
+ let(:param) { "comment" }
205
+
206
+ it "sets the option correctly" do
207
+ expect(aggregate.options[opt]).to eq(param)
208
+ end
209
+ end
210
+
211
+ context "when a :hint is given" do
212
+ let(:opt) { :hint }
213
+ let(:param) { "_id_" }
214
+
215
+ it "sets the option correctly" do
216
+ expect(aggregate.options[opt]).to eq(param)
217
+ end
218
+ end
219
+
220
+ context "when also including in options" do
221
+
222
+ let(:aggregate) do
223
+ view.limit(1).aggregate(pipeline, { limit: 2 })
224
+ end
225
+
226
+ it "sets the option correctly" do
227
+ expect(aggregate.options[:limit]).to eq(2)
228
+ end
229
+ end
230
+ end
231
+
232
+ context "when the broken_view_options flag is on" do
233
+ config_override :broken_view_options, true
234
+
235
+ let(:aggregate) do
236
+ view.send(opt, param).aggregate(pipeline, options)
237
+ end
238
+
239
+ context "when a :allow_disk_use is given" do
240
+ let(:aggregate) do
241
+ view.allow_disk_use.aggregate(pipeline, options)
242
+ end
243
+ let(:opt) { :allow_disk_use }
244
+
245
+ it "doesn't set the option correctly" do
246
+ expect(aggregate.options[opt]).to be_nil
247
+ end
248
+ end
249
+
250
+ context "when a :batch_size is given" do
251
+ let(:opt) { :batch_size }
252
+ let(:param) { 2 }
253
+
254
+ it "doesn't set the option correctly" do
255
+ expect(aggregate.options[opt]).to be_nil
256
+ end
257
+ end
258
+
259
+ context "when a :max_time_ms is given" do
260
+ let(:opt) { :max_time_ms }
261
+ let(:param) { 2 }
262
+
263
+ it "doesn't set the option correctly" do
264
+ expect(aggregate.options[opt]).to be_nil
265
+ end
266
+ end
267
+
268
+ context "when a :max_await_time_ms is given" do
269
+ let(:opt) { :max_await_time_ms }
270
+ let(:param) { 2 }
271
+
272
+ it "doesn't set the option correctly" do
273
+ expect(aggregate.options[opt]).to be_nil
274
+ end
275
+ end
276
+
277
+ context "when a :comment is given" do
278
+ let(:opt) { :comment }
279
+ let(:param) { "comment" }
280
+
281
+ it "doesn't set the option correctly" do
282
+ expect(aggregate.options[opt]).to be_nil
283
+ end
284
+ end
285
+
286
+ context "when a :hint is given" do
287
+ let(:opt) { :hint }
288
+ let(:param) { "_id_" }
289
+
290
+ it "doesn't set the option correctly" do
291
+ expect(aggregate.options[opt]).to be_nil
292
+ end
293
+ end
294
+
295
+ context "when also including in options" do
296
+
297
+ let(:aggregate) do
298
+ view.limit(1).aggregate(pipeline, { limit: 2 })
299
+ end
300
+
301
+ it "sets the option correctly" do
302
+ expect(aggregate.options[:limit]).to eq(2)
303
+ end
304
+ end
305
+ end
306
+ end
154
307
  end
155
308
 
156
309
  describe '#map_reduce' do
@@ -230,6 +383,42 @@ describe Mongo::Collection::View::Readable do
230
383
  end
231
384
  end
232
385
  end
386
+
387
+ context "when using methods to set map_reduce options" do
388
+
389
+ let(:map_reduce) do
390
+ view.send(opt, param).map_reduce(map, reduce, options)
391
+ end
392
+
393
+ context "when a :limit is given" do
394
+ let(:opt) { :limit }
395
+ let(:param) { 1 }
396
+
397
+ it "sets the option correctly" do
398
+ expect(map_reduce.options[opt]).to eq(param)
399
+ end
400
+ end
401
+
402
+ context "when a :sort is given" do
403
+ let(:opt) { :sort }
404
+ let(:param) { { 'x' => Mongo::Index::ASCENDING } }
405
+
406
+ it "sets the option correctly" do
407
+ expect(map_reduce.options[opt]).to eq(param)
408
+ end
409
+ end
410
+
411
+ context "when also including in options" do
412
+
413
+ let(:map_reduce) do
414
+ view.limit(1).map_reduce(map, reduce, { limit: 2})
415
+ end
416
+
417
+ it "sets the option correctly" do
418
+ expect(map_reduce.options[:limit]).to eq(2)
419
+ end
420
+ end
421
+ end
233
422
  end
234
423
 
235
424
  describe '#batch_size' do
@@ -603,6 +792,90 @@ describe Mongo::Collection::View::Readable do
603
792
  end
604
793
  end
605
794
  end
795
+
796
+ context "when using methods to set count options" do
797
+ let(:obj_path) { [:selector, opt] }
798
+
799
+ shared_examples "a count option" do
800
+
801
+ context "when the broken_view_options flag is off" do
802
+ config_override :broken_view_options, false
803
+
804
+ it "sets the option correctly" do
805
+ expect(Mongo::Operation::Count).to receive(:new).once.and_wrap_original do |m, *args|
806
+ opts = args.first.slice(*args.first.keys - [:session])
807
+ expect(opts.dig(*obj_path)).to eq(param)
808
+ m.call(*args)
809
+ end
810
+ view.send(opt, param).count(options)
811
+ end
812
+ end
813
+
814
+ context "when the broken_view_options flag is on" do
815
+ config_override :broken_view_options, true
816
+
817
+ it "doesn't set the option correctly" do
818
+ expect(Mongo::Operation::Count).to receive(:new).once.and_wrap_original do |m, *args|
819
+ opts = args.first.slice(*args.first.keys - [:session])
820
+ expect(opts.dig(*obj_path)).to be_nil
821
+ m.call(*args)
822
+ end
823
+ view.send(opt, param).count(options)
824
+ end
825
+ end
826
+ end
827
+
828
+ context "when a :hint is given" do
829
+ let(:opt) { :hint }
830
+ let(:param) { "_id_" }
831
+
832
+ it_behaves_like "a count option"
833
+ end
834
+
835
+ context "when a :max_time_ms is given" do
836
+ let(:opt) { :max_time_ms }
837
+ let(:param) { 5000 }
838
+ let(:obj_path) { [:selector, :maxTimeMS] }
839
+
840
+ it_behaves_like "a count option"
841
+ end
842
+
843
+ context "when a :comment is given" do
844
+ let(:opt) { :comment }
845
+ let(:param) { "comment" }
846
+ let(:obj_path) { opt }
847
+
848
+ it_behaves_like "a count option"
849
+ end
850
+
851
+ context "when a :limit is given" do
852
+ let(:opt) { :limit }
853
+ let(:param) { 1 }
854
+
855
+ it_behaves_like "a count option"
856
+ end
857
+
858
+ context "when a :skip is given" do
859
+ let(:opt) { :skip }
860
+ let(:param) { 1 }
861
+
862
+ it_behaves_like "a count option"
863
+ end
864
+
865
+ context "when also including in options" do
866
+
867
+ with_config_values :broken_view_options, true, false do
868
+ it "gives options higher precedence" do
869
+ expect(Mongo::Operation::Count).to receive(:new).once.and_wrap_original do |m, *args|
870
+ opts = args.first.slice(:selector)
871
+ expect(opts.dig(:selector, :limit)).to eq(2)
872
+ m.call(*args)
873
+ end
874
+ view.limit(1).count({ limit: 2 })
875
+ end
876
+ end
877
+ end
878
+ end
606
879
  end
607
880
 
608
881
  describe "#estimated_document_count" do
@@ -627,6 +900,22 @@ describe Mongo::Collection::View::Readable do
627
900
  end
628
901
  end
629
902
 
903
+ context 'when limit passed as an option' do
904
+ it 'raises an error' do
905
+ expect {
906
+ view.estimated_document_count(options.merge(limit: 5))
907
+ }.to raise_error(ArgumentError, "Cannot call estimated_document_count when querying with limit")
908
+ end
909
+ end
910
+
911
+ context 'when skip passed as an option' do
912
+ it 'raises an error' do
913
+ expect {
914
+ view.estimated_document_count(options.merge(skip: 5))
915
+ }.to raise_error(ArgumentError, "Cannot call estimated_document_count when querying with skip")
916
+ end
917
+ end
918
+
630
919
  context 'when collection has documents' do
631
920
  let(:documents) do
632
921
  (1..10).map{ |i| { field: "test#{i}" }}
@@ -669,13 +958,92 @@ describe Mongo::Collection::View::Readable do
669
958
  view.estimated_document_count.should == 0
670
959
  end
671
960
  end
672
- end
673
961
 
674
- describe '#count_documents' do
962
+ context "when using methods to set options" do
675
963
 
676
- let(:result) do
677
- new_view.count_documents(options)
964
+ context "when the broken_view_options flag is on" do
965
+ config_override :broken_view_options, true
966
+
967
+ context "when a :max_time_ms is given" do
968
+ let(:opt) { :max_time_ms }
969
+ let(:param) { 5000 }
970
+
971
+ it "doesn't set the option correctly" do
972
+ expect(Mongo::Operation::Count).to receive(:new).once.and_wrap_original do |m, *args|
973
+ opts = args.first.slice(*args.first.keys - [:session])
974
+ expect(opts.dig(:selector, :maxTimeMS)).to be_nil
975
+ m.call(*args)
976
+ end
977
+ view.send(opt, param).estimated_document_count(options)
978
+ end
979
+ end
980
+
981
+ context "when a :comment is given" do
982
+ let(:opt) { :comment }
983
+ let(:param) { "comment" }
984
+ let(:obj_path) { opt }
985
+
986
+ it "doesn't set the option correctly" do
987
+ expect(Mongo::Operation::Count).to receive(:new).once.and_wrap_original do |m, *args|
988
+ opts = args.first.slice(*args.first.keys - [:session])
989
+ expect(opts[opt]).to be_nil
990
+ m.call(*args)
991
+ end
992
+ view.send(opt, param).estimated_document_count(options)
993
+ end
994
+ end
995
+ end
996
+
997
+ context "when the broken_view_options flag is off" do
998
+ config_override :broken_view_options, false
999
+
1000
+ context "when a :max_time_ms is given" do
1001
+ let(:opt) { :max_time_ms }
1002
+ let(:param) { 5000 }
1003
+
1004
+ it "sets the option correctly" do
1005
+ expect(Mongo::Operation::Count).to receive(:new).once.and_wrap_original do |m, *args|
1006
+ opts = args.first.slice(*args.first.keys - [:session])
1007
+ expect(opts.dig(:selector, :maxTimeMS)).to eq(param)
1008
+ m.call(*args)
1009
+ end
1010
+ view.send(opt, param).estimated_document_count(options)
1011
+ end
1012
+ end
1013
+
1014
+ context "when a :comment is given" do
1015
+ let(:opt) { :comment }
1016
+ let(:param) { "comment" }
1017
+ let(:obj_path) { opt }
1018
+
1019
+ it "sets the option correctly" do
1020
+ expect(Mongo::Operation::Count).to receive(:new).once.and_wrap_original do |m, *args|
1021
+ opts = args.first.slice(*args.first.keys - [:session])
1022
+ expect(opts[opt]).to eq(param)
1023
+ m.call(*args)
1024
+ end
1025
+ view.send(opt, param).estimated_document_count(options)
1026
+ end
1027
+ end
1028
+
1029
+ context "when also including in options" do
1030
+
1031
+ with_config_values :broken_view_options, true, false do
1032
+ it "gives options higher precedence" do
1033
+ expect(Mongo::Operation::Count).to receive(:new).once.and_wrap_original do |m, *args|
1034
+ opts = args.first.slice(:selector)
1035
+ expect(opts.dig(:selector, :maxTimeMS)).to eq(2000)
1036
+ m.call(*args)
1037
+ end
1038
+ view.max_time_ms(1500).estimated_document_count({ max_time_ms: 2000 })
1039
+ end
1040
+ end
1041
+ end
1042
+ end
678
1043
  end
1044
+ end
1045
+
1046
+ describe '#count_documents' do
679
1047
 
680
1048
  context 'when session is given' do
681
1049
  min_server_fcv '3.6'
@@ -704,6 +1072,127 @@ describe Mongo::Collection::View::Readable do
704
1072
  end
705
1073
  end
706
1074
  end
1075
+
1076
+ context "when using methods to set count options" do
1077
+ shared_examples "a count option" do
1078
+ context "when the broken_view_options flag is on" do
1079
+ config_override :broken_view_options, true
1080
+
1081
+ it "doesn't set the option correctly" do
1082
+ expect_any_instance_of(Mongo::Collection::View).to receive(:aggregate).once.and_wrap_original do |m, *args|
1083
+ opts = args[1]
1084
+ expect(opts[opt]).to be_nil
1085
+ m.call(*args)
1086
+ end
1087
+ view.send(opt, param).count_documents(options)
1088
+ end
1089
+ end
1090
+
1091
+ context "when the broken_view_options flag is off" do
1092
+ config_override :broken_view_options, false
1093
+
1094
+ it "sets the option correctly" do
1095
+ expect_any_instance_of(Mongo::Collection::View).to receive(:aggregate).once.and_wrap_original do |m, *args|
1096
+ opts = args[1]
1097
+ expect(opts[opt]).to eq(param)
1098
+ m.call(*args)
1099
+ end
1100
+ view.send(opt, param).count_documents(options)
1101
+ end
1102
+ end
1103
+ end
1104
+
1105
+ context "when a :hint is given" do
1106
+ let(:opt) { :hint }
1107
+ let(:param) { "_id_" }
1108
+
1109
+ it_behaves_like "a count option"
1110
+ end
1111
+
1112
+ context "when a :max_time_ms is given" do
1113
+ let(:opt) { :max_time_ms }
1114
+ let(:param) { 5000 }
1115
+
1116
+ it_behaves_like "a count option"
1117
+ end
1118
+
1119
+ context "when a :comment is given" do
1120
+ let(:opt) { :comment }
1121
+ let(:param) { "comment" }
1122
+
1123
+ it_behaves_like "a count option"
1124
+ end
1125
+
1126
+ context "when a :limit is given" do
1127
+ context "when the broken_view_options flag is false" do
1128
+ config_override :broken_view_options, false
1129
+
1130
+ it "sets the option correctly" do
1131
+ expect_any_instance_of(Mongo::Collection::View).to receive(:aggregate).once.and_wrap_original do |m, *args|
1132
+ pipeline, opts = args
1133
+ expect(pipeline[1][:'$limit']).to eq(1)
1134
+ m.call(*args)
1135
+ end
1136
+ view.limit(1).count_documents(options)
1137
+ end
1138
+ end
1139
+
1140
+ context "when the broken_view_options flag is on" do
1141
+ config_override :broken_view_options, true
1142
+
1143
+ it "doesn't set the option correctly" do
1144
+ expect_any_instance_of(Mongo::Collection::View).to receive(:aggregate).once.and_wrap_original do |m, *args|
1145
+ pipeline, opts = args
1146
+ expect(pipeline[1][:'$limit']).to be_nil
1147
+ m.call(*args)
1148
+ end
1149
+ view.limit(1).count_documents(options)
1150
+ end
1151
+ end
1152
+ end
1153
+
1154
+ context "when a :skip is given" do
1155
+ context "when the broken_view_options flag is on" do
1156
+ config_override :broken_view_options, true
1157
+
1158
+ it "doesn't set the option correctly" do
1159
+ expect_any_instance_of(Mongo::Collection::View).to receive(:aggregate).once.and_wrap_original do |m, *args|
1160
+ pipeline, opts = args
1161
+ expect(pipeline[1][:'$skip']).to be_nil
1162
+ m.call(*args)
1163
+ end
1164
+ view.skip(1).count_documents(options)
1165
+ end
1166
+ end
1167
+
1168
+ context "when the broken_view_options flag is off" do
1169
+ config_override :broken_view_options, false
1170
+
1171
+ it "sets the option correctly" do
1172
+ expect_any_instance_of(Mongo::Collection::View).to receive(:aggregate).once.and_wrap_original do |m, *args|
1173
+ pipeline, opts = args
1174
+ expect(pipeline[1][:'$skip']).to eq(1)
1175
+ m.call(*args)
1176
+ end
1177
+ view.skip(1).count_documents(options)
1178
+ end
1179
+ end
1180
+ end
1181
+
1182
+ context "when also including in options" do
1183
+
1184
+ with_config_values :broken_view_options, true, false do
1185
+ it "gives options higher precedence" do
1186
+ expect_any_instance_of(Mongo::Collection::View).to receive(:aggregate).once.and_wrap_original do |m, *args|
1187
+ pipeline, opts = args
1188
+ expect(pipeline[1][:'$limit']).to eq(2)
1189
+ m.call(*args)
1190
+ end
1191
+ view.limit(1).count_documents({ limit: 2 })
1192
+ end
1193
+ end
1194
+ end
1195
+ end
707
1196
  end
708
1197
 
709
1198
  describe '#distinct' do
@@ -1105,6 +1594,86 @@ describe Mongo::Collection::View::Readable do
1105
1594
  expect(result).to match_array(['bang', 'BANG'])
1106
1595
  end
1107
1596
  end
1597
+
1598
+ context "when using methods to set options" do
1599
+
1600
+ context "when a :max_time_ms is given" do
1601
+ let(:opt) { :max_time_ms }
1602
+ let(:param) { 5000 }
1603
+
1604
+ context "when the broken_view_options flag is on" do
1605
+ config_override :broken_view_options, true
1606
+
1607
+ it "doesn't set the option correctly" do
1608
+ expect(Mongo::Operation::Distinct).to receive(:new).once.and_wrap_original do |m, *args|
1609
+ opts = args.first.slice(*args.first.keys - [:session])
1610
+ expect(opts.dig(:selector, :maxTimeMS)).to be_nil
1611
+ m.call(*args)
1612
+ end
1613
+ view.send(opt, param).distinct(:name, options)
1614
+ end
1615
+ end
1616
+
1617
+ context "when the broken_view_options flag is off" do
1618
+ config_override :broken_view_options, false
1619
+
1620
+ it "sets the option correctly" do
1621
+ expect(Mongo::Operation::Distinct).to receive(:new).once.and_wrap_original do |m, *args|
1622
+ opts = args.first.slice(*args.first.keys - [:session])
1623
+ expect(opts.dig(:selector, :maxTimeMS)).to eq(param)
1624
+ m.call(*args)
1625
+ end
1626
+ view.send(opt, param).distinct(:name, options)
1627
+ end
1628
+ end
1629
+ end
1630
+
1631
+ context "when a :comment is given" do
1632
+ let(:opt) { :comment }
1633
+ let(:param) { "comment" }
1634
+ let(:obj_path) { opt }
1635
+
1636
+ context "when the broken_view_options flag is on" do
1637
+ config_override :broken_view_options, true
1638
+
1639
+ it "doesn't set the option correctly" do
1640
+ expect(Mongo::Operation::Distinct).to receive(:new).once.and_wrap_original do |m, *args|
1641
+ opts = args.first.slice(*args.first.keys - [:session])
1642
+ expect(opts[opt]).to be_nil
1643
+ m.call(*args)
1644
+ end
1645
+ view.send(opt, param).distinct(:name, options)
1646
+ end
1647
+ end
1648
+
1649
+ context "when the broken_view_options flag is off" do
1650
+ config_override :broken_view_options, false
1651
+
1652
+ it "sets the option correctly" do
1653
+ expect(Mongo::Operation::Distinct).to receive(:new).once.and_wrap_original do |m, *args|
1654
+ opts = args.first.slice(*args.first.keys - [:session])
1655
+ expect(opts[opt]).to eq(param)
1656
+ m.call(*args)
1657
+ end
1658
+ view.send(opt, param).distinct(:name, options)
1659
+ end
1660
+ end
1661
+ end
1662
+
1663
+ context "when also including in options" do
1664
+
1665
+ with_config_values :broken_view_options, true, false do
1666
+ it "gives options higher precedence" do
1667
+ expect(Mongo::Operation::Distinct).to receive(:new).once.and_wrap_original do |m, *args|
1668
+ opts = args.first.slice(:selector)
1669
+ expect(opts.dig(:selector, :maxTimeMS)).to eq(2000)
1670
+ m.call(*args)
1671
+ end
1672
+ view.max_time_ms(1500).distinct(:name, { max_time_ms: 2000 })
1673
+ end
1674
+ end
1675
+ end
1676
+ end
1108
1677
  end
1109
1678
 
1110
1679
  describe '#hint' do
@@ -1221,6 +1790,62 @@ describe Mongo::Collection::View::Readable do
1221
1790
  it 'returns a new View' do
1222
1791
  expect(new_view).not_to be(view)
1223
1792
  end
1793
+
1794
+ context 'when sending to server' do
1795
+ let(:subscriber) { Mrss::EventSubscriber.new }
1796
+
1797
+ before do
1798
+ authorized_collection.client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
1799
+ end
1800
+
1801
+ let(:event) do
1802
+ subscriber.single_command_started_event('find')
1803
+ end
1804
+
1805
+ it 'is sent to server' do
1806
+ new_view.to_a
1807
+ event.command.slice('noCursorTimeout').should == {'noCursorTimeout' => true}
1808
+ end
1809
+ end
1810
+
1811
+ context 'integration test' do
1812
+ require_topology :single
1813
+
1814
+ # The number of open cursors with the option set to prevent timeout.
1815
+ def current_no_timeout_count
1816
+ root_authorized_client
1817
+ .command(serverStatus: 1)
1818
+ .documents
1819
+ .first
1820
+ .fetch('metrics')
1821
+ .fetch('cursor')
1822
+ .fetch('open')
1823
+ .fetch('noTimeout')
1824
+ end
1825
+
1826
+ it 'is applied on the server' do
1827
+ # Initialize collection with two documents.
1828
+ new_view.collection.insert_many([{}, {}])
1829
+
1830
+ expect(new_view.count).to be == 2
1831
+
1832
+ # Initial "noTimeout" count should be zero.
1833
+ states = [current_no_timeout_count]
1834
+
1835
+ # The "noTimeout" count should be one while iterating.
1836
+ new_view.batch_size(1).each { states << current_no_timeout_count }
1837
+
1838
+ # Final "noTimeout" count should be back to zero.
1839
+ states << current_no_timeout_count
1840
+
1841
+ # This succeeds on:
1842
+ # commit aab776ebdfb15ddb9765039f7300e15796de0c5c
1843
+ #
1844
+ # This starts failing with [0, 0, 0, 0] from:
1845
+ # commit 2d9f0217ec904a1952a1ada2136502eefbca562e
1846
+ expect(states).to be == [0, 1, 1, 0]
1847
+ end
1848
+ end
1224
1849
  end
1225
1850
 
1226
1851
  describe '#projection' do