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
@@ -142,26 +142,37 @@ module Mongo
142
142
  #
143
143
  # @since 2.0.0
144
144
  def connect!
145
- Timeout.timeout(options[:connect_timeout], Error::SocketTimeoutError, "The socket took over #{options[:connect_timeout]} seconds to connect") do
146
- map_exceptions do
147
- @tcp_socket.connect(::Socket.pack_sockaddr_in(port, host))
148
- end
149
- @socket = OpenSSL::SSL::SSLSocket.new(@tcp_socket, context)
150
- begin
151
- @socket.hostname = @host_name
152
- @socket.sync_close = true
153
- map_exceptions do
154
- @socket.connect
145
+ sockaddr = ::Socket.pack_sockaddr_in(port, host)
146
+ connect_timeout = options[:connect_timeout]
147
+ map_exceptions do
148
+ if connect_timeout && connect_timeout != 0
149
+ deadline = Utils.monotonic_time + connect_timeout
150
+ if BSON::Environment.jruby?
151
+ # We encounter some strange problems with connect_nonblock for
152
+ # ssl sockets on JRuby. Therefore, we use the old +Timeout.timeout+
153
+ # solution, even though it is known to be not very reliable.
154
+ raise Error::SocketTimeoutError, 'connect_timeout expired' if connect_timeout < 0
155
+
156
+ Timeout.timeout(connect_timeout, Error::SocketTimeoutError, "The socket took over #{options[:connect_timeout]} seconds to connect") do
157
+ connect_without_timeout(sockaddr)
158
+ end
159
+ else
160
+ connect_with_timeout(sockaddr, connect_timeout)
155
161
  end
162
+ remaining_timeout = deadline - Utils.monotonic_time
163
+ verify_certificate!(@socket)
164
+ verify_ocsp_endpoint!(@socket, remaining_timeout)
165
+ else
166
+ connect_without_timeout(sockaddr)
156
167
  verify_certificate!(@socket)
157
168
  verify_ocsp_endpoint!(@socket)
158
- rescue
159
- @socket.close
160
- @socket = nil
161
- raise
162
169
  end
163
- self
164
170
  end
171
+ self
172
+ rescue
173
+ @socket&.close
174
+ @socket = nil
175
+ raise
165
176
  end
166
177
  private :connect!
167
178
 
@@ -182,6 +193,87 @@ module Mongo
182
193
 
183
194
  private
184
195
 
