mongo 2.19.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 (356) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +40 -1
  3. data/Rakefile +83 -174
  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/topology/base.rb +16 -0
  13. data/lib/mongo/cluster.rb +41 -5
  14. data/lib/mongo/collection/helpers.rb +1 -1
  15. data/lib/mongo/collection/view/aggregation/behavior.rb +131 -0
  16. data/lib/mongo/collection/view/aggregation.rb +33 -99
  17. data/lib/mongo/collection/view/builder/aggregation.rb +1 -7
  18. data/lib/mongo/collection/view/change_stream.rb +80 -27
  19. data/lib/mongo/collection/view/iterable.rb +92 -60
  20. data/lib/mongo/collection/view/map_reduce.rb +25 -8
  21. data/lib/mongo/collection/view/readable.rb +79 -30
  22. data/lib/mongo/collection/view/writable.rb +109 -48
  23. data/lib/mongo/collection/view.rb +44 -3
  24. data/lib/mongo/collection.rb +185 -26
  25. data/lib/mongo/config.rb +2 -2
  26. data/lib/mongo/crypt/auto_encrypter.rb +4 -6
  27. data/lib/mongo/crypt/binding.rb +4 -4
  28. data/lib/mongo/crypt/context.rb +20 -14
  29. data/lib/mongo/crypt/encryption_io.rb +56 -26
  30. data/lib/mongo/crypt/explicit_encrypter.rb +49 -20
  31. data/lib/mongo/crypt/explicit_encryption_context.rb +17 -11
  32. data/lib/mongo/crypt/kms/azure/credentials_retriever.rb +22 -6
  33. data/lib/mongo/crypt/kms/gcp/credentials_retriever.rb +29 -4
  34. data/lib/mongo/csot_timeout_holder.rb +119 -0
  35. data/lib/mongo/cursor/kill_spec.rb +5 -2
  36. data/lib/mongo/cursor/nontailable.rb +27 -0
  37. data/lib/mongo/cursor.rb +86 -24
  38. data/lib/mongo/cursor_host.rb +82 -0
  39. data/lib/mongo/database/view.rb +81 -14
  40. data/lib/mongo/database.rb +88 -18
  41. data/lib/mongo/error/operation_failure.rb +209 -204
  42. data/lib/mongo/error/server_timeout_error.rb +12 -0
  43. data/lib/mongo/error/socket_timeout_error.rb +3 -1
  44. data/lib/mongo/error/timeout_error.rb +23 -0
  45. data/lib/mongo/error/transactions_not_supported.rb +34 -0
  46. data/lib/mongo/error.rb +3 -0
  47. data/lib/mongo/grid/fs_bucket.rb +48 -9
  48. data/lib/mongo/grid/stream/read.rb +15 -1
  49. data/lib/mongo/grid/stream/write.rb +21 -4
  50. data/lib/mongo/index/view.rb +77 -16
  51. data/lib/mongo/monitoring/event/secure.rb +1 -1
  52. data/lib/mongo/operation/context.rb +40 -2
  53. data/lib/mongo/operation/create_search_indexes/op_msg.rb +31 -0
  54. data/lib/mongo/operation/create_search_indexes.rb +15 -0
  55. data/lib/mongo/operation/delete/op_msg.rb +2 -1
  56. data/lib/mongo/operation/drop_search_index/op_msg.rb +33 -0
  57. data/lib/mongo/operation/drop_search_index.rb +15 -0
  58. data/lib/mongo/operation/find/op_msg.rb +45 -0
  59. data/lib/mongo/operation/get_more/op_msg.rb +33 -0
  60. data/lib/mongo/operation/insert/op_msg.rb +3 -2
  61. data/lib/mongo/operation/insert/result.rb +4 -2
  62. data/lib/mongo/operation/list_collections/result.rb +1 -1
  63. data/lib/mongo/operation/map_reduce/result.rb +1 -1
  64. data/lib/mongo/operation/op_msg_base.rb +3 -1
  65. data/lib/mongo/operation/result.rb +26 -5
  66. data/lib/mongo/operation/shared/executable.rb +55 -28
  67. data/lib/mongo/operation/shared/op_msg_executable.rb +4 -1
  68. data/lib/mongo/operation/shared/response_handling.rb +25 -27
  69. data/lib/mongo/operation/shared/sessions_supported.rb +1 -1
  70. data/lib/mongo/operation/shared/specifiable.rb +7 -0
  71. data/lib/mongo/operation/shared/timed.rb +52 -0
  72. data/lib/mongo/operation/shared/write.rb +4 -1
  73. data/lib/mongo/operation/update/op_msg.rb +2 -1
  74. data/lib/mongo/operation/update_search_index/op_msg.rb +34 -0
  75. data/lib/mongo/operation/update_search_index.rb +15 -0
  76. data/lib/mongo/operation.rb +4 -0
  77. data/lib/mongo/protocol/message.rb +1 -4
  78. data/lib/mongo/protocol/msg.rb +2 -2
  79. data/lib/mongo/retryable/base_worker.rb +28 -3
  80. data/lib/mongo/retryable/read_worker.rb +78 -36
  81. data/lib/mongo/retryable/write_worker.rb +59 -25
  82. data/lib/mongo/retryable.rb +8 -2
  83. data/lib/mongo/search_index/view.rb +232 -0
  84. data/lib/mongo/server/app_metadata/environment.rb +64 -9
  85. data/lib/mongo/server/app_metadata.rb +5 -4
  86. data/lib/mongo/server/connection.rb +11 -5
  87. data/lib/mongo/server/connection_base.rb +22 -2
  88. data/lib/mongo/server/connection_pool.rb +32 -14
  89. data/lib/mongo/server/description/features.rb +2 -1
  90. data/lib/mongo/server/description.rb +18 -5
  91. data/lib/mongo/server/monitor.rb +7 -4
  92. data/lib/mongo/server/pending_connection.rb +25 -8
  93. data/lib/mongo/server/{round_trip_time_averager.rb → round_trip_time_calculator.rb} +25 -7
  94. data/lib/mongo/server.rb +11 -6
  95. data/lib/mongo/server_selector/base.rb +54 -12
  96. data/lib/mongo/session/server_session/dirtyable.rb +52 -0
  97. data/lib/mongo/session/server_session.rb +3 -0
  98. data/lib/mongo/session/session_pool.rb +12 -18
  99. data/lib/mongo/session.rb +110 -9
  100. data/lib/mongo/socket/ssl.rb +131 -18
  101. data/lib/mongo/socket/tcp.rb +40 -6
  102. data/lib/mongo/socket.rb +154 -25
  103. data/lib/mongo/uri/options_mapper.rb +1 -0
  104. data/lib/mongo/uri.rb +0 -4
  105. data/lib/mongo/version.rb +1 -5
  106. data/lib/mongo.rb +2 -0
  107. data/mongo.gemspec +9 -18
  108. data/spec/atlas/atlas_connectivity_spec.rb +9 -9
  109. data/spec/atlas/operations_spec.rb +5 -5
  110. data/spec/faas/ruby-sam-app/Gemfile +9 -0
  111. data/spec/faas/ruby-sam-app/mongodb/Gemfile +4 -0
  112. data/spec/faas/ruby-sam-app/mongodb/app.rb +149 -0
  113. data/spec/faas/ruby-sam-app/template.yaml +48 -0
  114. data/spec/integration/client_side_encryption/auto_encryption_mongocryptd_spawn_spec.rb +2 -1
  115. data/spec/integration/client_side_encryption/auto_encryption_spec.rb +494 -487
  116. data/spec/integration/client_side_encryption/corpus_spec.rb +10 -2
  117. data/spec/integration/client_side_encryption/on_demand_aws_credentials_spec.rb +1 -1
  118. data/spec/integration/client_side_encryption/range_explicit_encryption_prose_spec.rb +67 -20
  119. data/spec/integration/client_side_operations_timeout/encryption_prose_spec.rb +131 -0
  120. data/spec/integration/connection_pool_populator_spec.rb +2 -0
  121. data/spec/integration/cursor_pinning_spec.rb +15 -60
  122. data/spec/integration/cursor_reaping_spec.rb +1 -1
  123. data/spec/integration/docs_examples_spec.rb +1 -1
  124. data/spec/integration/find_options_spec.rb +227 -0
  125. data/spec/integration/operation_failure_code_spec.rb +1 -1
  126. data/spec/integration/operation_failure_message_spec.rb +3 -3
  127. data/spec/integration/retryable_errors_spec.rb +2 -2
  128. data/spec/integration/retryable_reads_errors_spec.rb +196 -31
  129. data/spec/integration/retryable_writes_errors_spec.rb +156 -0
  130. data/spec/integration/sdam_error_handling_spec.rb +4 -1
  131. data/spec/integration/search_indexes_prose_spec.rb +172 -0
  132. data/spec/integration/server_spec.rb +4 -3
  133. data/spec/integration/transactions_api_examples_spec.rb +2 -0
  134. data/spec/kerberos/kerberos_spec.rb +4 -0
  135. data/spec/lite_spec_helper.rb +34 -20
  136. data/spec/mongo/auth/user/view_spec.rb +1 -1
  137. data/spec/mongo/caching_cursor_spec.rb +1 -1
  138. data/spec/mongo/client_encryption_spec.rb +1 -0
  139. data/spec/mongo/client_spec.rb +158 -4
  140. data/spec/mongo/cluster_spec.rb +36 -0
  141. data/spec/mongo/collection/view/aggregation_spec.rb +20 -40
  142. data/spec/mongo/collection/view/change_stream_spec.rb +3 -3
  143. data/spec/mongo/collection/view/explainable_spec.rb +2 -0
  144. data/spec/mongo/collection_crud_spec.rb +2 -1
  145. data/spec/mongo/collection_spec.rb +5 -6
  146. data/spec/mongo/crypt/auto_encrypter_spec.rb +14 -12
  147. data/spec/mongo/crypt/data_key_context_spec.rb +3 -1
  148. data/spec/mongo/crypt/explicit_encryption_context_spec.rb +2 -2
  149. data/spec/mongo/crypt/handle_spec.rb +1 -1
  150. data/spec/mongo/cursor_spec.rb +26 -9
  151. data/spec/mongo/error/operation_failure_heavy_spec.rb +2 -2
  152. data/spec/mongo/operation/context_spec.rb +79 -0
  153. data/spec/mongo/operation/create/op_msg_spec.rb +106 -110
  154. data/spec/mongo/operation/delete/op_msg_spec.rb +6 -5
  155. data/spec/mongo/operation/find/op_msg_spec.rb +66 -0
  156. data/spec/mongo/operation/get_more/op_msg_spec.rb +65 -0
  157. data/spec/mongo/operation/insert/op_msg_spec.rb +128 -131
  158. data/spec/mongo/operation/insert_spec.rb +1 -1
  159. data/spec/mongo/operation/shared/csot/examples.rb +113 -0
  160. data/spec/mongo/query_cache_spec.rb +243 -225
  161. data/spec/mongo/retryable/write_worker_spec.rb +39 -0
  162. data/spec/mongo/retryable_spec.rb +1 -0
  163. data/spec/mongo/server/app_metadata/environment_spec.rb +135 -0
  164. data/spec/mongo/server/app_metadata_spec.rb +12 -2
  165. data/spec/mongo/server/connection_spec.rb +26 -0
  166. data/spec/mongo/server/round_trip_time_calculator_spec.rb +120 -0
  167. data/spec/mongo/session/session_pool_spec.rb +1 -16
  168. data/spec/mongo/session_transaction_spec.rb +15 -0
  169. data/spec/mongo/socket/ssl_spec.rb +0 -10
  170. data/spec/mongo/uri_spec.rb +0 -9
  171. data/spec/runners/change_streams/test.rb +2 -2
  172. data/spec/runners/crud/operation.rb +1 -1
  173. data/spec/runners/crud/test.rb +0 -8
  174. data/spec/runners/crud/verifier.rb +3 -1
  175. data/spec/runners/crud.rb +1 -1
  176. data/spec/runners/transactions/operation.rb +4 -6
  177. data/spec/runners/transactions/test.rb +12 -3
  178. data/spec/runners/unified/ambiguous_operations.rb +13 -0
  179. data/spec/runners/unified/assertions.rb +20 -3
  180. data/spec/runners/unified/change_stream_operations.rb +14 -24
  181. data/spec/runners/unified/crud_operations.rb +82 -47
  182. data/spec/runners/unified/ddl_operations.rb +38 -7
  183. data/spec/runners/unified/grid_fs_operations.rb +37 -2
  184. data/spec/runners/unified/search_index_operations.rb +63 -0
  185. data/spec/runners/unified/support_operations.rb +46 -9
  186. data/spec/runners/unified/test.rb +33 -12
  187. data/spec/runners/unified.rb +1 -1
  188. data/spec/solo/clean_exit_spec.rb +2 -0
  189. data/spec/spec_helper.rb +1 -1
  190. data/spec/spec_tests/client_side_operations_timeout_spec.rb +15 -0
  191. data/spec/spec_tests/data/change_streams_unified/change-streams-clusterTime.yml +3 -1
  192. data/spec/spec_tests/data/change_streams_unified/change-streams-disambiguatedPaths.yml +3 -1
  193. data/spec/spec_tests/data/change_streams_unified/change-streams-errors.yml +3 -1
  194. data/spec/spec_tests/data/change_streams_unified/change-streams-pre_and_post_images.yml +1 -1
  195. data/spec/spec_tests/data/change_streams_unified/change-streams-resume-allowlist.yml +1 -1
  196. data/spec/spec_tests/data/change_streams_unified/change-streams-resume-errorLabels.yml +1 -1
  197. data/spec/spec_tests/data/change_streams_unified/change-streams-showExpandedEvents.yml +1 -1
  198. data/spec/spec_tests/data/client_side_encryption/badQueries.yml +2 -1
  199. data/spec/spec_tests/data/client_side_encryption/explain.yml +2 -2
  200. data/spec/spec_tests/data/client_side_encryption/fle2v2-BypassQueryAnalysis.yml +1 -0
  201. data/spec/spec_tests/data/client_side_encryption/fle2v2-Compact.yml +1 -0
  202. data/spec/spec_tests/data/client_side_encryption/fle2v2-CreateCollection.yml +1 -0
  203. data/spec/spec_tests/data/client_side_encryption/fle2v2-DecryptExistingData.yml +1 -0
  204. data/spec/spec_tests/data/client_side_encryption/fle2v2-Delete.yml +1 -0
  205. data/spec/spec_tests/data/client_side_encryption/fle2v2-EncryptedFields-vs-EncryptedFieldsMap.yml +1 -0
  206. data/spec/spec_tests/data/client_side_encryption/fle2v2-EncryptedFields-vs-jsonSchema.yml +1 -0
  207. data/spec/spec_tests/data/client_side_encryption/fle2v2-EncryptedFieldsMap-defaults.yml +1 -0
  208. data/spec/spec_tests/data/client_side_encryption/fle2v2-FindOneAndUpdate.yml +1 -0
  209. data/spec/spec_tests/data/client_side_encryption/fle2v2-InsertFind-Indexed.yml +1 -0
  210. data/spec/spec_tests/data/client_side_encryption/fle2v2-InsertFind-Unindexed.yml +1 -0
  211. data/spec/spec_tests/data/client_side_encryption/fle2v2-MissingKey.yml +1 -0
  212. data/spec/spec_tests/data/client_side_encryption/fle2v2-NoEncryption.yml +1 -0
  213. data/spec/spec_tests/data/client_side_encryption/fle2v2-Update.yml +1 -0
  214. data/spec/spec_tests/data/client_side_encryption/fle2v2-validatorAndPartialFieldExpression.yml +2 -1
  215. data/spec/spec_tests/data/client_side_encryption/timeoutMS.yml +67 -0
  216. data/spec/spec_tests/data/client_side_operations_timeout/bulkWrite.yml +87 -0
  217. data/spec/spec_tests/data/client_side_operations_timeout/change-streams.yml +358 -0
  218. data/spec/spec_tests/data/client_side_operations_timeout/close-cursors.yml +129 -0
  219. data/spec/spec_tests/data/client_side_operations_timeout/command-execution.yml +250 -0
  220. data/spec/spec_tests/data/client_side_operations_timeout/convenient-transactions.yml +113 -0
  221. data/spec/spec_tests/data/client_side_operations_timeout/cursors.yml +70 -0
  222. data/spec/spec_tests/data/client_side_operations_timeout/deprecated-options.yml +3982 -0
  223. data/spec/spec_tests/data/client_side_operations_timeout/error-transformations.yml +96 -0
  224. data/spec/spec_tests/data/client_side_operations_timeout/global-timeoutMS.yml +3236 -0
  225. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-advanced.yml +207 -0
  226. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-delete.yml +152 -0
  227. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-download.yml +182 -0
  228. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-find.yml +100 -0
  229. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-upload.yml +249 -0
  230. data/spec/spec_tests/data/client_side_operations_timeout/legacy-timeouts.yml +204 -0
  231. data/spec/spec_tests/data/client_side_operations_timeout/non-tailable-cursors.yml +307 -0
  232. data/spec/spec_tests/data/client_side_operations_timeout/override-collection-timeoutMS.yml +1877 -0
  233. data/spec/spec_tests/data/client_side_operations_timeout/override-operation-timeoutMS.yml +1918 -0
  234. data/spec/spec_tests/data/client_side_operations_timeout/retryability-legacy-timeouts.yml +1676 -0
  235. data/spec/spec_tests/data/client_side_operations_timeout/retryability-timeoutMS.yml +2824 -0
  236. data/spec/spec_tests/data/client_side_operations_timeout/sessions-inherit-timeoutMS.yml +168 -0
  237. data/spec/spec_tests/data/client_side_operations_timeout/sessions-override-operation-timeoutMS.yml +171 -0
  238. data/spec/spec_tests/data/client_side_operations_timeout/sessions-override-timeoutMS.yml +168 -0
  239. data/spec/spec_tests/data/client_side_operations_timeout/tailable-awaitData.yml +247 -0
  240. data/spec/spec_tests/data/client_side_operations_timeout/tailable-non-awaitData.yml +181 -0
  241. data/spec/spec_tests/data/connection_string/invalid-uris.yml +0 -10
  242. data/spec/spec_tests/data/connection_string/valid-options.yml +13 -0
  243. data/spec/spec_tests/data/crud_unified/aggregate-write-readPreference.yml +6 -0
  244. data/spec/spec_tests/data/crud_unified/db-aggregate-write-readPreference.yml +6 -0
  245. data/spec/spec_tests/data/crud_unified/find-test-all-options.yml +377 -0
  246. data/spec/spec_tests/data/index_management/createSearchIndex.yml +64 -0
  247. data/spec/spec_tests/data/index_management/createSearchIndexes.yml +86 -0
  248. data/spec/spec_tests/data/index_management/dropSearchIndex.yml +43 -0
  249. data/spec/spec_tests/data/index_management/listSearchIndexes.yml +91 -0
  250. data/spec/spec_tests/data/index_management/updateSearchIndex.yml +46 -0
  251. data/spec/spec_tests/data/retryable_writes/unified/bulkWrite-serverErrors.yml +3 -6
  252. data/spec/spec_tests/data/retryable_writes/unified/insertOne-serverErrors.yml +3 -6
  253. data/spec/spec_tests/data/run_command_unified/runCommand.yml +319 -0
  254. data/spec/spec_tests/data/sessions_unified/driver-sessions-dirty-session-errors.yml +351 -0
  255. data/spec/spec_tests/data/unified/valid-pass/poc-crud.yml +1 -1
  256. data/spec/spec_tests/data/unified/valid-pass/poc-retryable-writes.yml +7 -7
  257. data/spec/spec_tests/data/unified/valid-pass/poc-sessions.yml +3 -4
  258. data/spec/spec_tests/data/unified/valid-pass/poc-transactions-convenient-api.yml +1 -1
  259. data/spec/spec_tests/data/unified/valid-pass/poc-transactions-mongos-pin-auto.yml +1 -1
  260. data/spec/spec_tests/data/unified/valid-pass/poc-transactions.yml +3 -3
  261. data/spec/spec_tests/index_management_unified_spec.rb +13 -0
  262. data/spec/spec_tests/run_command_unified_spec.rb +13 -0
  263. data/spec/spec_tests/sdam_unified_spec.rb +2 -0
  264. data/spec/spec_tests/server_selection_rtt_spec.rb +6 -6
  265. data/spec/spec_tests/transactions_unified_spec.rb +2 -1
  266. data/spec/support/certificates/atlas-ocsp-ca.crt +89 -79
  267. data/spec/support/certificates/atlas-ocsp.crt +117 -122
  268. data/spec/support/certificates/retrieve-atlas-cert +1 -1
  269. data/spec/support/cluster_tools.rb +3 -3
  270. data/spec/support/common_shortcuts.rb +2 -2
  271. data/spec/support/constraints.rb +6 -0
  272. data/spec/support/crypt/encrypted_fields/range-encryptedFields-Date.json +1 -1
  273. data/spec/support/crypt/encrypted_fields/range-encryptedFields-DecimalNoPrecision.json +1 -1
  274. data/spec/support/crypt/encrypted_fields/range-encryptedFields-DecimalPrecision.json +1 -1
  275. data/spec/support/crypt/encrypted_fields/range-encryptedFields-DoubleNoPrecision.json +1 -1
  276. data/spec/support/crypt/encrypted_fields/range-encryptedFields-DoublePrecision.json +1 -1
  277. data/spec/support/crypt/encrypted_fields/range-encryptedFields-Int.json +1 -1
  278. data/spec/support/crypt/encrypted_fields/range-encryptedFields-Long.json +1 -1
  279. data/spec/support/ocsp +1 -1
  280. data/spec/support/recording_logger.rb +27 -0
  281. data/spec/support/shared/session.rb +2 -2
  282. data/spec/support/spec_config.rb +5 -0
  283. data/spec/support/spec_setup.rb +2 -2
  284. data/spec/support/utils.rb +3 -1
  285. metadata +1329 -1368
  286. checksums.yaml.gz.sig +0 -0
  287. data/spec/mongo/server/round_trip_time_averager_spec.rb +0 -48
  288. data/spec/shared/LICENSE +0 -20
  289. data/spec/shared/bin/get-mongodb-download-url +0 -17
  290. data/spec/shared/bin/s3-copy +0 -45
  291. data/spec/shared/bin/s3-upload +0 -69
  292. data/spec/shared/lib/mrss/child_process_helper.rb +0 -80
  293. data/spec/shared/lib/mrss/cluster_config.rb +0 -231
  294. data/spec/shared/lib/mrss/constraints.rb +0 -378
  295. data/spec/shared/lib/mrss/docker_runner.rb +0 -295
  296. data/spec/shared/lib/mrss/eg_config_utils.rb +0 -51
  297. data/spec/shared/lib/mrss/event_subscriber.rb +0 -210
  298. data/spec/shared/lib/mrss/lite_constraints.rb +0 -238
  299. data/spec/shared/lib/mrss/server_version_registry.rb +0 -113
  300. data/spec/shared/lib/mrss/session_registry.rb +0 -69
  301. data/spec/shared/lib/mrss/session_registry_legacy.rb +0 -60
  302. data/spec/shared/lib/mrss/spec_organizer.rb +0 -179
  303. data/spec/shared/lib/mrss/utils.rb +0 -37
  304. data/spec/shared/share/Dockerfile.erb +0 -330
  305. data/spec/shared/share/haproxy-1.conf +0 -16
  306. data/spec/shared/share/haproxy-2.conf +0 -17
  307. data/spec/shared/shlib/config.sh +0 -27
  308. data/spec/shared/shlib/distro.sh +0 -74
  309. data/spec/shared/shlib/server.sh +0 -416
  310. data/spec/shared/shlib/set_env.sh +0 -169
  311. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Aggregate.yml +0 -241
  312. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Correctness.yml +0 -422
  313. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Delete.yml +0 -182
  314. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-FindOneAndUpdate.yml +0 -239
  315. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-InsertFind.yml +0 -235
  316. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Update.yml +0 -252
  317. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Aggregate.yml +0 -1687
  318. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Correctness.yml +0 -293
  319. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Delete.yml +0 -905
  320. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-FindOneAndUpdate.yml +0 -1684
  321. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-InsertFind.yml +0 -1680
  322. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Update.yml +0 -1697
  323. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Aggregate.yml +0 -329
  324. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Correctness.yml +0 -424
  325. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Delete.yml +0 -226
  326. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.yml +0 -327
  327. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-InsertFind.yml +0 -319
  328. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Update.yml +0 -336
  329. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Aggregate.yml +0 -913
  330. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Correctness.yml +0 -292
  331. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Delete.yml +0 -518
  332. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-FindOneAndUpdate.yml +0 -911
  333. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-InsertFind.yml +0 -907
  334. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Update.yml +0 -924
  335. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Aggregate.yml +0 -325
  336. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Correctness.yml +0 -424
  337. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Delete.yml +0 -224
  338. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-FindOneAndUpdate.yml +0 -323
  339. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-InsertFind.yml +0 -319
  340. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Update.yml +0 -338
  341. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Aggregate.yml +0 -241
  342. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Correctness.yml +0 -423
  343. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Delete.yml +0 -182
  344. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-FindOneAndUpdate.yml +0 -239
  345. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-InsertFind.yml +0 -235
  346. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Update.yml +0 -254
  347. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Aggregate.yml +0 -241
  348. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Correctness.yml +0 -422
  349. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Delete.yml +0 -182
  350. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-FindOneAndUpdate.yml +0 -239
  351. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-InsertFind.yml +0 -235
  352. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Update.yml +0 -254
  353. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-WrongType.yml +0 -43
  354. data/spec/spec_tests/data/cmap/pool-clear-interrupt-immediately.yml +0 -49
  355. data.tar.gz.sig +0 -0
  356. metadata.gz.sig +0 -2
