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
@@ -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