196
+ # Connects the socket without a timeout provided.
197
+ #
198
+ # @param [ String ] sockaddr Address to connect to.
199
+ def connect_without_timeout(sockaddr)
200
+ @tcp_socket.connect(sockaddr)
201
+ @socket = OpenSSL::SSL::SSLSocket.new(@tcp_socket, context)
202
+ @socket.hostname = @host_name
203
+ @socket.sync_close = true
204
+ @socket.connect
205
+ end
206
+
207
+ # Connects the socket with the connect timeout. The timeout applies to
208
+ # connecting both ssl socket and the underlying tcp socket.
209
+ #
210
+ # @param [ String ] sockaddr Address to connect to.
211
+ def connect_with_timeout(sockaddr, connect_timeout)
212
+ if connect_timeout <= 0
213
+ raise Error::SocketTimeoutError, "The socket took over #{connect_timeout} seconds to connect"
214
+ end
215
+
216
+ deadline = Utils.monotonic_time + connect_timeout
217
+ connect_tcp_socket_with_timeout(sockaddr, deadline, connect_timeout)
218
+ connnect_ssl_socket_with_timeout(deadline, connect_timeout)
219
+ end
220
+
221
+ def connect_tcp_socket_with_timeout(sockaddr, deadline, connect_timeout)
222
+ if deadline <= Utils.monotonic_time
223
+ raise Error::SocketTimeoutError, "The socket took over #{connect_timeout} seconds to connect"
224
+ end
225
+ begin
226
+ @tcp_socket.connect_nonblock(sockaddr)
227
+ rescue IO::WaitWritable
228
+ with_select_timeout(deadline, connect_timeout) do |select_timeout|
229
+ IO.select(nil, [@tcp_socket], nil, select_timeout)
230
+ end
231
+ retry
232
+ rescue Errno::EISCONN
233
+ # Socket is connected, nothing to do.
234
+ end
235
+ end
236
+
237
+ def connnect_ssl_socket_with_timeout(deadline, connect_timeout)
238
+ if deadline <= Utils.monotonic_time
239
+ raise Error::SocketTimeoutError, "The socket took over #{connect_timeout} seconds to connect"
240
+ end
241
+ @socket = OpenSSL::SSL::SSLSocket.new(@tcp_socket, context)
242
+ @socket.hostname = @host_name
243
+ @socket.sync_close = true
244
+
245
+ # We still have time, connecting ssl socket.
246
+ begin
247
+ @socket.connect_nonblock
248
+ rescue IO::WaitReadable, OpenSSL::SSL::SSLErrorWaitReadable
249
+ with_select_timeout(deadline, connect_timeout) do |select_timeout|
250
+ IO.select([@socket], nil, nil, select_timeout)
251
+ end
252
+ retry
253
+ rescue IO::WaitWritable, OpenSSL::SSL::SSLErrorWaitWritable
254
+ with_select_timeout(deadline, connect_timeout) do |select_timeout|
255
+ IO.select(nil, [@socket], nil, select_timeout)
256
+ end
257
+ retry
258
+ rescue Errno::EISCONN
259
+ # Socket is connected, nothing to do
260
+ end
261
+ end
262
+
263
+ # Raises +Error::SocketTimeoutError+ exception if deadline reached or the
264
+ # block returns nil. The block should call +IO.select+ with the
265
+ # +connect_timeout+ value. It returns nil if the +connect_timeout+ expires.
266
+ def with_select_timeout(deadline, connect_timeout, &block)
267
+ select_timeout = deadline - Utils.monotonic_time
268
+ if select_timeout <= 0
269
+ raise Error::SocketTimeoutError, "The socket took over #{connect_timeout} seconds to connect"
270
+ end
271
+ rv = block.call(select_timeout)
272
+ if rv.nil?
273
+ raise Error::SocketTimeoutError, "The socket took over #{connect_timeout} seconds to connect"
274
+ end
275
+ end
276
+
185
277
  def verify_certificate?
186
278
  # If ssl_verify_certificate is not present, disable only if
187
279
  # ssl_verify is explicitly set to false.
@@ -287,7 +379,7 @@ module Mongo
287
379
  # for instance, if there is no newline between two certificates
288
380
  # this code will extract them both but OpenSSL fails in this situation.
289
381
  if cert_text
290
- certs = cert_text.scan(/-----BEGIN CERTIFICATE-----(?:.|\n)+?-----END CERTIFICATE-----/)
382
+ certs = extract_certs(cert_text)
291
383
  if certs.length > 1
292
384
  context.cert = OpenSSL::X509::Certificate.new(certs.shift)
293
385
  context.extra_chain_cert = certs.map do |cert|
@@ -362,7 +454,7 @@ module Mongo
362
454
  end
363
455
  end
364
456
 
365
- def verify_ocsp_endpoint!(socket)
457
+ def verify_ocsp_endpoint!(socket, timeout = nil)
366
458
  unless verify_ocsp_endpoint?
367
459
  return
368
460
  end
@@ -371,7 +463,7 @@ module Mongo
371
463
  ca_cert = socket.peer_cert_chain.last
372
464
 
373
465
  verifier = OcspVerifier.new(@host_name, cert, ca_cert, context.cert_store,
374
- **Utils.shallow_symbolize_keys(options))
466
+ **Utils.shallow_symbolize_keys(options).merge(timeout: timeout))
375
467
  verifier.verify_with_cache
376
468
  end
377
469
 
@@ -390,6 +482,27 @@ module Mongo
390
482
  hook.call(@context)
391
483
  end
392
484
  end
485
+
486
+ BEGIN_CERT = "-----BEGIN CERTIFICATE-----"
487
+ END_CERT = "-----END CERTIFICATE-----"
488
+
489
+ # This was originally a scan + regex, but the regex was particularly
490
+ # inefficient and was flagged as a concern by static analysis.
491
+ def extract_certs(text)
492
+ [].tap do |list|
493
+ pos = 0
494
+
495
+ while (begin_idx = text.index(BEGIN_CERT, pos))
496
+ end_idx = text.index(END_CERT, begin_idx)
497
+ break unless end_idx
498
+
499
+ end_idx += END_CERT.length
500
+ list.push(text[begin_idx...end_idx])
501
+
502
+ pos = end_idx
503
+ end
504
+ end
505
+ end
393
506
  end
