mongo 2.20.1 → 2.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (246) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -0
  3. data/Rakefile +2 -2
  4. data/lib/mongo/address.rb +22 -3
  5. data/lib/mongo/auth/aws/credentials_retriever.rb +70 -17
  6. data/lib/mongo/auth/base.rb +1 -1
  7. data/lib/mongo/bulk_write.rb +35 -2
  8. data/lib/mongo/client.rb +38 -6
  9. data/lib/mongo/client_encryption.rb +6 -3
  10. data/lib/mongo/cluster/reapers/cursor_reaper.rb +6 -1
  11. data/lib/mongo/cluster/sdam_flow.rb +20 -7
  12. data/lib/mongo/cluster.rb +14 -4
  13. data/lib/mongo/collection/helpers.rb +1 -1
  14. data/lib/mongo/collection/view/aggregation/behavior.rb +131 -0
  15. data/lib/mongo/collection/view/aggregation.rb +33 -99
  16. data/lib/mongo/collection/view/builder/aggregation.rb +1 -7
  17. data/lib/mongo/collection/view/change_stream.rb +80 -27
  18. data/lib/mongo/collection/view/iterable.rb +76 -60
  19. data/lib/mongo/collection/view/map_reduce.rb +25 -8
  20. data/lib/mongo/collection/view/readable.rb +79 -30
  21. data/lib/mongo/collection/view/writable.rb +109 -48
  22. data/lib/mongo/collection/view.rb +43 -3
  23. data/lib/mongo/collection.rb +158 -23
  24. data/lib/mongo/crypt/auto_encrypter.rb +4 -6
  25. data/lib/mongo/crypt/binding.rb +4 -4
  26. data/lib/mongo/crypt/context.rb +20 -14
  27. data/lib/mongo/crypt/encryption_io.rb +56 -26
  28. data/lib/mongo/crypt/explicit_encrypter.rb +49 -20
  29. data/lib/mongo/crypt/explicit_encryption_context.rb +17 -11
  30. data/lib/mongo/crypt/kms/azure/credentials_retriever.rb +22 -6
  31. data/lib/mongo/crypt/kms/gcp/credentials_retriever.rb +29 -4
  32. data/lib/mongo/csot_timeout_holder.rb +119 -0
  33. data/lib/mongo/cursor/kill_spec.rb +5 -2
  34. data/lib/mongo/cursor/nontailable.rb +27 -0
  35. data/lib/mongo/cursor.rb +86 -24
  36. data/lib/mongo/cursor_host.rb +82 -0
  37. data/lib/mongo/database/view.rb +81 -14
  38. data/lib/mongo/database.rb +88 -18
  39. data/lib/mongo/error/operation_failure.rb +209 -204
  40. data/lib/mongo/error/server_timeout_error.rb +12 -0
  41. data/lib/mongo/error/socket_timeout_error.rb +3 -1
  42. data/lib/mongo/error/timeout_error.rb +23 -0
  43. data/lib/mongo/error.rb +2 -0
  44. data/lib/mongo/grid/fs_bucket.rb +45 -12
  45. data/lib/mongo/grid/stream/read.rb +15 -1
  46. data/lib/mongo/grid/stream/write.rb +21 -4
  47. data/lib/mongo/index/view.rb +77 -16
  48. data/lib/mongo/operation/context.rb +40 -2
  49. data/lib/mongo/operation/create_search_indexes/op_msg.rb +2 -2
  50. data/lib/mongo/operation/delete/op_msg.rb +2 -1
  51. data/lib/mongo/operation/drop_search_index/op_msg.rb +2 -2
  52. data/lib/mongo/operation/find/op_msg.rb +45 -0
  53. data/lib/mongo/operation/get_more/op_msg.rb +33 -0
  54. data/lib/mongo/operation/insert/op_msg.rb +3 -2
  55. data/lib/mongo/operation/insert/result.rb +4 -2
  56. data/lib/mongo/operation/list_collections/result.rb +1 -1
  57. data/lib/mongo/operation/map_reduce/result.rb +1 -1
  58. data/lib/mongo/operation/op_msg_base.rb +3 -1
  59. data/lib/mongo/operation/result.rb +26 -5
  60. data/lib/mongo/operation/shared/executable.rb +12 -1
  61. data/lib/mongo/operation/shared/op_msg_executable.rb +4 -1
  62. data/lib/mongo/operation/shared/response_handling.rb +3 -3
  63. data/lib/mongo/operation/shared/sessions_supported.rb +1 -1
  64. data/lib/mongo/operation/shared/timed.rb +52 -0
  65. data/lib/mongo/operation/shared/write.rb +4 -1
  66. data/lib/mongo/operation/update/op_msg.rb +2 -1
  67. data/lib/mongo/operation/update_search_index/op_msg.rb +2 -2
  68. data/lib/mongo/operation.rb +1 -0
  69. data/lib/mongo/protocol/message.rb +1 -4
  70. data/lib/mongo/protocol/msg.rb +2 -2
  71. data/lib/mongo/retryable/read_worker.rb +69 -29
  72. data/lib/mongo/retryable/write_worker.rb +49 -18
  73. data/lib/mongo/retryable.rb +8 -2
  74. data/lib/mongo/server/connection.rb +11 -5
  75. data/lib/mongo/server/connection_base.rb +22 -2
  76. data/lib/mongo/server/connection_pool.rb +32 -14
  77. data/lib/mongo/server/description/features.rb +1 -1
  78. data/lib/mongo/server/description.rb +18 -5
  79. data/lib/mongo/server/monitor.rb +7 -4
  80. data/lib/mongo/server/pending_connection.rb +7 -3
  81. data/lib/mongo/server/{round_trip_time_averager.rb → round_trip_time_calculator.rb} +25 -7
  82. data/lib/mongo/server.rb +11 -6
  83. data/lib/mongo/server_selector/base.rb +25 -9
  84. data/lib/mongo/session.rb +78 -9
  85. data/lib/mongo/socket/ssl.rb +109 -17
  86. data/lib/mongo/socket/tcp.rb +40 -6
  87. data/lib/mongo/socket.rb +154 -25
  88. data/lib/mongo/uri/options_mapper.rb +1 -0
  89. data/lib/mongo/version.rb +1 -1
  90. data/lib/mongo.rb +1 -0
  91. data/spec/atlas/atlas_connectivity_spec.rb +4 -0
  92. data/spec/atlas/operations_spec.rb +4 -0
  93. data/spec/integration/client_side_encryption/auto_encryption_mongocryptd_spawn_spec.rb +2 -1
  94. data/spec/integration/client_side_encryption/auto_encryption_spec.rb +494 -487
  95. data/spec/integration/client_side_encryption/on_demand_aws_credentials_spec.rb +1 -1
  96. data/spec/integration/client_side_encryption/range_explicit_encryption_prose_spec.rb +66 -22
  97. data/spec/integration/client_side_operations_timeout/encryption_prose_spec.rb +131 -0
  98. data/spec/integration/connection_pool_populator_spec.rb +2 -0
  99. data/spec/integration/cursor_pinning_spec.rb +15 -60
  100. data/spec/integration/cursor_reaping_spec.rb +1 -1
  101. data/spec/integration/docs_examples_spec.rb +1 -1
  102. data/spec/integration/operation_failure_code_spec.rb +1 -1
  103. data/spec/integration/operation_failure_message_spec.rb +3 -3
  104. data/spec/integration/retryable_errors_spec.rb +2 -2
  105. data/spec/integration/sdam_error_handling_spec.rb +2 -1
  106. data/spec/integration/search_indexes_prose_spec.rb +4 -0
  107. data/spec/integration/server_spec.rb +4 -3
  108. data/spec/integration/transactions_api_examples_spec.rb +2 -0
  109. data/spec/kerberos/kerberos_spec.rb +4 -0
  110. data/spec/lite_spec_helper.rb +3 -1
  111. data/spec/mongo/auth/user/view_spec.rb +1 -1
  112. data/spec/mongo/caching_cursor_spec.rb +1 -1
  113. data/spec/mongo/client_encryption_spec.rb +1 -0
  114. data/spec/mongo/client_spec.rb +158 -4
  115. data/spec/mongo/collection/view/aggregation_spec.rb +14 -39
  116. data/spec/mongo/collection/view/change_stream_spec.rb +3 -3
  117. data/spec/mongo/collection_spec.rb +5 -6
  118. data/spec/mongo/crypt/auto_encrypter_spec.rb +14 -12
  119. data/spec/mongo/crypt/data_key_context_spec.rb +3 -1
  120. data/spec/mongo/crypt/explicit_encryption_context_spec.rb +2 -2
  121. data/spec/mongo/crypt/handle_spec.rb +1 -1
  122. data/spec/mongo/cursor_spec.rb +26 -9
  123. data/spec/mongo/error/operation_failure_heavy_spec.rb +2 -2
  124. data/spec/mongo/operation/context_spec.rb +79 -0
  125. data/spec/mongo/operation/create/op_msg_spec.rb +106 -110
  126. data/spec/mongo/operation/delete/op_msg_spec.rb +6 -5
  127. data/spec/mongo/operation/find/op_msg_spec.rb +66 -0
  128. data/spec/mongo/operation/get_more/op_msg_spec.rb +65 -0
  129. data/spec/mongo/operation/insert/op_msg_spec.rb +128 -131
  130. data/spec/mongo/operation/shared/csot/examples.rb +113 -0
  131. data/spec/mongo/query_cache_spec.rb +243 -225
  132. data/spec/mongo/retryable_spec.rb +1 -0
  133. data/spec/mongo/server/round_trip_time_calculator_spec.rb +120 -0
  134. data/spec/mongo/socket/ssl_spec.rb +0 -10
  135. data/spec/runners/change_streams/test.rb +2 -2
  136. data/spec/runners/crud/operation.rb +1 -1
  137. data/spec/runners/crud/verifier.rb +3 -1
  138. data/spec/runners/transactions/operation.rb +4 -6
  139. data/spec/runners/unified/ambiguous_operations.rb +13 -0
  140. data/spec/runners/unified/assertions.rb +4 -0
  141. data/spec/runners/unified/change_stream_operations.rb +14 -24
  142. data/spec/runners/unified/crud_operations.rb +82 -59
  143. data/spec/runners/unified/ddl_operations.rb +38 -7
  144. data/spec/runners/unified/grid_fs_operations.rb +37 -2
  145. data/spec/runners/unified/support_operations.rb +43 -4
  146. data/spec/runners/unified/test.rb +22 -10
  147. data/spec/runners/unified.rb +1 -1
  148. data/spec/solo/clean_exit_spec.rb +2 -0
  149. data/spec/spec_tests/client_side_operations_timeout_spec.rb +15 -0
  150. data/spec/spec_tests/data/change_streams_unified/change-streams-clusterTime.yml +3 -1
  151. data/spec/spec_tests/data/change_streams_unified/change-streams-disambiguatedPaths.yml +3 -1
  152. data/spec/spec_tests/data/change_streams_unified/change-streams-errors.yml +3 -1
  153. data/spec/spec_tests/data/change_streams_unified/change-streams-pre_and_post_images.yml +1 -1
  154. data/spec/spec_tests/data/change_streams_unified/change-streams-resume-allowlist.yml +1 -1
  155. data/spec/spec_tests/data/change_streams_unified/change-streams-resume-errorLabels.yml +1 -1
  156. data/spec/spec_tests/data/change_streams_unified/change-streams-showExpandedEvents.yml +1 -1
  157. data/spec/spec_tests/data/client_side_encryption/badQueries.yml +2 -1
  158. data/spec/spec_tests/data/client_side_encryption/timeoutMS.yml +67 -0
  159. data/spec/spec_tests/data/client_side_operations_timeout/bulkWrite.yml +87 -0
  160. data/spec/spec_tests/data/client_side_operations_timeout/change-streams.yml +358 -0
  161. data/spec/spec_tests/data/client_side_operations_timeout/close-cursors.yml +129 -0
  162. data/spec/spec_tests/data/client_side_operations_timeout/command-execution.yml +250 -0
  163. data/spec/spec_tests/data/client_side_operations_timeout/convenient-transactions.yml +113 -0
  164. data/spec/spec_tests/data/client_side_operations_timeout/cursors.yml +70 -0
  165. data/spec/spec_tests/data/client_side_operations_timeout/deprecated-options.yml +3982 -0
  166. data/spec/spec_tests/data/client_side_operations_timeout/error-transformations.yml +96 -0
  167. data/spec/spec_tests/data/client_side_operations_timeout/global-timeoutMS.yml +3236 -0
  168. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-advanced.yml +207 -0
  169. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-delete.yml +152 -0
  170. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-download.yml +182 -0
  171. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-find.yml +100 -0
  172. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-upload.yml +249 -0
  173. data/spec/spec_tests/data/client_side_operations_timeout/legacy-timeouts.yml +204 -0
  174. data/spec/spec_tests/data/client_side_operations_timeout/non-tailable-cursors.yml +307 -0
  175. data/spec/spec_tests/data/client_side_operations_timeout/override-collection-timeoutMS.yml +1877 -0
  176. data/spec/spec_tests/data/client_side_operations_timeout/override-operation-timeoutMS.yml +1918 -0
  177. data/spec/spec_tests/data/client_side_operations_timeout/retryability-legacy-timeouts.yml +1676 -0
  178. data/spec/spec_tests/data/client_side_operations_timeout/retryability-timeoutMS.yml +2824 -0
  179. data/spec/spec_tests/data/client_side_operations_timeout/sessions-inherit-timeoutMS.yml +168 -0
  180. data/spec/spec_tests/data/client_side_operations_timeout/sessions-override-operation-timeoutMS.yml +171 -0
  181. data/spec/spec_tests/data/client_side_operations_timeout/sessions-override-timeoutMS.yml +168 -0
  182. data/spec/spec_tests/data/client_side_operations_timeout/tailable-awaitData.yml +247 -0
  183. data/spec/spec_tests/data/client_side_operations_timeout/tailable-non-awaitData.yml +181 -0
  184. data/spec/spec_tests/data/crud_unified/aggregate-write-readPreference.yml +4 -0
  185. data/spec/spec_tests/data/crud_unified/db-aggregate-write-readPreference.yml +4 -0
  186. data/spec/spec_tests/data/crud_unified/find-test-all-options.yml +29 -0
  187. data/spec/spec_tests/server_selection_rtt_spec.rb +6 -6
  188. data/spec/support/certificates/atlas-ocsp-ca.crt +81 -83
  189. data/spec/support/certificates/atlas-ocsp.crt +107 -107
  190. data/spec/support/cluster_tools.rb +3 -3
  191. data/spec/support/common_shortcuts.rb +2 -2
  192. data/spec/support/crypt/encrypted_fields/range-encryptedFields-Date.json +1 -1
  193. data/spec/support/crypt/encrypted_fields/range-encryptedFields-DecimalNoPrecision.json +1 -1
  194. data/spec/support/crypt/encrypted_fields/range-encryptedFields-DecimalPrecision.json +1 -1
  195. data/spec/support/crypt/encrypted_fields/range-encryptedFields-DoubleNoPrecision.json +1 -1
  196. data/spec/support/crypt/encrypted_fields/range-encryptedFields-DoublePrecision.json +1 -1
  197. data/spec/support/crypt/encrypted_fields/range-encryptedFields-Int.json +1 -1
  198. data/spec/support/crypt/encrypted_fields/range-encryptedFields-Long.json +1 -1
  199. data/spec/support/shared/session.rb +2 -2
  200. data/spec/support/spec_setup.rb +2 -2
  201. data/spec/support/utils.rb +3 -1
  202. metadata +78 -91
  203. data/spec/mongo/server/round_trip_time_averager_spec.rb +0 -48
  204. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Aggregate.yml +0 -242
  205. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Correctness.yml +0 -423
  206. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Delete.yml +0 -183
  207. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-FindOneAndUpdate.yml +0 -240
  208. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-InsertFind.yml +0 -236
  209. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Update.yml +0 -253
  210. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Aggregate.yml +0 -1688
  211. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Correctness.yml +0 -294
  212. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Delete.yml +0 -906
  213. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-FindOneAndUpdate.yml +0 -1685
  214. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-InsertFind.yml +0 -1681
  215. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Update.yml +0 -1698
  216. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Aggregate.yml +0 -330
  217. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Correctness.yml +0 -425
  218. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Delete.yml +0 -227
  219. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.yml +0 -328
  220. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-InsertFind.yml +0 -320
  221. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Update.yml +0 -337
  222. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Aggregate.yml +0 -914
  223. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Correctness.yml +0 -293
  224. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Delete.yml +0 -519
  225. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-FindOneAndUpdate.yml +0 -912
  226. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-InsertFind.yml +0 -908
  227. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Update.yml +0 -925
  228. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Aggregate.yml +0 -326
  229. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Correctness.yml +0 -425
  230. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Delete.yml +0 -225
  231. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-FindOneAndUpdate.yml +0 -324
  232. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-InsertFind.yml +0 -320
  233. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Update.yml +0 -339
  234. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Aggregate.yml +0 -242
  235. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Correctness.yml +0 -424
  236. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Delete.yml +0 -183
  237. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-FindOneAndUpdate.yml +0 -240
  238. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-InsertFind.yml +0 -236
  239. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Update.yml +0 -255
  240. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Aggregate.yml +0 -242
  241. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Correctness.yml +0 -423
  242. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Delete.yml +0 -183
  243. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-FindOneAndUpdate.yml +0 -240
  244. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-InsertFind.yml +0 -236
  245. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Update.yml +0 -255
  246. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-WrongType.yml +0 -44