@@ -0,0 +1,227 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'Find operation options' do
6
+ require_mri
7
+ require_no_auth
8
+ min_server_fcv '4.4'
9
+
10
+ let(:subscriber) { Mrss::EventSubscriber.new }
11
+
12
+ let(:seeds) do
13
+ [ SpecConfig.instance.addresses.first ]
14
+ end
15
+
16
+ let(:client_options) do
17
+ {}
18
+ end
19
+
20
+ let(:collection_options) do
21
+ {}
22
+ end
23
+
24
+ let(:client) do
25
+ ClientRegistry.instance.new_local_client(
26
+ seeds,
27
+ SpecConfig.instance.test_options
28
+ .merge(database: SpecConfig.instance.test_db)
29
+ .merge(client_options)
30
+ ).tap do |client|
31
+ client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
32
+ end
33
+ end
34
+
35
+ let(:collection) do
36
+ client['find_options', collection_options]
37
+ end
38
+
39
+ let(:find_command) do
40
+ subscriber.started_events.find { |cmd| cmd.command_name == 'find' }
41
+ end
42
+
43
+ let(:should_create_collection) { true }
44
+
45
+ before do
46
+ client['find_options'].drop
47
+ collection.create if should_create_collection
48
+ collection.insert_many([ { a: 1 }, { a: 2 }, { a: 3 } ])
49
+ end
50
+
51
+ describe 'collation' do
52
+ let(:client_options) do
53
+ {}
54
+ end
55
+
56
+ let(:collation) do
57
+ { 'locale' => 'en_US' }
58
+ end
59
+
60
+ context 'when defined on the collection' do
61
+ let(:collection_options) do
62
+ { collation: collation }
63
+ end
64
+
65
+ it 'uses the collation defined on the collection' do
66
+ collection.find.to_a
67
+ expect(find_command.command['collation']).to be_nil
68
+ end
69
+ end
70
+
71
+ context 'when defined on the operation' do
72
+ let(:collection_options) do
73
+ {}
74
+ end
75
+
76
+ it 'uses the collation defined on the collection' do
77
+ collection.find({}, collation: collation).to_a
78
+ expect(find_command.command['collation']).to eq(collation)
79
+ end
80
+ end
81
+
82
+ context 'when defined on both collection and operation' do
83
+ let(:collection_options) do
84
+ { 'locale' => 'de_AT' }
85
+ end
86
+
87
+ let(:should_create_collection) { false }
88
+
89
+ it 'uses the collation defined on the collection' do
90
+ collection.find({}, collation: collation).to_a
91
+ expect(find_command.command['collation']).to eq(collation)
92
+ end
93
+ end
94
+ end
95
+
96
+ describe 'read concern' do
97
+ context 'when defined on the client' do
98
+ let(:client_options) do
99
+ { read_concern: { level: :local } }
100
+ end
101
+
102
+ let(:collection_options) do
103
+ {}
104
+ end
105
+
106
+ it 'uses the read concern defined on the client' do
107
+ collection.find.to_a
108
+ expect(find_command.command['readConcern']).to eq('level' => 'local')
109
+ end
110
+
111
+ context 'when defined on the collection' do
112
+ let(:collection_options) do
113
+ { read_concern: { level: :majority } }
114
+ end
115
+
116
+ it 'uses the read concern defined on the collection' do
117
+ collection.find.to_a
118
+ expect(find_command.command['readConcern']).to eq('level' => 'majority')
119
+ end
120
+
121
+ context 'when defined on the operation' do
122
+ let(:operation_read_concern) do
123
+ { level: :available }
124
+ end
125
+
126
+ it 'uses the read concern defined on the operation' do
127
+ collection.find({}, read_concern: operation_read_concern).to_a
128
+ expect(find_command.command['readConcern']).to eq('level' => 'available')
129
+ end
130
+ end
131
+ end
132
+
133
+ context 'when defined on the operation' do
134
+ let(:collection_options) do
135
+ {}
136
+ end
137
+
138
+ let(:operation_read_concern) do
139
+ { level: :available }
140
+ end
141
+
142
+ it 'uses the read concern defined on the operation' do
143
+ collection.find({}, read_concern: operation_read_concern).to_a
144
+ expect(find_command.command['readConcern']).to eq('level' => 'available')
145
+ end
146
+ end
147
+ end
148
+
149
+ context 'when defined on the collection' do
150
+ let(:client_options) do
151
+ {}
152
+ end
153
+
154
+ let(:collection_options) do
155
+ { read_concern: { level: :majority } }
156
+ end
157
+
158
+ it 'uses the read concern defined on the collection' do
159
+ collection.find.to_a
160
+ expect(find_command.command['readConcern']).to eq('level' => 'majority')
161
+ end
162
+
163
+ context 'when defined on the operation' do
164
+ let(:operation_read_concern) do
165
+ { level: :available }
166
+ end
167
+
168
+ it 'uses the read concern defined on the operation' do
169
+ collection.find({}, read_concern: operation_read_concern).to_a
170
+ expect(find_command.command['readConcern']).to eq('level' => 'available')
171
+ end
172
+ end
173
+ end
174
+ end
175
+
176
+ describe 'read preference' do
177
+ require_topology :replica_set
178
+
179
+ context 'when defined on the client' do
180
+ let(:client_options) do
181
+ { read: { mode: :secondary } }
182
+ end
183
+
184
+ let(:collection_options) do
185
+ {}
186
+ end
187
+
188
+ it 'uses the read preference defined on the client' do
189
+ collection.find.to_a
190
+ expect(find_command.command['$readPreference']).to eq('mode' => 'secondary')
191
+ end
192
+
193
+ context 'when defined on the collection' do
194
+ let(:collection_options) do
195
+ { read: { mode: :secondary_preferred } }
196
+ end
197
+
198
+ it 'uses the read concern defined on the collection' do
199
+ collection.find.to_a
200
+ expect(find_command.command['$readPreference']).to eq('mode' => 'secondaryPreferred')
201
+ end
202
+ end
203
+ end
204
+ end
205
+
206
+ describe 'cursor type' do
207
+ let(:collection_options) do
208
+ { capped: true, size: 1000 }
209
+ end
210
+
211
+ context 'when cursor type is :tailable' do
212
+ it 'sets the cursor type to tailable' do
213
+ collection.find({}, cursor_type: :tailable).first
214
+ expect(find_command.command['tailable']).to be true
215
+ expect(find_command.command['awaitData']).to be_falsey
216
+ end
217
+ end
218
+
219
+ context 'when cursor type is :tailable_await' do
220
+ it 'sets the cursor type to tailable' do
221
+ collection.find({}, cursor_type: :tailable_await).first
222
+ expect(find_command.command['tailable']).to be true
223
+ expect(find_command.command['awaitData']).to be true
224
+ end
225
+ end
226
+ end
227
+ end
@@ -17,7 +17,7 @@ describe 'OperationFailure code' do
17
17
  collection.insert_one(_id: 1)