394
507
  end
395
508
  end
@@ -79,16 +79,50 @@ module Mongo
79
79
  # @return [ TCP ] The connected socket instance.
80
80
  #
81
81
  # @since 2.0.0
82
+ # @api private
82
83
  def connect!
83
- Timeout.timeout(options[:connect_timeout], Error::SocketTimeoutError, "The socket took over #{options[:connect_timeout]} seconds to connect") do
84
- socket.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
85
- map_exceptions do
86
- socket.connect(::Socket.pack_sockaddr_in(port, host))
84
+ socket.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
85
+ sockaddr = ::Socket.pack_sockaddr_in(port, host)
86
+ connect_timeout = options[:connect_timeout]
87
+ map_exceptions do
88
+ if connect_timeout && connect_timeout != 0
89
+ connect_with_timeout(sockaddr, connect_timeout)
90
+ else
91
+ connect_without_timeout(sockaddr)
92
+ end
93
+ end
94
+ self
95
+ end
96
+
97
+ # @api private
98
+ def connect_without_timeout(sockaddr)
99
+ socket.connect(sockaddr)
100
+ end
101
+
102
+ # @api private
103
+ def connect_with_timeout(sockaddr, connect_timeout)
104
+ if connect_timeout <= 0
105
+ raise Error::SocketTimeoutError, "The socket took over #{connect_timeout} seconds to connect"
106
+ end
107
+
108
+ deadline = Utils.monotonic_time + connect_timeout
109
+ begin
110
+ socket.connect_nonblock(sockaddr)
111
+ rescue IO::WaitWritable
112
+ select_timeout = deadline - Utils.monotonic_time
113
+ if select_timeout <= 0
114
+ raise Error::SocketTimeoutError, "The socket took over #{connect_timeout} seconds to connect"
115
+ end
116
+ if IO.select(nil, [socket], nil, select_timeout)
117
+ retry
118
+ else
119
+ socket.close
120
+ raise Error::SocketTimeoutError, "The socket took over #{connect_timeout} seconds to connect"
87
121
  end
88
- self
122
+ rescue Errno::EISCONN
123
+ # Socket is connected, nothing more to do
89
124
  end
90
125
  end
91
- private :connect!
92
126
 
93
127
  private
94
128
 
data/lib/mongo/socket.rb CHANGED
@@ -192,27 +192,24 @@ module Mongo
192
192
  # socket.read(4096)
193
193
  #
194
194
  # @param [ Integer ] length The number of bytes to read.
195
- # @param [ Numeric ] timeout The timeout to use for each chunk read.
195
+ # @param [ Numeric ] socket_timeout The timeout to use for each chunk read,
196
+ # mutually exclusive to +timeout+.
197
+ # @param [ Numeric ] timeout The total timeout to the whole read operation,
198
+ # mutually exclusive to +socket_timeout+.
196
199
  #
197
200
  # @raise [ Mongo::SocketError ] If not all data is returned.
198
201
  #
199
202
  # @return [ Object ] The data from the socket.
200
203
  #
201
204
  # @since 2.0.0
202
- def read(length, timeout: nil)
203
- map_exceptions do
204
- data = read_from_socket(length, timeout: timeout)
205
- unless (data.length > 0 || length == 0)
206
- raise IOError, "Expected to read > 0 bytes but read 0 bytes"
207
- end
208
- while data.length < length
209
- chunk = read_from_socket(length - data.length, timeout: timeout)
210
- unless (chunk.length > 0 || length == 0)
211
- raise IOError, "Expected to read > 0 bytes but read 0 bytes"
212
- end
213
- data << chunk
214
- end
215
- data
205
+ def read(length, socket_timeout: nil, timeout: nil)
206
+ if !socket_timeout.nil? && !timeout.nil?
207
+ raise ArgumentError, 'Both timeout and socket_timeout cannot be set'
208
+ end
209
+ if !socket_timeout.nil? || timeout.nil?
210
+ read_without_timeout(length, socket_timeout)
211
+ else
212
+ read_with_timeout(length, timeout)
216
213
  end