@@ -561,6 +561,75 @@ describe Mongo::Client do
561
561
  expect(command['comment']).to eq('comment')
562
562
  end
563
563
  end
564
+
565
+ context 'with timeout_ms' do
566
+ # To make it easier with failCommand
567
+ require_topology :single
568
+ min_server_version '4.4'
569
+
570
+ before do
571
+ root_authorized_client.use('admin').command({
572
+ configureFailPoint: "failCommand",
573
+ mode: "alwaysOn",
574
+ data: {
575
+ failCommands: ["listDatabases"],
576
+ blockConnection: true,
577
+ blockTimeMS: 100
578
+ }
579
+ })
580
+ end
581
+
582
+ after do
583
+ root_authorized_client.use('admin').command({
584
+ configureFailPoint: "failCommand",
585
+ mode: "off"
586
+ })
587
+ end
588
+
589
+ context 'when timeout_ms is set on command level' do
590
+ context 'when there is not enough time' do
591
+ it 'raises' do
592
+ expect do
593
+ monitored_client.database_names({}, timeout_ms: 50)
594
+ end.to raise_error(Mongo::Error::TimeoutError)
595
+ end
596
+ end
597
+
598
+ context 'when there is enough time' do
599
+ it 'does not raise' do
600
+ expect do
601
+ monitored_client.database_names({}, timeout_ms: 200)
602
+ end.not_to raise_error
603
+ end
604
+ end
605
+ end
606
+
607
+ context 'when timeout_ms is set on client level' do
608
+ context 'when there is not enough time' do
609
+ let(:client) do
610
+ root_authorized_client.with(timeout_ms: 50)
611
+ end
612
+
613
+ it 'raises' do
614
+ expect do
615
+ client.database_names({})
616
+ end.to raise_error(Mongo::Error::TimeoutError)
617
+ end
618
+ end
619
+
620
+ context 'when there is enough time' do
621
+ let(:client) do
622
+ root_authorized_client.with(timeout_ms: 200)
623
+ end
624
+
625
+ it 'does not raise' do
626
+ expect do
627
+ monitored_client.database_names({})
628
+ end.not_to raise_error
629
+ end
630
+ end
631
+ end
632
+ end
564
633
  end