18
18
  collection.insert_one(_id: 1)
19
19
  fail('Should have raised')
20
- rescue Mongo::Error::OperationFailure => e
20
+ rescue Mongo::Error::OperationFailure::Family => e
21
21
  expect(e.code).to eq(11000)
22
22
  # 4.0 and 4.2 sharded clusters set code name.
23
23
  # 4.0 and 4.2 replica sets and standalones do not,
@@ -22,7 +22,7 @@ describe 'OperationFailure message' do
22
22
  begin
23
23
  client.command(bogus_command: nil)
24
24
  fail('Should have raised')
25
- rescue Mongo::Error::OperationFailure => e
25
+ rescue Mongo::Error::OperationFailure::Family => e
26
26
  e.code_name.should == 'CommandNotFound'
27
27
  e.message.should =~ %r,\A\[59:CommandNotFound\]: no such (?:command|cmd): '?bogus_command'?,
28
28
  end
@@ -36,7 +36,7 @@ describe 'OperationFailure message' do
36
36
  begin
37
37
  client.command(bogus_command: nil)
38
38
  fail('Should have raised')
39
- rescue Mongo::Error::OperationFailure => e
39
+ rescue Mongo::Error::OperationFailure::Family => e
40
40
  e.code_name.should be nil
41
41
  e.message.should =~ %r,\A\[59\]: no such (?:command|cmd): '?bogus_command'?,