217
214
  end
218
215
 
@@ -233,15 +230,16 @@ module Mongo
233
230
  # Writes data to the socket instance.
234
231
  #
235
232
  # @param [ Array<Object> ] args The data to be written.
233
+ # @param [ Numeric ] timeout The total timeout to the whole write operation.
236
234
  #
237
235
  # @return [ Integer ] The length of bytes written to the socket.
238
236
  #
239
237
  # @raise [ Error::SocketError | Error::SocketTimeoutError ] When there is a network error during the write.
240
238
  #
241
239
  # @since 2.0.0
242
- def write(*args)
240
+ def write(*args, timeout: nil)
243
241
  map_exceptions do
244
- do_write(*args)
242
+ do_write(*args, timeout: timeout)
245
243
  end
246
244
  end
247
245
 
@@ -254,7 +252,7 @@ module Mongo
254
252
  true
255
253
  end
256
254
 
257
- # For backwards compatibilty only, do not use.
255
+ # For backwards compatibility only, do not use.
258
256
  #
259
257
  # @return [ true ] Always true.
260
258
  #
@@ -265,18 +263,76 @@ module Mongo
265
263
 
266
264
  private
267
265
 
268
- def read_from_socket(length, timeout: nil)
266
+ # Reads the +length+ bytes from the socket, the read operation duration is
267
+ # limited to +timeout+ second.
268
+ #
269
+ # @param [ Integer ] length The number of bytes to read.
270
+ # @param [ Numeric ] timeout The total timeout to the whole read operation.
271
+ #
272
+ # @return [ Object ] The data from the socket.
273
+ def read_with_timeout(length, timeout)
274
+ deadline = Utils.monotonic_time + timeout
275
+ map_exceptions do
276
+ String.new.tap do |data|
277
+ while data.length < length
278
+ socket_timeout = deadline - Utils.monotonic_time
279
+ if socket_timeout <= 0
280
+ raise Mongo::Error::TimeoutError
281
+ end
282
+ chunk = read_from_socket(length - data.length, socket_timeout: socket_timeout, csot: true)
283
+ unless chunk.length > 0
284
+ raise IOError, "Expected to read > 0 bytes but read 0 bytes"
285
+ end
286
+ data << chunk
287
+ end
288
+ end
289
+ end
290
+ end
291
+
292
+ # Reads the +length+ bytes from the socket. The read operation may involve
293
+ # multiple socket reads, each read is limited to +timeout+ second,
294
+ # if the parameter is provided.
295
+ #
296
+ # @param [ Integer ] length The number of bytes to read.
297
+ # @param [ Numeric ] socket_timeout The timeout to use for each chunk read.
298
+ #
299
+ # @return [ Object ] The data from the socket.
300
+ def read_without_timeout(length, socket_timeout = nil)
301
+ map_exceptions do
302
+ String.new.tap do |data|
303
+ while data.length < length
304
+ chunk = read_from_socket(length - data.length, socket_timeout: socket_timeout)
305
+ unless chunk.length > 0
306
+ raise IOError, "Expected to read > 0 bytes but read 0 bytes"
307
+ end
308
+ data << chunk
309
+ end
310
+ end
311
+ end
312
+ end
313
+
314
+
315
+ # Reads the +length+ bytes from the socket. The read operation may involve
316
+ # multiple socket reads, each read is limited to +timeout+ second,
317
+ # if the parameter is provided.
318
+ #
319
+ # @param [ Integer ] length The number of bytes to read.
320
+ # @param [ Numeric ] :socket_timeout The timeout to use for each chunk read.
321
+ # @param [ true | false ] :csot Whether the CSOT timeout is set for the operation.
322
+ #
323
+ # @return [ Object ] The data from the socket.
324
+ def read_from_socket(length, socket_timeout: nil, csot: false)
269
325
  # Just in case
270
326
  if length == 0
271
327
  return ''.force_encoding('BINARY')
272
328
  end
273
329
 
274
- _timeout = timeout || self.timeout
330
+ _timeout = socket_timeout || self.timeout
275
331
  if _timeout