565
634
 
566
635
  describe '#list_databases' do
@@ -572,8 +641,6 @@ describe Mongo::Client do
572
641
  end
573
642
 
574
643
  context 'when filter criteria is present' do
575
- min_server_fcv '3.6'
576
-
577
644
  include_context 'ensure test db exists'
578
645
 
579
646
  let(:result) do
@@ -591,8 +658,6 @@ describe Mongo::Client do
591
658
  end
592
659
 
593
660
  context 'when name_only is true' do
594
- min_server_fcv '3.6'
595
-
596
661
  let(:command) do
597
662
  Utils.get_command_event(root_authorized_client, 'listDatabases') do |client|
598
663
  client.list_databases({}, true)
@@ -667,6 +732,75 @@ describe Mongo::Client do
667
732
  expect(command['comment']).to eq('comment')
668
733
  end
669
734
  end
735
+
736
+ context 'with timeout_ms' do
737
+ # To make it easier with failCommand
738
+ require_topology :single
739
+ min_server_version '4.4'
740
+
741
+ before do
742
+ root_authorized_client.use('admin').command({
743
+ configureFailPoint: "failCommand",
744
+ mode: "alwaysOn",
745
+ data: {
746
+ failCommands: ["listDatabases"],
747
+ blockConnection: true,
748
+ blockTimeMS: 100
749
+ }
750
+ })
751
+ end
752
+
753
+ after do
754
+ root_authorized_client.use('admin').command({
755
+ configureFailPoint: "failCommand",
756
+ mode: "off"
757
+ })
758
+ end
759
+
760
+ context 'when timeout_ms is set on command level' do
761
+ context 'when there is not enough time' do
762
+ it 'raises' do
763
+ expect do
764
+ monitored_client.list_databases({}, false, timeout_ms: 50)
765
+ end.to raise_error(Mongo::Error::TimeoutError)
766
+ end
767
+ end
768
+
769
+ context 'when there is enough time' do
770
+ it 'does not raise' do
771
+ expect do
772
+ monitored_client.list_databases({}, false, timeout_ms: 200)
773
+ end.not_to raise_error
774
+ end
775
+ end
776
+ end
777
+
778
+ context 'when timeout_ms is set on client level' do
779
+ context 'when there is not enough time' do
780
+ let(:client) do
781
+ root_authorized_client.with(timeout_ms: 50)
782
+ end
783
+
784
+ it 'raises' do
785
+ expect do
786
+ client.list_databases({})
787
+ end.to raise_error(Mongo::Error::TimeoutError)
788
+ end
789
+ end
790
+
791
+ context 'when there is enough time' do
792
+ let(:client) do
793
+ root_authorized_client.with(timeout_ms: 200)
794
+ end
795
+
796
+ it 'does not raise' do
797
+ expect do
798
+ monitored_client.list_databases({})
799
+ end.not_to raise_error
800
+ end
801
+ end
802
+ end
803
+ end
670
804
  end
