mongo 2.20.1 → 2.21.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 (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