42
42
  end
@@ -53,7 +53,7 @@ describe 'OperationFailure message' do
53
53
  collection.insert_one(_id: 1)
54
54
  collection.insert_one(_id: 1)
55
55
  fail('Should have raised')
56
- rescue Mongo::Error::OperationFailure => e
56
+ rescue Mongo::Error::OperationFailure::Family => e
57
57
  e.code_name.should be nil
58
58
  e.message.should =~ %r,\A\[11000\]: (?:insertDocument :: caused by :: 11000 )?E11000 duplicate key error (?:collection|index):,
59
59
  end
@@ -83,7 +83,7 @@ describe 'Failing retryable operations' do
83
83
 
84
84
  begin
85
85
  collection.find(a: 1).to_a
86
- rescue Mongo::Error::OperationFailure => exception
86
+ rescue Mongo::Error::OperationFailure::Family => exception
87
87
  else
88
88
  fail('Expected operation to fail')
89
89
  end
@@ -128,7 +128,7 @@ describe 'Failing retryable operations' do
128
128
 
129
129
  begin
130
130
  collection.insert_one(a: 1)
131
- rescue Mongo::Error::OperationFailure => exception
131
+ rescue Mongo::Error::OperationFailure::Family => exception
132
132
  else
133
133
  fail('Expected operation to fail')