671
805
 
672
806
  describe '#list_mongo_databases' do
@@ -1156,6 +1290,26 @@ describe Mongo::Client do
1156
1290
  }.to raise_exception(Mongo::Error::InvalidSession)
1157
1291
  end
1158
1292
  end
1293
+
1294
+ context 'when CSOT is set on the client' do
1295
+ require_topology :replica_set
1296
+
1297
+ let(:timeout_ms) { 10 }
1298
+
1299
+ let(:timeout_sec) { timeout_ms / 1_000.0 }
1300
+
1301
+ let(:client) do
1302
+ authorized_client.with(timeout_ms: timeout_ms)
1303
+ end
1304
+
1305
+ it 'uses CSOT timeout set on the client' do
1306
+ expect_any_instance_of(Mongo::ServerSelector::PrimaryPreferred).to(
1307
+ receive(:select_server).with(anything, {timeout: timeout_sec}).and_call_original
1308
+ )
1309
+
1310
+ client.start_session
1311
+ end
1312
+ end
1159
1313
  end
1160
1314
 
1161
1315
  describe '#summary' do
@@ -156,8 +156,6 @@ describe Mongo::Collection::View::Aggregation do
156
156
  end
157
157
 
158
158
  context 'when the initial response has no results but an active cursor' do
159
- min_server_fcv '3.2'
160
-
161
159
  let(:documents) do