276
332
  if _timeout > 0
277
333
  deadline = Utils.monotonic_time + _timeout
278
334
  elsif _timeout < 0
279
- raise Errno::ETIMEDOUT, "Negative timeout #{_timeout} given to socket"
335
+ raise_timeout_error!("Negative timeout #{_timeout} given to socket", csot)
280
336
  end
281
337
  end
282
338
 
@@ -331,7 +387,7 @@ module Mongo
331
387
  if deadline
332
388
  select_timeout = deadline - Utils.monotonic_time
333
389
  if select_timeout <= 0
334
- raise Errno::ETIMEDOUT, "Took more than #{_timeout} seconds to receive data"
390
+ raise_timeout_error!("Took more than #{_timeout} seconds to receive data", csot)
335
391
  end
336
392
  end
337
393
  pipe = options[:pipe]
@@ -373,11 +429,11 @@ module Mongo
373
429
  if deadline
374
430
  select_timeout = deadline - Utils.monotonic_time
375
431
  if select_timeout <= 0
376
- raise Errno::ETIMEDOUT, "Took more than #{_timeout} seconds to receive data"
432
+ raise_timeout_error!("Took more than #{_timeout} seconds to receive data", csot)
377
433
  end
378
434
  end
379
435
  elsif rv.nil?
380
- raise Errno::ETIMEDOUT, "Took more than #{_timeout} seconds to receive data (select call timed out)"
436
+ raise_timeout_error!("Took more than #{_timeout} seconds to receive data (select call timed out)", csot)
381
437
  end
382
438
  retry
383
439
  end
@@ -402,9 +458,23 @@ module Mongo
402
458
  # sholud map exceptions.
403
459
  #
404
460
  # @param [ Array<Object> ] args The data to be written.
461
+ # @param [ Numeric ] :timeout The total timeout to the whole write operation.
462
+ #
463
+ # @return [ Integer ] The length of bytes written to the socket.
464
+ def do_write(*args, timeout: nil)
465
+ if timeout.nil?
466
+ write_without_timeout(*args)
467
+ else
468
+ write_with_timeout(*args, timeout: timeout)
469
+ end
470
+ end
471
+
472
+ # Writes data to to the socket.
473
+ #
474
+ # @param [ Array<Object> ] args The data to be written.
405
475
  #
406
476
  # @return [ Integer ] The length of bytes written to the socket.
407
- def do_write(*args)
477
+ def write_without_timeout(*args)
408
478
  # This method used to forward arguments to @socket.write in a
409
479
  # single call like so:
410
480
  #
@@ -428,6 +498,57 @@ module Mongo
428
498
  end
429
499
  end
430
500
 
501
+ # Writes data to to the socket, the write duration is limited to +timeout+.
502
+ #
503
+ # @param [ Array<Object> ] args The data to be written.
504
+ # @param [ Numeric ] :timeout The total timeout to the whole write operation.
505
+ #
506
+ # @return [ Integer ] The length of bytes written to the socket.
507
+ def write_with_timeout(*args, timeout:)
508
+ raise ArgumentError, 'timeout cannot be nil' if timeout.nil?
509
+ raise_timeout_error!("Negative timeout #{timeout} given to socket", true) if timeout < 0
510
+
511
+ written = 0
512
+ args.each do |buf|
513
+ buf = buf.to_s
514
+ i = 0
515
+ while i < buf.length
516
+ chunk = buf[i...(i + WRITE_CHUNK_SIZE)]
517
+ written += write_chunk(chunk, timeout)
518
+ i += WRITE_CHUNK_SIZE
519
+ end
520
+ end
521
+ written
522
+ end
523
+
524
+ def write_chunk(chunk, timeout)
525
+ deadline = Utils.monotonic_time + timeout
526
+ written = 0
527
+ begin
528
+ written += @socket.write_nonblock(chunk[written..-1])
529
+ rescue IO::WaitWritable, Errno::EINTR
530
+ select_timeout = deadline - Utils.monotonic_time
531
+ rv = Kernel.select(nil, [@socket], nil, select_timeout)
532
+ if BSON::Environment.jruby?
533
+ # Ignore the return value of Kernel.select.
534
+ # On JRuby, select appears to return nil prior to timeout expiration
535
+ # (apparently due to a EAGAIN) which then causes us to fail the read
536
+ # even though we could have retried it.
537
+ # Check the deadline ourselves.
538
+ if deadline
539
+ select_timeout = deadline - Utils.monotonic_time
540
+ if select_timeout <= 0
541
+ raise_timeout_error!("Took more than #{timeout} seconds to receive data", true)
542
+ end
543
+ end
544
+ elsif rv.nil?
545
+ raise_timeout_error!("Took more than #{timeout} seconds to receive data (select call timed out)", true)
546
+ end
547
+ retry
548
+ end
549
+ written
550
+ end
551
+
431
552
  def unix_socket?(sock)