134
134
  end
@@ -4,6 +4,7 @@
4
4
  require 'spec_helper'
5
5
 
6
6
  describe 'Retryable reads errors tests' do
7
+ retry_test
7
8
 
8
9
  let(:client) { authorized_client.with(options.merge(retry_reads: true)) }
9
10
 
@@ -20,14 +21,14 @@ describe 'Retryable reads errors tests' do
20
21
 
21
22
  let(:failpoint) do
22
23
  {
23
- configureFailPoint: "failCommand",
24
- mode: { times: 1 },
25
- data: {
26
- failCommands: [ "find" ],
27
- errorCode: 91,
28
- blockConnection: true,
29
- blockTimeMS: 1000
30
- }
24
+ configureFailPoint: "failCommand",
25
+ mode: { times: 1 },
26
+ data: {
27
+ failCommands: [ "find" ],
28
+ errorCode: 91,
29
+ blockConnection: true,
30
+ blockTimeMS: 1000
31
+ }
31
32
  }
32
33
  end
33
34
 
@@ -73,31 +74,42 @@ describe 'Retryable reads errors tests' do
73
74
  client.subscribe(Mongo::Monitoring::CONNECTION_POOL, subscriber)
74
75
  end
75
76
 
76
- it "retries on PoolClearedError" do
77
- # After the first find fails, the pool is paused and retry is triggered.
78
- # Now, a race is started between the second find acquiring a connection,
79
- # and the first retrying the read. Now, retry reads cause the cluster to
80
- # be rescanned and the pool to be unpaused, allowing the second checkout
81
- # to succeed (when it should fail). Therefore we want the second find's
82
- # check out to win the race. This gives the check out a little head start.
83
- allow_any_instance_of(Mongo::Server::ConnectionPool).to receive(:ready).and_wrap_original do |m, *args, &block|
84
- ::Utils.wait_for_condition(5) do
85
- # check_out_results should contain:
86
- # - find1 connection check out successful
87
- # - pool cleared
88
- # - find2 connection check out failed
89
- # We wait here for the third event to happen before we ready the pool.
90
- cmap_events.select do |e|
91
- event_types.include?(e.class)
92
- end.length >= 3
77
+ shared_examples_for 'retries on PoolClearedError' do
78
+ it "retries on PoolClearedError" do
79
+ # After the first find fails, the pool is paused and retry is triggered.
80
+ # Now, a race is started between the second find acquiring a connection,
81
+ # and the first retrying the read. Now, retry reads cause the cluster to
82
+ # be rescanned and the pool to be unpaused, allowing the second checkout
83
+ # to succeed (when it should fail). Therefore we want the second find's
84
+ # check out to win the race. This gives the check out a little head start.
85
+ allow_any_instance_of(Mongo::Server::ConnectionPool).to receive(:ready).and_wrap_original do |m, *args, &block|
86
+ ::Utils.wait_for_condition(5) do
87
+ # check_out_results should contain:
88
+ # - find1 connection check out successful
89
+ # - pool cleared
90
+ # - find2 connection check out failed
91
+ # We wait here for the third event to happen before we ready the pool.
92
+ cmap_events.select do |e|
93
+ event_types.include?(e.class)
94
+ end.length >= 3
95
+ end
96
+ m.call(*args, &block)
93
97
  end