162
160
  [
163
161
  { city: 'a'*6000000 },
@@ -166,7 +164,7 @@ describe Mongo::Collection::View::Aggregation do
166
164
  end
167
165
 
168
166
  let(:options) do
169
- { :use_cursor => true }
167
+ {}
170
168
  end
171
169
 
172
170
  let(:pipeline) do
@@ -486,48 +484,25 @@ describe Mongo::Collection::View::Aggregation do
486
484
  end
487
485
  end
488
486
 
489
- context 'when use_cursor is set' do
490
-
491
- context 'when use_cursor is true' do
492
-
493
- context 'when batch_size is set' do
494
-
495
- let(:options) do
496
- { :use_cursor => true,
497
- :batch_size => 10
498
- }
499
- end
500
-
501
- it 'sets a batch size document in the spec' do
502
- expect(aggregation_spec[:selector][:cursor][:batchSize]).to eq(options[:batch_size])
503
- end
504
- end
505
-
506
- context 'when batch_size is not set' do
507
-
508
- let(:options) do
509
- { :use_cursor => true }
510
- end
487
+ context 'when batch_size is set' do
511
488
 
512
- it 'sets an empty document in the spec' do
513
- expect(aggregation_spec[:selector][:cursor]).to eq({})
514
- end
515
- end
489
+ let(:options) do
490
+ { :batch_size => 10 }
491
+ end
516
492
 
493
+ it 'sets a batch size document in the spec' do
494
+ expect(aggregation_spec[:selector][:cursor][:batchSize]).to eq(options[:batch_size])
517
495
  end
496
+ end
518
497
 
519
- context 'when use_cursor is false' do
498
+ context 'when batch_size is not set' do
520
499
 
521
- let(:options) do
522
- { :use_cursor => false }
523
- end
524
-
525
- context 'when batch_size is set' do
500
+ let(:options) do
501
+ {}
502
+ end
526
503
 
527
- it 'does not set the cursor option in the spec' do
528
- expect(aggregation_spec[:selector][:cursor]).to be_nil
529
- end
530
- end
504
+ it 'sets an empty document in the spec' do
505
+ expect(aggregation_spec[:selector][:cursor]).to eq({})
531
506
  end
532
507
  end
533
508
  end
@@ -507,7 +507,7 @@ describe Mongo::Collection::View::ChangeStream do
507
507
  end
508
508
 
509
509
  it 'includes the max_await_time value in the formatted string' do
510
- expect(change_stream.inspect).to include({ max_await_time_ms: 10 }.to_s)
510
+ expect(change_stream.inspect).to include({ 'max_await_time_ms' => 10 }.to_s)
511
511
  end
512
512
  end
513
513
 
@@ -518,7 +518,7 @@ describe Mongo::Collection::View::ChangeStream do
518
518
  end
519
519
 
520
520
  it 'includes the batch_size value in the formatted string' do
521
- expect(change_stream.inspect).to include({ batch_size: 5 }.to_s)
521
+ expect(change_stream.inspect).to include({ 'batch_size' => 5 }.to_s)
522
522
  end
523
523
  end
524
524
 
@@ -529,7 +529,7 @@ describe Mongo::Collection::View::ChangeStream do
529
529
  end
530
530
 
531
531
  it 'includes the collation value in the formatted string' do
532
- expect(change_stream.inspect).to include({ 'collation' => { locale: 'en_US', strength: 2 } }.to_s)
532
+ expect(change_stream.inspect).to include({ 'collation' => { 'locale' => 'en_US', 'strength' => 2 } }.to_s)
533
533
  end
534
534
  end
535
535
 
@@ -828,13 +828,12 @@ describe Mongo::Collection do
828
828
 
829
829
  let(:enum) { change_stream.to_enum }
830
830
 
831
+ let(:get_more) { subscriber.started_events.detect { |e| e.command['getMore'] }.command }
832
+
831
833
  it 'sets the option correctly' do
832
- expect(change_stream.instance_variable_get(:@cursor)).to receive(:get_more_operation).once.and_wrap_original do |m, *args, &block|
833
- m.call(*args).tap do |op|
834
- expect(op.max_time_ms).to eq(3000)
835
- end
836
- end
837
- enum.next
834
+ enum.try_next
835
+ expect(get_more).not_to be_nil
836
+ expect(get_more['maxTimeMS']).to be == 3000
838
837
  end
839
838
 
840
839
  it "waits the appropriate amount of time" do
@@ -58,6 +58,8 @@ describe Mongo::Crypt::AutoEncrypter do
58
58
  )