432
553
  defined?(UNIXSocket) && sock.is_a?(UNIXSocket)
433
554
  end
@@ -482,5 +603,13 @@ module Mongo
482
603
  def human_address
483
604
  raise NotImplementedError
484
605
  end
606
+
607
+ def raise_timeout_error!(message = nil, csot = false)
608
+ if csot
609
+ raise Mongo::Error::TimeoutError
610
+ else
611
+ raise Errno::ETIMEDOUT, message
612
+ end
613
+ end
485
614
  end
486
615
  end
@@ -272,6 +272,7 @@ module Mongo
272
272
  uri_option 'localThresholdMS', :local_threshold, type: :ms
273
273
  uri_option 'heartbeatFrequencyMS', :heartbeat_frequency, type: :ms
274
274
  uri_option 'maxIdleTimeMS', :max_idle_time, type: :ms
275
+ uri_option 'timeoutMS', :timeout_ms, type: :integer
275
276
 
276
277
  # Write Options
277
278
  uri_option 'w', :w, group: :write_concern, type: :w
data/lib/mongo/uri.rb CHANGED
@@ -377,10 +377,6 @@ module Mongo
377
377
  raise_invalid_error!("Options contain an unescaped question mark (?), or the database name contains a question mark and was not escaped")
378
378
  end
379
379
 
380
- if options && !hosts_and_db.index('/')
381
- raise_invalid_error!("MongoDB URI must have a slash (/) after the hosts if options are given")
382
- end
383
-
384
380
  hosts, db = hosts_and_db.split('/', 2)
385
381
  if db && db.index('/')
386
382
  raise_invalid_error!("Database name contains an unescaped slash (/): #{db}")
data/lib/mongo/version.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- # rubocop:todo all
3
2
 
4
3
  # Copyright (C) 2014-2020 MongoDB Inc.
5
4
  #
@@ -16,9 +15,6 @@
16
15
  # limitations under the License.
17
16
 
18
17
  module Mongo
19
-
20
18
  # The current version of the driver.
21
- #
22
- # @since 2.0.0
23
- VERSION = '2.19.1'.freeze
19
+ VERSION = '2.21.0'
24
20
  end
data/lib/mongo.rb CHANGED
@@ -39,6 +39,7 @@ require 'mongo/bson'
39
39
  require 'mongo/semaphore'
40
40
  require 'mongo/distinguishing_semaphore'
41
41
  require 'mongo/condition_variable'
42
+ require 'mongo/csot_timeout_holder'
42
43
  require 'mongo/options'
43
44
  require 'mongo/loggable'
44
45
  require 'mongo/cluster_time'
@@ -64,6 +65,7 @@ require 'mongo/client_encryption'
64
65
  require 'mongo/dbref'
65
66
  require 'mongo/grid'
66
67
  require 'mongo/index'
68
+ require 'mongo/search_index/view'
67
69
  require 'mongo/lint'
68
70
  require 'mongo/query_cache'
69
71
  require 'mongo/server'
data/mongo.gemspec CHANGED
@@ -9,28 +9,25 @@ Gem::Specification.new do |s|
9
9
  s.name = 'mongo'
10
10
  s.version = Mongo::VERSION
11
11
  s.platform = Gem::Platform::RUBY
12
- s.authors = ["The MongoDB Ruby Team"]
13
- s.email = "dbx-ruby@mongodb.com"
12
+ s.authors = [ 'The MongoDB Ruby Team' ]
13
+ s.email = 'dbx-ruby@mongodb.com'
14
14
  s.homepage = 'https://mongodb.com/docs/ruby-driver/'