94
- m.call(*args, &block)
98
+ threads.map(&:join)
99
+ expect(check_out_results[0]).to be_a(Mongo::Monitoring::Event::Cmap::ConnectionCheckedOut)
100
+ expect(check_out_results[1]).to be_a(Mongo::Monitoring::Event::Cmap::PoolCleared)
101
+ expect(check_out_results[2]).to be_a(Mongo::Monitoring::Event::Cmap::ConnectionCheckOutFailed)
102
+ expect(find_events.length).to eq(3)
95
103
  end
96
- threads.map(&:join)
97
- expect(check_out_results[0]).to be_a(Mongo::Monitoring::Event::Cmap::ConnectionCheckedOut)
98
- expect(check_out_results[1]).to be_a(Mongo::Monitoring::Event::Cmap::PoolCleared)
99
- expect(check_out_results[2]).to be_a(Mongo::Monitoring::Event::Cmap::ConnectionCheckOutFailed)
100
- expect(find_events.length).to eq(3)
104
+ end
105
+
106
+ it_behaves_like 'retries on PoolClearedError'
107
+
108
+ context 'legacy read retries' do
109
+
110
+ let(:client) { authorized_client.with(options.merge(retry_reads: false, max_read_retries: 1)) }
111
+
112
+ it_behaves_like 'retries on PoolClearedError'
101
113
  end