59
59
  end
60
60
 
61
+ let(:operation_context) { Mongo::Operation::Context.new }
62
+
61
63
  shared_context 'with jsonSchema validator' do
62
64
  before do
63
65
  users_collection = client.use(db_name)[collection_name]
@@ -81,14 +83,14 @@ describe Mongo::Crypt::AutoEncrypter do
81
83
  shared_examples 'a functioning auto encrypter' do
82
84
  describe '#encrypt' do
83
85
  it 'replaces the ssn field with a BSON::Binary' do
84
- result = auto_encrypter.encrypt(db_name, command)
86
+ result = auto_encrypter.encrypt(db_name, command, operation_context)
85
87
  expect(result).to eq(encrypted_command)
86
88
  end
87
89
  end
88
90
 
89
91
  describe '#decrypt' do
90
92
  it 'returns the unencrypted document' do
91
- result = auto_encrypter.decrypt(encrypted_command)
93
+ result = auto_encrypter.decrypt(encrypted_command, operation_context)
92
94
  expect(result).to eq(command)
93
95
  end
94
96
  end
@@ -329,14 +331,14 @@ describe Mongo::Crypt::AutoEncrypter do
329
331
 
330
332
  describe '#encrypt' do
331
333
  it 'does not perform encryption' do
332
- result = auto_encrypter.encrypt(db_name, command)
334
+ result = auto_encrypter.encrypt(db_name, command, operation_context)
333
335
  expect(result).to eq(command)
334
336
  end
335
337
  end
336
338
 
337
339
  describe '#decrypt' do
338
340
  it 'still performs decryption' do
339
- result = auto_encrypter.decrypt(encrypted_command)
341
+ result = auto_encrypter.decrypt(encrypted_command, operation_context)
340
342
  expect(result).to eq(command)
341
343
  end
342
344
  end
@@ -347,14 +349,14 @@ describe Mongo::Crypt::AutoEncrypter do
347
349
 
348
350
  describe '#encrypt' do
349
351
  it 'does not perform encryption' do
350
- result = auto_encrypter.encrypt(db_name, command)
352
+ result = auto_encrypter.encrypt(db_name, command, operation_context)
351
353
  expect(result).to eq(command)
352
354
  end
353
355
  end
354
356
 
355
357
  describe '#decrypt' do
356
358
  it 'still performs decryption' do
357
- result = auto_encrypter.decrypt(encrypted_command)
359
+ result = auto_encrypter.decrypt(encrypted_command, operation_context)
358
360
  expect(result).to eq(command)
359
361
  end
360
362
  end
@@ -365,14 +367,14 @@ describe Mongo::Crypt::AutoEncrypter do
365
367
 
366
368
  describe '#encrypt' do
367
369
  it 'does not perform encryption' do
368
- result = auto_encrypter.encrypt(db_name, command)
370
+ result = auto_encrypter.encrypt(db_name, command, operation_context)
369
371
  expect(result).to eq(command)
370
372
  end
371
373
  end
372
374
 
373
375
  describe '#decrypt' do
374
376
  it 'still performs decryption' do
375
- result = auto_encrypter.decrypt(encrypted_command)
377
+ result = auto_encrypter.decrypt(encrypted_command, operation_context)
376
378
  expect(result).to eq(command)
377
379
  end
378
380
  end