15
15
  s.summary = 'Ruby driver for MongoDB'
16
- s.description = 'A Ruby driver for MongoDB'
17
16
  s.license = 'Apache-2.0'
17
+ s.description = <<~DESC
18
+ A pure-Ruby driver for connecting to, querying, and manipulating MongoDB
19
+ databases. Officially developed and supported by MongoDB, with love for
20
+ the Ruby community.
21
+ DESC
18
22
 
19
23
  s.metadata = {
20
24
  'bug_tracker_uri' => 'https://jira.mongodb.org/projects/RUBY',
21
25
  'changelog_uri' => 'https://github.com/mongodb/mongo-ruby-driver/releases',
22
- 'documentation_uri' => 'https://mongodb.com/docs/ruby-driver/',
23
26
  'homepage_uri' => 'https://mongodb.com/docs/ruby-driver/',
27
+ 'documentation_uri' => 'https://mongodb.com/docs/ruby-driver/current/tutorials/quick-start/',
24
28
  'source_code_uri' => 'https://github.com/mongodb/mongo-ruby-driver',
25
29
  }
26
30
 
27
- if File.exist?('gem-private_key.pem')
28
- s.signing_key = 'gem-private_key.pem'
29
- s.cert_chain = ['gem-public_cert.pem']
30
- else
31
- warn "[#{s.name}] Warning: No private key present, creating unsigned gem."
32
- end
33
-
34
31
  s.files = Dir.glob('{bin,lib,spec}/**/*')
35
32
  s.files += %w[mongo.gemspec LICENSE README.md CONTRIBUTING.md Rakefile]
36
33
  s.test_files = Dir.glob('spec/**/*')
@@ -41,11 +38,5 @@ Gem::Specification.new do |s|
41
38
 
42
39
  s.required_ruby_version = ">= 2.5"
43
40
 
44
- # For testing driver against bson master we need to depend on bson < 6.0.0
45
- # but in release version we want to depend on bson < 5.0.0.
46
- if %w(1 yes true).include?(ENV['MONGO_RUBY_DRIVER_BSON_MASTER'])
47
- s.add_dependency 'bson', '>=4.13.0', '<6.0.0'
48
- else
49
- s.add_dependency 'bson', '>=4.14.1', '<5.0.0'
50
- end
41
+ s.add_dependency 'bson', '>=4.14.1', '<6.0.0'
51
42
  end
@@ -7,21 +7,21 @@ describe 'Atlas connectivity' do
7
7
  let(:uri) { ENV['ATLAS_URI'] }
8
8
  let(:client) { Mongo::Client.new(uri) }
9
9
 
10
- before do
11
- if uri.nil?
12
- skip "ATLAS_URI not set in environment"
13
- end
14
- end
10
+ require_atlas
15
11
 
16
12
  describe 'connection to Atlas' do
13
+ after do
14
+ client.close
15
+ end
16
+
17
17
  it 'runs ismaster successfully' do
18
- result = client.database.command(:ismaster => 1)
19
- expect(result.documents.first['ismaster']).to be true
18
+ expect { client.database.command(:hello => 1) }
19
+ .not_to raise_error
20
20
  end
21
21
 
22
22
  it 'runs findOne successfully' do
23
- result = client.use(:test)['test'].find.to_a
24
- expect(result).to be_a(Array)
23
+ expect { client.use(:test)['test'].find.to_a }
24
+ .not_to raise_error
25
25
  end
26
26
  end
27
27
  end
@@ -7,13 +7,13 @@ describe 'Operations' do
7
7
  let(:uri) { ENV['ATLAS_URI'] }
8
8
  let(:client) { Mongo::Client.new(uri) }
9
9
 
10
- before do
11
- if uri.nil?
12
- skip "ATLAS_URI not set in environment"
13
- end
14
- end
10
+ require_atlas
15
11
 
16
12
  describe 'ping' do
13
+ after do
14
+ client.close
15
+ end
16
+
17
17
  it 'works' do
18
18
  expect do
19
19
  client.database.command(ping: 1)
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "httparty"
4
+ gem "mongo"
5
+
6
+ group :test do
7
+ gem "test-unit"
8
+ gem "mocha"
9
+ end