102
114
 
103
115
  after do
@@ -107,4 +119,157 @@ describe 'Retryable reads errors tests' do
107
119
  })
108
120
  end
109
121
  end
122
+
123
+ context 'Retries in a sharded cluster' do
124
+ require_topology :sharded
125
+ min_server_version '4.2'
126
+ require_no_auth
127
+
128
+ let(:subscriber) { Mrss::EventSubscriber.new }
129
+
130
+ let(:find_started_events) do
131
+ subscriber.started_events.select { |e| e.command_name == "find" }
132
+ end
133
+
134
+ let(:find_failed_events) do
135
+ subscriber.failed_events.select { |e| e.command_name == "find" }
136
+ end
137
+
138
+ let(:find_succeeded_events) do
139
+ subscriber.succeeded_events.select { |e| e.command_name == "find" }
140
+ end
141
+
142
+ context 'when another mongos is available' do
143
+
144
+ let(:first_mongos) do
145
+ Mongo::Client.new(
146
+ [SpecConfig.instance.addresses.first],
147
+ direct_connection: true,
148
+ database: 'admin'
149
+ )
150
+ end
151
+
152
+ let(:second_mongos) do
153
+ Mongo::Client.new(
154
+ [SpecConfig.instance.addresses.last],
155
+ direct_connection: false,
156
+ database: 'admin'
157
+ )
158
+ end
159
+
160
+ let(:client) do
161
+ new_local_client(
162
+ [
163
+ SpecConfig.instance.addresses.first,
164
+ SpecConfig.instance.addresses.last,
165
+ ],
166
+ SpecConfig.instance.test_options.merge(retry_reads: true)
167
+ )
168
+ end
169
+
170
+ let(:expected_servers) do
171
+ [
172
+ SpecConfig.instance.addresses.first.to_s,
173
+ SpecConfig.instance.addresses.last.to_s
174
+ ].sort
175
+ end
176
+
177
+ before do
178
+ skip 'This test requires at least two mongos' if SpecConfig.instance.addresses.length < 2
179
+
180
+ first_mongos.database.command(
181
+ configureFailPoint: 'failCommand',
182
+ mode: { times: 1 },
183
+ data: {
184
+ failCommands: %w(find),
185
+ closeConnection: false,
186
+ errorCode: 6
187
+ }
188
+ )
189
+
190
+ second_mongos.database.command(
191
+ configureFailPoint: 'failCommand',
192
+ mode: { times: 1 },
193
+ data: {
194
+ failCommands: %w(find),
195
+ closeConnection: false,
196
+ errorCode: 6
197
+ }
198
+ )
199
+ end
200
+
201
+ after do
202
+ [first_mongos, second_mongos].each do |admin_client|
203
+ admin_client.database.command(
204
+ configureFailPoint: 'failCommand',
205
+ mode: 'off'
206
+ )
207
+ admin_client.close
208
+ end
209
+ client.close
210
+ end
211
+
212
+ it 'retries on different mongos' do
213
+ client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
214
+ expect { collection.find.first }.to raise_error(Mongo::Error::OperationFailure)
215
+ expect(find_started_events.map { |e| e.address.to_s }.sort).to eq(expected_servers)
216
+ expect(find_failed_events.map { |e| e.address.to_s }.sort).to eq(expected_servers)
217
+ end
218
+ end
219
+
220
+ context 'when no other mongos is available' do
221
+ let(:mongos) do
222
+ Mongo::Client.new(
223
+ [SpecConfig.instance.addresses.first],
224
+ direct_connection: true,
225
+ database: 'admin'
226
+ )
227
+ end
228
+
229
+ let(:client) do
230
+ new_local_client(
231
+ [
232
+ SpecConfig.instance.addresses.first
233
+ ],
234
+ SpecConfig.instance.test_options.merge(retry_reads: true)
235
+ )
236
+ end
237
+
238
+ before do
239
+ mongos.database.command(
240
+ configureFailPoint: 'failCommand',
241
+ mode: { times: 1 },
242
+ data: {
243
+ failCommands: %w(find),
244
+ closeConnection: false,
245
+ errorCode: 6
246
+ }
247
+ )
248
+ end
249
+
250
+ after do
251
+ mongos.database.command(
252
+ configureFailPoint: 'failCommand',
253
+ mode: 'off'
254
+ )
255
+ mongos.close
256
+ client.close
257
+ end
258
+
259
+ it 'retries on the same mongos' do
260
+ client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
261
+ expect { collection.find.first }.not_to raise_error
262
+ expect(find_started_events.map { |e| e.address.to_s }.sort).to eq([
263
+ SpecConfig.instance.addresses.first.to_s,
264
+ SpecConfig.instance.addresses.first.to_s
265
+ ])
266
+ expect(find_failed_events.map { |e| e.address.to_s }.sort).to eq([
267
+ SpecConfig.instance.addresses.first.to_s
268
+ ])
269
+ expect(find_succeeded_events.map { |e| e.address.to_s }.sort).to eq([
270
+ SpecConfig.instance.addresses.first.to_s
271
+ ])
272
+ end
273
+ end
274
+ end
110
275
  end