@@ -383,14 +385,14 @@ describe Mongo::Crypt::AutoEncrypter do
383
385
 
384
386
  describe '#encrypt' do
385
387
  it 'does not perform encryption' do
386
- result = auto_encrypter.encrypt(db_name, command)
388
+ result = auto_encrypter.encrypt(db_name, command, operation_context)
387
389
  expect(result).to eq(command)
388
390
  end
389
391
  end
390
392
 
391
393
  describe '#decrypt' do
392
394
  it 'still performs decryption' do
393
- result = auto_encrypter.decrypt(encrypted_command)
395
+ result = auto_encrypter.decrypt(encrypted_command, operation_context)
394
396
  expect(result).to eq(command)
395
397
  end
396
398
  end
@@ -401,14 +403,14 @@ describe Mongo::Crypt::AutoEncrypter do
401
403
 
402
404
  describe '#encrypt' do
403
405
  it 'does not perform encryption' do
404
- result = auto_encrypter.encrypt(db_name, command)
406
+ result = auto_encrypter.encrypt(db_name, command, operation_context)
405
407
  expect(result).to eq(command)
406
408
  end
407
409
  end
408
410
 
409
411
  describe '#decrypt' do
410
412
  it 'still performs decryption' do
411
- result = auto_encrypter.decrypt(encrypted_command)
413
+ result = auto_encrypter.decrypt(encrypted_command, operation_context)
412
414
  expect(result).to eq(command)
413
415
  end
414
416
  end
@@ -136,8 +136,10 @@ describe Mongo::Crypt::DataKeyContext do
136
136
  )
137
137
  end
138
138
 
139
+ let(:operation_context) { Mongo::Operation::Context.new }
140
+
139
141
  it 'creates a data key' do
140
- expect(context.run_state_machine).to be_a_kind_of(Hash)
142
+ expect(context.run_state_machine(operation_context)).to be_a_kind_of(Hash)
141
143
  end
142
144
  end
143
145
  end
@@ -139,7 +139,7 @@ describe Mongo::Crypt::ExplicitEncryptionContext do
139
139
  value,
140
140
  options.merge(query_type: "equality")
141
141
  )
142
- end.to raise_error(ArgumentError, /query_type is allowed only for "Indexed" or "RangePreview" algorithm/)
142
+ end.to raise_error(ArgumentError, /query_type is allowed only for "Indexed" or "Range" algorithm/)
143
143
  end
144
144
  end
145
145
 
@@ -154,7 +154,7 @@ describe Mongo::Crypt::ExplicitEncryptionContext do
154
154
  value,
155
155
  options.merge(contention_factor: 10)
156
156
  )
157
- end.to raise_error(ArgumentError, /contention_factor is allowed only for "Indexed" or "RangePreview" algorithm/)
157
+ end.to raise_error(ArgumentError, /contention_factor is allowed only for "Indexed" or "Range" algorithm/)
158
158
  end
159
159
  end
160
160
 
@@ -188,7 +188,7 @@ describe Mongo::Crypt::Handle do
188
188
  end
189
189
 
190
190
  it 'raises an exception' do
191
- expect { handle }.to raise_error(Mongo::Error::CryptError, 'local key must be 96 bytes (libmongocrypt error code 1)')
191
+ expect { handle }.to raise_error(Mongo::Error::CryptError, /local key must be 96 bytes \(libmongocrypt error code 1\)/)
192
192
  end
193
193
  end
194
194
 
@@ -8,6 +8,10 @@ describe Mongo::Cursor do
8
8
  authorized_client['cursor_spec_collection']
9
9
  end
10
10
 
11
+ let(:context) do
12
+ Mongo::Operation::Context.new(client: authorized_client)
13
+ end
14
+
11
15
  before do
12
16
  authorized_collection.drop
13
17
  end
@@ -18,7 +22,7 @@ describe Mongo::Cursor do
18
22
  end
19
23
 
20
24
  let(:reply) do
21
- view.send(:send_initial_query, server)
25
+ view.send(:send_initial_query, server, context)
22
26
  end
23
27
 
24
28
  let(:cursor) do
@@ -118,7 +122,7 @@ describe Mongo::Cursor do
118
122
  end
119
123
 
120
124
  let(:reply) do
121
- view.send(:send_initial_query, server)
125
+ view.send(:send_initial_query, server, context)
122
126
  end
123
127
 
124
128
  let(:cursor) do
@@ -170,7 +174,11 @@ describe Mongo::Cursor do
170
174
 
171
175
  before do
172
176
  expect(cursor).to receive(:get_more_operation).and_return(op).ordered
173
- expect(op).to receive(:execute).and_raise(Mongo::Error::SocketError).ordered
177
+ if SpecConfig.instance.connect_options[:connect] == :load_balanced
178
+ expect(op).to receive(:execute_with_connection).and_raise(Mongo::Error::SocketError).ordered
179
+ else
180
+ expect(op).to receive(:execute).and_raise(Mongo::Error::SocketError).ordered
181
+ end
174
182
  end
175
183
 
176
184
  it 'raises the error' do
@@ -617,6 +625,9 @@ describe Mongo::Cursor do
617
625
  allow(reply).to receive(:connection_description).and_return(conn_desc)
618
626
  allow(reply).to receive(:cursor_id).and_return(42)
619
627
  allow(reply).to receive(:connection_global_id).and_return(1)
628
+ if SpecConfig.instance.connect_options[:connect] == :load_balanced
629
+ allow(reply).to receive(:connection).and_return(nil)
630
+ end
620
631
  end
621
632
  end
622
633
 
@@ -645,7 +656,7 @@ describe Mongo::Cursor do
645
656
  end
646
657
 
647
658
  let(:reply) do
648
- view.send(:send_initial_query, authorized_primary)
659
+ view.send(:send_initial_query, authorized_primary, context)
649
660
  end
650
661
 
651
662
  let(:cursor) do
@@ -721,7 +732,7 @@ describe Mongo::Cursor do
721
732
  end
722
733
 
723
734
  let(:reply) do
724
- view.send(:send_initial_query, server)
735
+ view.send(:send_initial_query, server, context)
725
736
  end
726
737
 
727
738
  let(:cursor) do
@@ -770,10 +781,16 @@ describe Mongo::Cursor do
770
781
 
771
782
  it 'does not raise an error' do
772
783
  cursor
773
- server.with_connection do |conn|
774
- expect(conn).to receive(:deliver)
775
- .at_least(:once)
776
- .and_raise(Mongo::Error::SocketError, "test error")
784
+ if SpecConfig.instance.connect_options[:connect] == :load_balanced
785
+ expect(cursor.connection).to receive(:deliver)
786
+ .at_least(:once)
787
+ .and_raise(Mongo::Error::SocketError, "test error")
788
+ else
789
+ server.with_connection do |conn|
790
+ expect(conn).to receive(:deliver)
791
+ .at_least(:once)
792
+ .and_raise(Mongo::Error::SocketError, "test error")
793
+ end
777
794
  end
778
795
  expect do
779
796
  cursor.close
@@ -39,7 +39,7 @@ describe Mongo::Error::OperationFailure do
39
39
 
40
40
  begin
41
41
  authorized_client['foo'].insert_one(test: 1)
42
- rescue Mongo::Error::OperationFailure => exc
42
+ rescue Mongo::Error::OperationFailure::Family => exc
43
43
  expect(exc.details).to eq(exc.document['writeConcernError']['errInfo'])
44
44
  expect(exc.server_message).to eq(exc.document['writeConcernError']['errmsg'])
45
45
  expect(exc.code).to eq(exc.document['writeConcernError']['code'])
@@ -90,7 +90,7 @@ describe Mongo::Error::OperationFailure do
90
90
  it 'succeeds and prints the error' do
91
91
  begin
92
92
  collection.insert_one({x: 1})
93
- rescue Mongo::Error::OperationFailure => e
93
+ rescue Mongo::Error::OperationFailure::Family => e
94
94
  insert_events = subscriber.succeeded_events.select { |e| e.command_name == "insert" }
95
95
  expect(insert_events.length).to eq 1
96
96
  expect(e.message).to match(/\[#{e.code}(:.*)?\].+ -- .+/)
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lite_spec_helper'
4
+
5
+ describe Mongo::Operation::Context do
6
+ describe '#initialize' do
7
+ context 'when timeout_ms is negative' do
8
+ it 'raises an error' do
9
+ expect do
10
+ described_class.new(operation_timeouts: { operation_timeout_ms: -1 })
11
+ end.to raise_error ArgumentError, /must be a non-negative integer/
12
+ end
13
+ end
14
+ end
15
+
16
+ describe '#deadline' do
17
+ let(:context) { described_class.new(operation_timeouts: { operation_timeout_ms: timeout_ms }) }
18
+
19
+ context 'when timeout_ms is nil' do
20
+ let(:timeout_ms) { nil }
21
+
22
+ it 'returns nil' do
23
+ expect(context.deadline).to be_nil
24
+ end
25
+ end
26
+
27
+ context 'when timeout_ms is zero' do
28
+ let(:timeout_ms) { 0 }
29
+
30
+ it 'returns nil' do
31
+ expect(context.deadline).to eq(0)
32
+ end
33
+ end
34
+
35
+ context 'when timeout_ms is positive' do
36
+ before do
37
+ allow(Mongo::Utils).to receive(:monotonic_time).and_return(100.0)
38
+ end
39
+
40
+ let(:timeout_ms) { 10_000 }
41
+
42
+ it 'calculates the deadline' do
43
+ expect(context.deadline).to eq(110)
44
+ end
45
+ end
46
+ end
47
+
48
+ describe '#remaining_timeout_ms' do
49
+ let(:context) { described_class.new(operation_timeouts: { operation_timeout_ms: timeout_ms }) }
50
+
51
+ context 'when timeout_ms is nil' do
52
+ let(:timeout_ms) { nil }
53
+
54
+ it 'returns nil' do
55
+ expect(context.remaining_timeout_ms).to be_nil
56
+ end
57
+ end
58
+
59
+ context 'when timeout_ms is zero' do
60
+ let(:timeout_ms) { 0 }
61
+
62
+ it 'returns nil' do
63
+ expect(context.remaining_timeout_ms).to be_nil
64
+ end
65
+ end
66
+
67
+ context 'when timeout_ms is positive' do
68
+ before do
69
+ allow(Mongo::Utils).to receive(:monotonic_time).and_return(100.0, 105.0)
70
+ end
71
+
72
+ let(:timeout_ms) { 10_000 }
73
+
74
+ it 'calculates the remaining time' do
75
+ expect(context.remaining_timeout_ms).to eq(5_000)
76
+ end
77
+ end
78
+ end
79
+ end