@@ -189,4 +189,160 @@ describe 'Retryable writes errors tests' do
189
189
  })
190
190
  end
191
191
  end
192
+
193
+ context 'Retries in a sharded cluster' do
194
+ require_topology :sharded
195
+ min_server_version '4.2'
196
+ require_no_auth
197
+
198
+ let(:subscriber) { Mrss::EventSubscriber.new }
199
+
200
+ let(:insert_started_events) do
201
+ subscriber.started_events.select { |e| e.command_name == "insert" }
202
+ end
203
+
204
+ let(:insert_failed_events) do
205
+ subscriber.failed_events.select { |e| e.command_name == "insert" }
206
+ end
207
+
208
+ let(:insert_succeeded_events) do
209
+ subscriber.succeeded_events.select { |e| e.command_name == "insert" }
210
+ end
211
+
212
+ context 'when another mongos is available' do
213
+
214
+ let(:first_mongos) do
215
+ Mongo::Client.new(
216
+ [SpecConfig.instance.addresses.first],
217
+ direct_connection: true,
218
+ database: 'admin'
219
+ )
220
+ end
221
+
222
+ let(:second_mongos) do
223
+ Mongo::Client.new(
224
+ [SpecConfig.instance.addresses.last],
225
+ direct_connection: false,
226
+ database: 'admin'
227
+ )
228
+ end
229
+
230
+ let(:client) do
231
+ new_local_client(
232
+ [
233
+ SpecConfig.instance.addresses.first,
234
+ SpecConfig.instance.addresses.last,
235
+ ],
236
+ SpecConfig.instance.test_options.merge(retry_writes: true)
237
+ )
238
+ end
239
+
240
+ let(:expected_servers) do
241
+ [
242
+ SpecConfig.instance.addresses.first.to_s,
243
+ SpecConfig.instance.addresses.last.to_s
244
+ ].sort
245
+ end
246
+
247
+ before do
248
+ skip 'This test requires at least two mongos' if SpecConfig.instance.addresses.length < 2
249
+
250
+ first_mongos.database.command(
251
+ configureFailPoint: 'failCommand',
252
+ mode: { times: 1 },
253
+ data: {
254
+ failCommands: %w(insert),
255
+ closeConnection: false,
256
+ errorCode: 6,
257
+ errorLabels: ['RetryableWriteError']
258
+ }
259
+ )
260
+
261
+ second_mongos.database.command(
262
+ configureFailPoint: 'failCommand',
263
+ mode: { times: 1 },
264
+ data: {
265
+ failCommands: %w(insert),
266
+ closeConnection: false,
267
+ errorCode: 6,
268
+ errorLabels: ['RetryableWriteError']
269
+ }
270
+ )
271
+ end
272
+
273
+ after do
274
+ [first_mongos, second_mongos].each do |admin_client|
275
+ admin_client.database.command(
276
+ configureFailPoint: 'failCommand',
277
+ mode: 'off'
278
+ )
279
+ admin_client.close
280
+ end
281
+ client.close
282
+ end
283
+
284
+ it 'retries on different mongos' do
285
+ client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
286
+ expect { collection.insert_one(x: 1) }.to raise_error(Mongo::Error::OperationFailure)
287
+ expect(insert_started_events.map { |e| e.address.to_s }.sort).to eq(expected_servers)
288
+ expect(insert_failed_events.map { |e| e.address.to_s }.sort).to eq(expected_servers)
289
+ end
290
+ end
291
+
292
+ context 'when no other mongos is available' do
293
+ let(:mongos) do
294
+ Mongo::Client.new(
295
+ [SpecConfig.instance.addresses.first],
296
+ direct_connection: true,
297
+ database: 'admin'
298
+ )
299
+ end
300
+
301
+ let(:client) do
302
+ new_local_client(
303
+ [
304
+ SpecConfig.instance.addresses.first
305
+ ],
306
+ SpecConfig.instance.test_options.merge(retry_writes: true)
307
+ )
308
+ end
309
+
310
+ before do
311
+ mongos.database.command(
312
+ configureFailPoint: 'failCommand',
313
+ mode: { times: 1 },
314
+ data: {
315
+ failCommands: %w(insert),
316
+ closeConnection: false,
317
+ errorCode: 6,
318
+ errorLabels: ['RetryableWriteError']
319
+ }
320
+ )
321
+ end
322
+
323
+ after do
324
+ mongos.database.command(
325
+ configureFailPoint: 'failCommand',
326
+ mode: 'off'
327
+ )
328
+ mongos.close
329
+ client.close
330
+ end
331
+
332
+ it 'retries on the same mongos' do
333
+ client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
334
+ expect { collection.insert_one(x: 1) }.not_to raise_error
335
+ expect(insert_started_events.map { |e| e.address.to_s }.sort).to eq([
336
+ SpecConfig.instance.addresses.first.to_s,
337
+ SpecConfig.instance.addresses.first.to_s
338
+ ])
339
+ expect(insert_failed_events.map { |e| e.address.to_s }.sort).to eq([
340
+ SpecConfig.instance.addresses.first.to_s
341
+ ])
342
+ expect(insert_succeeded_events.map { |e| e.address.to_s }.sort).to eq([
343
+ SpecConfig.instance.addresses.first.to_s
344
+ ])
345
+ end
346
+ end
347
+ end
192
348
  end