mongo 2.13.0 → 2.15.0.alpha

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 (375) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +1 -4
  3. data.tar.gz.sig +0 -0
  4. data/README.md +4 -1
  5. data/Rakefile +46 -18
  6. data/lib/mongo.rb +32 -0
  7. data/lib/mongo/address.rb +1 -1
  8. data/lib/mongo/address/ipv4.rb +1 -1
  9. data/lib/mongo/address/ipv6.rb +1 -1
  10. data/lib/mongo/auth/aws/conversation.rb +1 -4
  11. data/lib/mongo/auth/base.rb +13 -7
  12. data/lib/mongo/auth/conversation_base.rb +32 -0
  13. data/lib/mongo/auth/cr/conversation.rb +6 -29
  14. data/lib/mongo/auth/gssapi/conversation.rb +4 -15
  15. data/lib/mongo/auth/ldap/conversation.rb +3 -14
  16. data/lib/mongo/auth/sasl_conversation_base.rb +1 -13
  17. data/lib/mongo/auth/scram_conversation_base.rb +7 -34
  18. data/lib/mongo/auth/user/view.rb +16 -9
  19. data/lib/mongo/auth/x509/conversation.rb +4 -25
  20. data/lib/mongo/background_thread.rb +11 -0
  21. data/lib/mongo/bulk_write.rb +38 -18
  22. data/lib/mongo/caching_cursor.rb +74 -0
  23. data/lib/mongo/client.rb +142 -16
  24. data/lib/mongo/cluster.rb +22 -31
  25. data/lib/mongo/cluster/reapers/cursor_reaper.rb +6 -2
  26. data/lib/mongo/cluster/sdam_flow.rb +14 -0
  27. data/lib/mongo/cluster/topology/single.rb +1 -1
  28. data/lib/mongo/collection.rb +58 -18
  29. data/lib/mongo/collection/view.rb +24 -20
  30. data/lib/mongo/collection/view/aggregation.rb +26 -5
  31. data/lib/mongo/collection/view/builder/find_command.rb +38 -18
  32. data/lib/mongo/collection/view/change_stream.rb +1 -1
  33. data/lib/mongo/collection/view/explainable.rb +27 -8
  34. data/lib/mongo/collection/view/iterable.rb +73 -13
  35. data/lib/mongo/collection/view/map_reduce.rb +2 -2
  36. data/lib/mongo/collection/view/readable.rb +57 -21
  37. data/lib/mongo/collection/view/writable.rb +29 -15
  38. data/lib/mongo/crypt/encryption_io.rb +6 -6
  39. data/lib/mongo/cursor.rb +18 -5
  40. data/lib/mongo/database.rb +28 -5
  41. data/lib/mongo/database/view.rb +2 -2
  42. data/lib/mongo/error.rb +11 -1
  43. data/lib/mongo/error/bulk_write_error.rb +17 -3
  44. data/lib/mongo/error/internal_driver_error.rb +22 -0
  45. data/lib/mongo/error/invalid_read_concern.rb +28 -0
  46. data/lib/mongo/error/operation_failure.rb +26 -7
  47. data/lib/mongo/error/parser.rb +65 -12
  48. data/lib/mongo/error/server_api_conflict.rb +23 -0
  49. data/lib/mongo/error/server_api_not_supported.rb +24 -0
  50. data/lib/mongo/error/server_certificate_revoked.rb +22 -0
  51. data/lib/mongo/error/unmet_dependency.rb +21 -0
  52. data/lib/mongo/error/unsupported_option.rb +14 -12
  53. data/lib/mongo/grid/fs_bucket.rb +37 -37
  54. data/lib/mongo/index/view.rb +21 -11
  55. data/lib/mongo/lint.rb +2 -1
  56. data/lib/mongo/logger.rb +3 -3
  57. data/lib/mongo/monitoring.rb +13 -4
  58. data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +27 -16
  59. data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +26 -15
  60. data/lib/mongo/operation.rb +4 -2
  61. data/lib/mongo/operation/aggregate/result.rb +9 -8
  62. data/lib/mongo/operation/collections_info.rb +18 -1
  63. data/lib/mongo/operation/collections_info/command.rb +5 -0
  64. data/lib/mongo/operation/collections_info/result.rb +18 -1
  65. data/lib/mongo/operation/context.rb +99 -0
  66. data/lib/mongo/operation/delete/bulk_result.rb +2 -0
  67. data/lib/mongo/operation/delete/result.rb +3 -0
  68. data/lib/mongo/operation/explain/command.rb +4 -0
  69. data/lib/mongo/operation/explain/legacy.rb +4 -0
  70. data/lib/mongo/operation/explain/op_msg.rb +6 -0
  71. data/lib/mongo/operation/explain/result.rb +3 -0
  72. data/lib/mongo/operation/find/legacy/result.rb +2 -0
  73. data/lib/mongo/operation/find/result.rb +13 -0
  74. data/lib/mongo/operation/get_more/result.rb +3 -0
  75. data/lib/mongo/operation/indexes.rb +15 -1
  76. data/lib/mongo/operation/indexes/result.rb +5 -0
  77. data/lib/mongo/operation/insert/bulk_result.rb +5 -0
  78. data/lib/mongo/operation/insert/command.rb +2 -2
  79. data/lib/mongo/operation/insert/legacy.rb +2 -2
  80. data/lib/mongo/operation/insert/op_msg.rb +2 -2
  81. data/lib/mongo/operation/insert/result.rb +5 -0
  82. data/lib/mongo/operation/list_collections/result.rb +9 -1
  83. data/lib/mongo/operation/map_reduce/result.rb +10 -0
  84. data/lib/mongo/operation/parallel_scan/result.rb +4 -0
  85. data/lib/mongo/operation/result.rb +37 -6
  86. data/lib/mongo/operation/shared/bypass_document_validation.rb +1 -0
  87. data/lib/mongo/operation/shared/causal_consistency_supported.rb +1 -0
  88. data/lib/mongo/operation/shared/executable.rb +25 -14
  89. data/lib/mongo/operation/shared/executable_no_validate.rb +2 -2
  90. data/lib/mongo/operation/shared/idable.rb +2 -1
  91. data/lib/mongo/operation/shared/limited.rb +1 -0
  92. data/lib/mongo/operation/shared/object_id_generator.rb +1 -0
  93. data/lib/mongo/operation/shared/op_msg_or_command.rb +1 -7
  94. data/lib/mongo/operation/shared/op_msg_or_find_command.rb +1 -7
  95. data/lib/mongo/operation/shared/polymorphic_operation.rb +39 -0
  96. data/lib/mongo/operation/shared/response_handling.rb +23 -23
  97. data/lib/mongo/operation/shared/result/aggregatable.rb +1 -0
  98. data/lib/mongo/operation/shared/sessions_supported.rb +14 -2
  99. data/lib/mongo/operation/shared/specifiable.rb +1 -0
  100. data/lib/mongo/operation/shared/write.rb +9 -18
  101. data/lib/mongo/operation/shared/write_concern_supported.rb +1 -0
  102. data/lib/mongo/operation/update/legacy/result.rb +7 -0
  103. data/lib/mongo/operation/update/result.rb +8 -0
  104. data/lib/mongo/operation/users_info/result.rb +3 -0
  105. data/lib/mongo/protocol/compressed.rb +51 -5
  106. data/lib/mongo/protocol/message.rb +31 -4
  107. data/lib/mongo/protocol/msg.rb +37 -12
  108. data/lib/mongo/protocol/query.rb +36 -0
  109. data/lib/mongo/query_cache.rb +272 -0
  110. data/lib/mongo/retryable.rb +9 -2
  111. data/lib/mongo/server.rb +12 -16
  112. data/lib/mongo/server/app_metadata.rb +52 -18
  113. data/lib/mongo/server/connection.rb +5 -0
  114. data/lib/mongo/server/connection_base.rb +16 -15
  115. data/lib/mongo/server/connection_common.rb +2 -2
  116. data/lib/mongo/server/connection_pool.rb +9 -4
  117. data/lib/mongo/server/description.rb +12 -1
  118. data/lib/mongo/server/description/features.rb +9 -8
  119. data/lib/mongo/server/monitor.rb +21 -2
  120. data/lib/mongo/server/monitor/app_metadata.rb +1 -1
  121. data/lib/mongo/server/monitor/connection.rb +12 -13
  122. data/lib/mongo/server/pending_connection.rb +26 -8
  123. data/lib/mongo/server/push_monitor.rb +12 -2
  124. data/lib/mongo/server_selector/base.rb +5 -1
  125. data/lib/mongo/session.rb +7 -3
  126. data/lib/mongo/session/session_pool.rb +4 -2
  127. data/lib/mongo/socket.rb +35 -8
  128. data/lib/mongo/socket/ocsp_cache.rb +97 -0
  129. data/lib/mongo/socket/ocsp_verifier.rb +368 -0
  130. data/lib/mongo/socket/ssl.rb +53 -24
  131. data/lib/mongo/srv/monitor.rb +7 -24
  132. data/lib/mongo/srv/resolver.rb +14 -10
  133. data/lib/mongo/timeout.rb +2 -0
  134. data/lib/mongo/uri.rb +21 -390
  135. data/lib/mongo/uri/options_mapper.rb +620 -0
  136. data/lib/mongo/uri/srv_protocol.rb +3 -2
  137. data/lib/mongo/utils.rb +27 -1
  138. data/lib/mongo/version.rb +1 -1
  139. data/spec/NOTES.aws-auth.md +12 -7
  140. data/spec/README.md +87 -2
  141. data/spec/integration/auth_spec.rb +25 -15
  142. data/spec/integration/bson_symbol_spec.rb +4 -2
  143. data/spec/integration/bulk_write_error_message_spec.rb +41 -0
  144. data/spec/integration/bulk_write_spec.rb +48 -0
  145. data/spec/integration/change_stream_spec.rb +5 -5
  146. data/spec/integration/client_authentication_options_spec.rb +92 -28
  147. data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +6 -2
  148. data/spec/integration/command_monitoring_spec.rb +2 -2
  149. data/spec/integration/connection_pool_populator_spec.rb +4 -2
  150. data/spec/integration/connection_spec.rb +2 -0
  151. data/spec/integration/cursor_reaping_spec.rb +54 -18
  152. data/spec/integration/docs_examples_spec.rb +8 -1
  153. data/spec/integration/fork_reconnect_spec.rb +60 -2
  154. data/spec/integration/ocsp_connectivity_spec.rb +26 -0
  155. data/spec/integration/ocsp_verifier_cache_spec.rb +188 -0
  156. data/spec/integration/ocsp_verifier_spec.rb +340 -0
  157. data/spec/integration/operation_failure_code_spec.rb +1 -1
  158. data/spec/integration/operation_failure_message_spec.rb +90 -0
  159. data/spec/integration/query_cache_spec.rb +1045 -0
  160. data/spec/integration/query_cache_transactions_spec.rb +190 -0
  161. data/spec/integration/reconnect_spec.rb +1 -1
  162. data/spec/integration/retryable_writes/retryable_writes_40_and_newer_spec.rb +1 -0
  163. data/spec/integration/retryable_writes/shared/performs_legacy_retries.rb +2 -0
  164. data/spec/integration/sdam_error_handling_spec.rb +86 -1
  165. data/spec/integration/sdam_events_spec.rb +8 -7
  166. data/spec/integration/server_selection_spec.rb +36 -0
  167. data/spec/integration/size_limit_spec.rb +20 -19
  168. data/spec/integration/snappy_compression_spec.rb +25 -0
  169. data/spec/integration/srv_monitoring_spec.rb +39 -4
  170. data/spec/integration/srv_spec.rb +56 -0
  171. data/spec/integration/transactions_examples_spec.rb +23 -7
  172. data/spec/integration/zlib_compression_spec.rb +1 -1
  173. data/spec/integration/zstd_compression_spec.rb +26 -0
  174. data/spec/lite_spec_helper.rb +15 -5
  175. data/spec/mongo/address_spec.rb +16 -12
  176. data/spec/mongo/auth/ldap/conversation_spec.rb +1 -1
  177. data/spec/mongo/auth/ldap_spec.rb +5 -1
  178. data/spec/mongo/auth/scram_negotiation_spec.rb +1 -1
  179. data/spec/mongo/auth/scram_spec.rb +1 -1
  180. data/spec/mongo/auth/user_spec.rb +1 -1
  181. data/spec/mongo/auth/x509/conversation_spec.rb +3 -3
  182. data/spec/mongo/bulk_write_spec.rb +2 -2
  183. data/spec/mongo/caching_cursor_spec.rb +70 -0
  184. data/spec/mongo/client_construction_spec.rb +273 -35
  185. data/spec/mongo/client_encryption_spec.rb +16 -10
  186. data/spec/mongo/client_spec.rb +64 -0
  187. data/spec/mongo/cluster/topology/replica_set_spec.rb +1 -1
  188. data/spec/mongo/cluster/topology/sharded_spec.rb +1 -1
  189. data/spec/mongo/cluster/topology/single_spec.rb +15 -6
  190. data/spec/mongo/cluster/topology/unknown_spec.rb +1 -1
  191. data/spec/mongo/cluster/topology_spec.rb +1 -1
  192. data/spec/mongo/cluster_spec.rb +6 -18
  193. data/spec/mongo/collection/view/change_stream_resume_spec.rb +1 -1
  194. data/spec/mongo/collection/view/explainable_spec.rb +87 -4
  195. data/spec/mongo/collection/view/map_reduce_spec.rb +2 -0
  196. data/spec/mongo/collection/view/readable_spec.rb +50 -0
  197. data/spec/mongo/collection_crud_spec.rb +4357 -0
  198. data/spec/mongo/collection_ddl_spec.rb +534 -0
  199. data/spec/mongo/collection_spec.rb +5 -4787
  200. data/spec/mongo/crypt/auto_decryption_context_spec.rb +1 -1
  201. data/spec/mongo/crypt/auto_encryption_context_spec.rb +1 -1
  202. data/spec/mongo/crypt/binary_spec.rb +1 -6
  203. data/spec/mongo/crypt/binding/binary_spec.rb +1 -6
  204. data/spec/mongo/crypt/binding/context_spec.rb +2 -7
  205. data/spec/mongo/crypt/binding/helpers_spec.rb +1 -6
  206. data/spec/mongo/crypt/binding/mongocrypt_spec.rb +2 -7
  207. data/spec/mongo/crypt/binding/status_spec.rb +1 -6
  208. data/spec/mongo/crypt/binding/version_spec.rb +1 -6
  209. data/spec/mongo/crypt/data_key_context_spec.rb +1 -1
  210. data/spec/mongo/crypt/explicit_decryption_context_spec.rb +1 -1
  211. data/spec/mongo/crypt/explicit_encryption_context_spec.rb +1 -1
  212. data/spec/mongo/crypt/status_spec.rb +1 -6
  213. data/spec/mongo/database_spec.rb +174 -4
  214. data/spec/mongo/error/bulk_write_error_spec.rb +3 -3
  215. data/spec/mongo/error/no_server_available_spec.rb +1 -1
  216. data/spec/mongo/error/parser_spec.rb +37 -6
  217. data/spec/mongo/index/view_spec.rb +8 -2
  218. data/spec/mongo/logger_spec.rb +13 -11
  219. data/spec/mongo/monitoring/event/server_closed_spec.rb +1 -1
  220. data/spec/mongo/monitoring/event/server_heartbeat_failed_spec.rb +1 -1
  221. data/spec/mongo/monitoring/event/server_heartbeat_succeeded_spec.rb +1 -1
  222. data/spec/mongo/monitoring/event/server_opening_spec.rb +1 -1
  223. data/spec/mongo/monitoring/event/topology_changed_spec.rb +1 -1
  224. data/spec/mongo/monitoring/event/topology_closed_spec.rb +1 -1
  225. data/spec/mongo/monitoring/event/topology_opening_spec.rb +1 -1
  226. data/spec/mongo/operation/aggregate_spec.rb +2 -1
  227. data/spec/mongo/operation/collections_info_spec.rb +4 -1
  228. data/spec/mongo/operation/command_spec.rb +6 -3
  229. data/spec/mongo/operation/create_index_spec.rb +6 -3
  230. data/spec/mongo/operation/create_user_spec.rb +6 -3
  231. data/spec/mongo/operation/delete/bulk_spec.rb +9 -6
  232. data/spec/mongo/operation/delete/op_msg_spec.rb +3 -3
  233. data/spec/mongo/operation/delete_spec.rb +11 -7
  234. data/spec/mongo/operation/drop_index_spec.rb +6 -2
  235. data/spec/mongo/operation/find/legacy_spec.rb +3 -1
  236. data/spec/mongo/operation/get_more_spec.rb +3 -1
  237. data/spec/mongo/operation/indexes_spec.rb +5 -1
  238. data/spec/mongo/operation/insert/bulk_spec.rb +10 -7
  239. data/spec/mongo/operation/insert/command_spec.rb +2 -2
  240. data/spec/mongo/operation/insert/op_msg_spec.rb +3 -3
  241. data/spec/mongo/operation/insert_spec.rb +15 -12
  242. data/spec/mongo/operation/map_reduce_spec.rb +5 -2
  243. data/spec/mongo/operation/read_preference_op_msg_spec.rb +1 -1
  244. data/spec/mongo/operation/remove_user_spec.rb +6 -3
  245. data/spec/mongo/operation/result_spec.rb +1 -1
  246. data/spec/mongo/operation/update/bulk_spec.rb +9 -6
  247. data/spec/mongo/operation/update/command_spec.rb +2 -2
  248. data/spec/mongo/operation/update/op_msg_spec.rb +3 -3
  249. data/spec/mongo/operation/update_spec.rb +10 -7
  250. data/spec/mongo/operation/update_user_spec.rb +4 -1
  251. data/spec/mongo/protocol/compressed_spec.rb +26 -12
  252. data/spec/mongo/query_cache_middleware_spec.rb +55 -0
  253. data/spec/mongo/query_cache_spec.rb +280 -0
  254. data/spec/mongo/retryable_spec.rb +3 -2
  255. data/spec/mongo/server/app_metadata_shared.rb +2 -2
  256. data/spec/mongo/server/app_metadata_spec.rb +2 -0
  257. data/spec/mongo/server/connection_pool/populator_spec.rb +3 -1
  258. data/spec/mongo/server/connection_pool_spec.rb +8 -4
  259. data/spec/mongo/server/connection_spec.rb +39 -25
  260. data/spec/mongo/server/description_spec.rb +18 -0
  261. data/spec/mongo/server/monitor/connection_spec.rb +17 -7
  262. data/spec/mongo/server/monitor_spec.rb +9 -1
  263. data/spec/mongo/server_selector_spec.rb +2 -2
  264. data/spec/mongo/server_spec.rb +15 -2
  265. data/spec/mongo/socket/ssl_spec.rb +44 -4
  266. data/spec/mongo/socket_spec.rb +2 -2
  267. data/spec/mongo/tls_context_hooks_spec.rb +37 -0
  268. data/spec/mongo/uri/srv_protocol_spec.rb +64 -33
  269. data/spec/mongo/uri_option_parsing_spec.rb +11 -11
  270. data/spec/mongo/uri_spec.rb +68 -41
  271. data/spec/mongo/utils_spec.rb +39 -0
  272. data/spec/runners/auth.rb +3 -0
  273. data/spec/runners/change_streams/test.rb +1 -1
  274. data/spec/runners/connection_string.rb +31 -124
  275. data/spec/runners/crud/requirement.rb +40 -3
  276. data/spec/runners/crud/test_base.rb +0 -19
  277. data/spec/runners/crud/verifier.rb +8 -0
  278. data/spec/runners/server_selection.rb +1 -1
  279. data/spec/runners/transactions/operation.rb +13 -2
  280. data/spec/runners/transactions/test.rb +3 -2
  281. data/spec/runners/unified.rb +96 -0
  282. data/spec/runners/unified/assertions.rb +249 -0
  283. data/spec/runners/unified/change_stream_operations.rb +26 -0
  284. data/spec/runners/unified/crud_operations.rb +199 -0
  285. data/spec/runners/unified/ddl_operations.rb +96 -0
  286. data/spec/runners/unified/entity_map.rb +39 -0
  287. data/spec/runners/unified/error.rb +25 -0
  288. data/spec/runners/unified/event_subscriber.rb +91 -0
  289. data/spec/runners/unified/exceptions.rb +21 -0
  290. data/spec/runners/unified/grid_fs_operations.rb +55 -0
  291. data/spec/runners/unified/support_operations.rb +250 -0
  292. data/spec/runners/unified/test.rb +393 -0
  293. data/spec/runners/unified/test_group.rb +28 -0
  294. data/spec/runners/unified/using_hash.rb +31 -0
  295. data/spec/shared/LICENSE +20 -0
  296. data/spec/shared/bin/get-mongodb-download-url +17 -0
  297. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  298. data/spec/shared/lib/mrss/cluster_config.rb +218 -0
  299. data/spec/shared/lib/mrss/constraints.rb +346 -0
  300. data/spec/shared/lib/mrss/docker_runner.rb +262 -0
  301. data/spec/shared/lib/mrss/lite_constraints.rb +175 -0
  302. data/spec/shared/lib/mrss/server_version_registry.rb +112 -0
  303. data/spec/shared/lib/mrss/spec_organizer.rb +149 -0
  304. data/spec/shared/lib/mrss/utils.rb +15 -0
  305. data/spec/shared/share/Dockerfile.erb +231 -0
  306. data/spec/shared/shlib/distro.sh +73 -0
  307. data/spec/shared/shlib/server.sh +290 -0
  308. data/spec/shared/shlib/set_env.sh +128 -0
  309. data/spec/solo/clean_exit_spec.rb +21 -0
  310. data/spec/spec_helper.rb +7 -2
  311. data/spec/spec_tests/cmap_spec.rb +7 -3
  312. data/spec/spec_tests/crud_unified_spec.rb +10 -0
  313. data/spec/spec_tests/data/change_streams/change-streams-errors.yml +0 -1
  314. data/spec/spec_tests/data/change_streams/change-streams.yml +0 -2
  315. data/spec/spec_tests/data/cmap/pool-checkout-connection.yml +6 -2
  316. data/spec/spec_tests/data/cmap/pool-create-min-size.yml +3 -0
  317. data/spec/spec_tests/data/connection_string/valid-warnings.yml +24 -0
  318. data/spec/spec_tests/data/crud_unified/estimatedDocumentCount.yml +267 -0
  319. data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-4.9.yml +60 -0
  320. data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount.yml → estimatedDocumentCount-pre4.9.yml} +2 -0
  321. data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-serverErrors-4.9.yml +146 -0
  322. data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount-serverErrors.yml → estimatedDocumentCount-serverErrors-pre4.9.yml} +2 -0
  323. data/spec/spec_tests/data/retryable_reads/listIndexNames.yml +1 -1
  324. data/spec/spec_tests/data/sdam_monitoring/discovered_standalone.yml +1 -3
  325. data/spec/spec_tests/data/sdam_monitoring/standalone.yml +2 -2
  326. data/spec/spec_tests/data/sdam_monitoring/standalone_repeated.yml +2 -2
  327. data/spec/spec_tests/data/sdam_monitoring/standalone_suppress_equal_description_changes.yml +2 -2
  328. data/spec/spec_tests/data/sdam_monitoring/standalone_to_rs_with_me_mismatch.yml +2 -2
  329. data/spec/spec_tests/data/unified/valid-fail/operation-failure.yml +31 -0
  330. data/spec/spec_tests/data/unified/valid-pass/poc-change-streams.yml +220 -0
  331. data/spec/spec_tests/data/unified/valid-pass/poc-command-monitoring.yml +102 -0
  332. data/spec/spec_tests/data/unified/valid-pass/poc-crud.yml +184 -0
  333. data/spec/spec_tests/data/unified/valid-pass/poc-gridfs.yml +155 -0
  334. data/spec/spec_tests/data/unified/valid-pass/poc-retryable-reads.yml +193 -0
  335. data/spec/spec_tests/data/unified/valid-pass/poc-retryable-writes.yml +210 -0
  336. data/spec/spec_tests/data/unified/valid-pass/poc-sessions.yml +215 -0
  337. data/spec/spec_tests/data/unified/valid-pass/poc-transactions-convenient-api.yml +235 -0
  338. data/spec/spec_tests/data/unified/valid-pass/poc-transactions-mongos-pin-auto.yml +169 -0
  339. data/spec/spec_tests/data/unified/valid-pass/poc-transactions.yml +170 -0
  340. data/spec/spec_tests/data/uri_options/auth-options.yml +25 -0
  341. data/spec/spec_tests/data/uri_options/compression-options.yml +7 -4
  342. data/spec/spec_tests/data/uri_options/read-preference-options.yml +24 -0
  343. data/spec/spec_tests/data/uri_options/ruby-connection-options.yml +1 -0
  344. data/spec/spec_tests/data/uri_options/tls-options.yml +160 -4
  345. data/spec/spec_tests/data/versioned_api/crud-api-version-1-strict.yml +416 -0
  346. data/spec/spec_tests/data/versioned_api/crud-api-version-1.yml +409 -0
  347. data/spec/spec_tests/data/versioned_api/runcommand-helper-no-api-version-declared.yml +67 -0
  348. data/spec/spec_tests/data/versioned_api/test-commands-deprecation-errors.yml +47 -0
  349. data/spec/spec_tests/data/versioned_api/test-commands-strict-mode.yml +44 -0
  350. data/spec/spec_tests/data/versioned_api/transaction-handling.yml +180 -0
  351. data/spec/spec_tests/dns_seedlist_discovery_spec.rb +9 -1
  352. data/spec/spec_tests/unified_spec.rb +15 -0
  353. data/spec/spec_tests/uri_options_spec.rb +47 -33
  354. data/spec/spec_tests/versioned_api_spec.rb +10 -0
  355. data/spec/stress/fork_reconnect_stress_spec.rb +1 -1
  356. data/spec/support/certificates/atlas-ocsp-ca.crt +28 -0
  357. data/spec/support/certificates/atlas-ocsp.crt +41 -0
  358. data/spec/support/client_registry_macros.rb +11 -2
  359. data/spec/support/common_shortcuts.rb +59 -0
  360. data/spec/support/constraints.rb +6 -253
  361. data/spec/support/matchers.rb +16 -0
  362. data/spec/support/ocsp +1 -0
  363. data/spec/support/session_registry.rb +52 -0
  364. data/spec/support/shared/session.rb +2 -2
  365. data/spec/support/spec_config.rb +68 -3
  366. data/spec/support/spec_setup.rb +48 -38
  367. data/spec/support/utils.rb +102 -4
  368. metadata +1087 -936
  369. metadata.gz.sig +0 -0
  370. data/lib/mongo/operation/shared/collections_info_or_list_collections.rb +0 -56
  371. data/lib/mongo/operation/shared/op_msg_or_list_indexes_command.rb +0 -47
  372. data/spec/support/child_process_helper.rb +0 -78
  373. data/spec/support/cluster_config.rb +0 -207
  374. data/spec/support/lite_constraints.rb +0 -141
  375. data/spec/support/spec_organizer.rb +0 -129
@@ -44,13 +44,13 @@ module Mongo
44
44
  # @since 2.0.0
45
45
  def create(user_or_name, options = {})
46
46
  user = generate(user_or_name, options)
47
- client.send(:with_session, options) do |session|
47
+ execute_operation(options) do |session|
48
48
  Operation::CreateUser.new(
49
49
  user: user,
50
50
  db_name: database.name,
51
51
  session: session,
52
52
  write_concern: options[:write_concern] && WriteConcern.get(options[:write_concern]),
53
- ).execute(next_primary(nil, session), client: client)
53
+ )
54
54
  end
55
55
  end
56
56
 
@@ -81,13 +81,13 @@ module Mongo
81
81
  #
82
82
  # @since 2.0.0
83
83
  def remove(name, options = {})
84
- client.send(:with_session, options) do |session|
84
+ execute_operation(options) do |session|
85
85
  Operation::RemoveUser.new(
86
86
  user_name: name,
87
87
  db_name: database.name,
88
88
  session: session,
89
89
  write_concern: options[:write_concern] && WriteConcern.get(options[:write_concern]),
90
- ).execute(next_primary(nil, session), client: client)
90
+ )
91
91
  end
92
92
  end
93
93
 
@@ -106,14 +106,14 @@ module Mongo
106
106
  #
107
107
  # @since 2.0.0
108
108
  def update(user_or_name, options = {})
109
- client.send(:with_session, options) do |session|
110
- user = generate(user_or_name, options)
109
+ user = generate(user_or_name, options)
110
+ execute_operation(options) do |session|
111
111
  Operation::UpdateUser.new(
112
112
  user: user,
113
113
  db_name: database.name,
114
114
  session: session,
115
115
  write_concern: options[:write_concern] && WriteConcern.get(options[:write_concern]),
116
- ).execute(next_primary(nil, session), client: client)
116
+ )
117
117
  end
118
118
  end
119
119
 
@@ -137,18 +137,25 @@ module Mongo
137
137
  private
138
138
 
139
139
  def user_query(name, options = {})
140
- client.send(:with_session, options) do |session|
140
+ execute_operation(options) do |session|
141
141
  Operation::UsersInfo.new(
142
142
  user_name: name,
143
143
  db_name: database.name,
144
144
  session: session
145
- ).execute(next_primary(nil, session), client: client)
145
+ )
146
146
  end
147
147
  end
148
148
 
149
149
  def generate(user, options)
150
150
  user.is_a?(String) ? Auth::User.new({ user: user }.merge(options)) : user
151
151
  end
152
+
153
+ def execute_operation(options)
154
+ client.send(:with_session, options) do |session|
155
+ op = yield session
156
+ op.execute(next_primary(nil, session), context: Operation::Context.new(client: client, session: session))
157
+ end
158
+ end
152
159
  end
153
160
  end
154
161
  end
@@ -34,34 +34,13 @@ module Mongo
34
34
  # @param [ Server::Connection ] connection The connection being
35
35
  # authenticated.
36
36
  #
37
- # @return [ Protocol::Query ] The first X.509 conversation message.
37
+ # @return [ Protocol::Message ] The first X.509 conversation message.
38
38
  #
39
39
  # @since 2.0.0
40
40
  def start(connection)
41
- login = client_first_document
42
- if connection && connection.features.op_msg_enabled?
43
- selector = login
44
- # The only valid database for X.509 authentication is $external.
45
- if user.auth_source != '$external'
46
- user_name_msg = if user.name
47
- " #{user.name}"
48
- else
49
- ''
50
- end
51
- raise Auth::InvalidConfiguration, "User#{user_name_msg} specifies auth source '#{user.auth_source}', but the only valid auth source for X.509 is '$external'"
52
- end
53
- selector[Protocol::Msg::DATABASE_IDENTIFIER] = '$external'
54
- cluster_time = connection.mongos? && connection.cluster_time
55
- selector[Operation::CLUSTER_TIME] = cluster_time if cluster_time
56
- Protocol::Msg.new([], {}, selector)
57
- else
58
- Protocol::Query.new(
59
- Auth::EXTERNAL,
60
- Database::COMMAND,
61
- login,
62
- limit: -1
63
- )
64
- end
41
+ validate_external_auth_source
42
+ selector = client_first_document
43
+ build_message(connection, '$external', selector)
65
44
  end
66
45
 
67
46
  # Returns the hash to provide to the server in the handshake
@@ -20,6 +20,17 @@ module Mongo
20
20
  # compatibility reasons. However using these methods outside of the driver
21
21
  # is deprecated.
22
22
  #
23
+ # @note Do not start or stop background threads in finalizers. See
24
+ # https://jira.mongodb.org/browse/RUBY-2453 and
25
+ # https://bugs.ruby-lang.org/issues/16288. When interpreter exits,
26
+ # background threads are stopped first and finalizers are invoked next,
27
+ # and MRI's internal data structures are basically corrupt at this point
28
+ # if threads are being referenced. Prior to interpreter shutdown this
29
+ # means threads cannot be stopped by objects going out of scope, but
30
+ # most likely the threads hold references to said objects anyway if
31
+ # work is being performed thus the objects wouldn't go out of scope in
32
+ # the first place.
33
+ #
23
34
  # @api private
24
35
  module BackgroundThread
25
36
  include Loggable
@@ -58,6 +58,7 @@ module Mongo
58
58
  operations = op_combiner.combine
59
59
 
60
60
  client.send(:with_session, @options) do |session|
61
+ context = Operation::Context.new(client: client, session: session)
61
62
  operations.each do |operation|
62
63
  if single_statement?(operation)
63
64
  write_concern = write_concern(session)
@@ -67,6 +68,7 @@ module Mongo
67
68
  operation.keys.first,
68
69
  operation.values.flatten,
69
70
  connection,
71
+ context,
70
72
  operation_id,
71
73
  result_combiner,
72
74
  session,
@@ -80,6 +82,7 @@ module Mongo
80
82
  operation.keys.first,
81
83
  operation.values.flatten,
82
84
  connection,
85
+ context,
83
86
  operation_id,
84
87
  result_combiner,
85
88
  session)
@@ -177,28 +180,35 @@ module Mongo
177
180
  }
178
181
  end
179
182
 
180
- def execute_operation(name, values, connection, operation_id, result_combiner, session, txn_num = nil)
183
+ def execute_operation(name, values, connection, context, operation_id, result_combiner, session, txn_num = nil)
181
184
  validate_collation!(connection)
182
185
  validate_array_filters!(connection)
183
186
  validate_hint!(connection)
184
187
 
185
188
  unpin_maybe(session) do
186
189
  if values.size > connection.description.max_write_batch_size
187
- split_execute(name, values, connection, operation_id, result_combiner, session, txn_num)
190
+ split_execute(name, values, connection, context, operation_id, result_combiner, session, txn_num)
188
191
  else
189
- result = send(name, values, connection, operation_id, session, txn_num)
192
+ result = send(name, values, connection, context, operation_id, session, txn_num)
190
193
 
191
194
  add_server_diagnostics(connection) do
192
- add_error_labels(client, connection, session) do
195
+ add_error_labels(connection, context) do
193
196
  result_combiner.combine!(result, values.size)
194
197
  end
195
198
  end
196
199
  end
197
200
  end
201
+ # With OP_MSG (3.6+ servers), the size of each section in the message
202
+ # is independently capped at 16m and each bulk operation becomes
203
+ # its own section. The size of the entire bulk write is limited to 48m.
204
+ # With OP_QUERY (pre-3.6 servers), the entire bulk write is sent as a
205
+ # single document and is thus subject to the 16m document size limit.
206
+ # This means the splits differ between pre-3.6 and 3.6+ servers, with
207
+ # 3.6+ servers being able to split less.
198
208
  rescue Error::MaxBSONSize, Error::MaxMessageSize => e
199
209
  raise e if values.size <= 1
200
210
  unpin_maybe(session) do
201
- split_execute(name, values, connection, operation_id, result_combiner, session, txn_num)
211
+ split_execute(name, values, connection, context, operation_id, result_combiner, session, txn_num)
202
212
  end
203
213
  end
204
214
 
@@ -206,37 +216,47 @@ module Mongo
206
216
  @op_combiner ||= ordered? ? OrderedCombiner.new(requests) : UnorderedCombiner.new(requests)
207
217
  end
208
218
 
209
- def split_execute(name, values, connection, operation_id, result_combiner, session, txn_num)
210
- execute_operation(name, values.shift(values.size / 2), connection, operation_id, result_combiner, session, txn_num)
219
+ def split_execute(name, values, connection, context, operation_id, result_combiner, session, txn_num)
220
+ execute_operation(name, values.shift(values.size / 2), connection, context, operation_id, result_combiner, session, txn_num)
211
221
 
212
222
  txn_num = session.next_txn_num if txn_num
213
- execute_operation(name, values, connection, operation_id, result_combiner, session, txn_num)
223
+ execute_operation(name, values, connection, context, operation_id, result_combiner, session, txn_num)
214
224
  end
215
225
 
216
- def delete_one(documents, connection, operation_id, session, txn_num)
226
+ def delete_one(documents, connection, context, operation_id, session, txn_num)
227
+ QueryCache.clear_namespace(collection.namespace)
228
+
217
229
  spec = base_spec(operation_id, session).merge(:deletes => documents, :txn_num => txn_num)
218
- Operation::Delete.new(spec).bulk_execute(connection, client: client)
230
+ Operation::Delete.new(spec).bulk_execute(connection, context: context)
219
231
  end
220
232
 
221
- def delete_many(documents, connection, operation_id, session, txn_num)
233
+ def delete_many(documents, connection, context, operation_id, session, txn_num)
234
+ QueryCache.clear_namespace(collection.namespace)
235
+
222
236
  spec = base_spec(operation_id, session).merge(:deletes => documents)
223
- Operation::Delete.new(spec).bulk_execute(connection, client: client)
237
+ Operation::Delete.new(spec).bulk_execute(connection, context: context)
224
238
  end
225
239
 
226
- def insert_one(documents, connection, operation_id, session, txn_num)
240
+ def insert_one(documents, connection, context, operation_id, session, txn_num)
241
+ QueryCache.clear_namespace(collection.namespace)
242
+
227
243
  spec = base_spec(operation_id, session).merge(:documents => documents, :txn_num => txn_num)
228
- Operation::Insert.new(spec).bulk_execute(connection, client: client)
244
+ Operation::Insert.new(spec).bulk_execute(connection, context: context)
229
245
  end
230
246
 
231
- def update_one(documents, connection, operation_id, session, txn_num)
247
+ def update_one(documents, connection, context, operation_id, session, txn_num)
248
+ QueryCache.clear_namespace(collection.namespace)
249
+
232
250
  spec = base_spec(operation_id, session).merge(:updates => documents, :txn_num => txn_num)
233
- Operation::Update.new(spec).bulk_execute(connection, client: client)
251
+ Operation::Update.new(spec).bulk_execute(connection, context: context)
234
252
  end
235
253
  alias :replace_one :update_one
236
254
 
237
- def update_many(documents, connection, operation_id, session, txn_num)
255
+ def update_many(documents, connection, context, operation_id, session, txn_num)
256
+ QueryCache.clear_namespace(collection.namespace)
257
+
238
258
  spec = base_spec(operation_id, session).merge(:updates => documents)
239
- Operation::Update.new(spec).bulk_execute(connection, client: client)
259
+ Operation::Update.new(spec).bulk_execute(connection, context: context)
240
260
  end
241
261
 
242
262
  private
@@ -0,0 +1,74 @@
1
+ # Copyright (C) 2020 MongoDB Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+
17
+ # A Cursor that attempts to load documents from memory first before hitting
18
+ # the database if the same query has already been executed.
19
+ #
20
+ # @api semiprivate
21
+ class CachingCursor < Cursor
22
+
23
+ # @return [ Array <BSON::Document> ] The cursor's cached documents.
24
+ # @api private
25
+ attr_reader :cached_docs
26
+
27
+ # We iterate over the cached documents if they exist already in the
28
+ # cursor otherwise proceed as normal.
29
+ #
30
+ # @example Iterate over the documents.
31
+ # cursor.each do |doc|
32
+ # # ...
33
+ # end
34
+ def each
35
+ if @cached_docs
36
+ @cached_docs.each do |doc|
37
+ yield doc
38
+ end
39
+
40
+ unless closed?
41
+ # StopIteration raised by try_next ends this loop.
42
+ loop do
43
+ document = try_next
44
+ yield document if document
45
+ end
46
+ end
47
+ else
48
+ super
49
+ end
50
+ end
51
+
52
+ # Get a human-readable string representation of +Cursor+.
53
+ #
54
+ # @example Inspect the cursor.
55
+ # cursor.inspect
56
+ #
57
+ # @return [ String ] A string representation of a +Cursor+ instance.
58
+ def inspect
59
+ "#<Mongo::CachingCursor:0x#{object_id} @view=#{@view.inspect}>"
60
+ end
61
+
62
+ # Acquires the next document for cursor iteration and then
63
+ # inserts that document in the @cached_docs array.
64
+ #
65
+ # @api private
66
+ def try_next
67
+ @cached_docs ||= []
68
+ document = super
69
+ @cached_docs << document if document
70
+
71
+ document
72
+ end
73
+ end
74
+ end
data/lib/mongo/client.rb CHANGED
@@ -85,6 +85,7 @@ module Mongo
85
85
  :retry_writes,
86
86
  :scan,
87
87
  :sdam_proc,
88
+ :server_api,
88
89
  :server_selection_timeout,
89
90
  :socket_timeout,
90
91
  :ssl,
@@ -101,6 +102,7 @@ module Mongo
101
102
  :ssl_verify,
102
103
  :ssl_verify_certificate,
103
104
  :ssl_verify_hostname,
105
+ :ssl_verify_ocsp_endpoint,
104
106
  :truncate_logs,
105
107
  :user,
106
108
  :wait_queue_timeout,
@@ -113,7 +115,16 @@ module Mongo
113
115
  # The compression algorithms supported by the driver.
114
116
  #
115
117
  # @since 2.5.0
116
- VALID_COMPRESSORS = [ Mongo::Protocol::Compressed::ZLIB ].freeze
118
+ VALID_COMPRESSORS = [
119
+ Mongo::Protocol::Compressed::ZSTD,
120
+ Mongo::Protocol::Compressed::SNAPPY,
121
+ Mongo::Protocol::Compressed::ZLIB
122
+ ].freeze
123
+
124
+ # The known server API versions.
125
+ VALID_SERVER_API_VERSIONS = %w(
126
+ 1
127
+ ).freeze
117
128
 
118
129
  # @return [ Mongo::Cluster ] cluster The cluster of servers for the client.
119
130
  attr_reader :cluster
@@ -222,7 +233,7 @@ module Mongo
222
233
  # @option options [ Array<String> ] :compressors A list of potential
223
234
  # compressors to use, in order of preference. The driver chooses the
224
235
  # first compressor that is also supported by the server. Currently the
225
- # driver only supports 'zlib'.
236
+ # driver only supports 'zstd, 'snappy' and 'zlib'.
226
237
  # @option options [ true | false ] :direct_connection Whether to connect
227
238
  # directly to the specified seed, bypassing topology discovery. Exactly
228
239
  # one seed must be provided.
@@ -311,11 +322,16 @@ module Mongo
311
322
  # in particular the cluster is nil at this time. sdam_proc should
312
323
  # limit itself to calling #subscribe and #unsubscribe methods on the
313
324
  # client only.
325
+ # @option options [ Hash ] :server_api The requested server API version.
326
+ # This hash can have the following items:
327
+ # - *:version* -- string
328
+ # - *:strict* -- boolean
329
+ # - *:deprecation_errors* -- boolean
314
330
  # @option options [ Integer ] :server_selection_timeout The timeout in seconds
315
331
  # for selecting a server for an operation.
316
332
  # @option options [ Float ] :socket_timeout The timeout, in seconds, to
317
333
  # execute operations on a socket.
318
- # @option options [ true, false ] :ssl Whether to use SSL.
334
+ # @option options [ true, false ] :ssl Whether to use TLS.
319
335
  # @option options [ String ] :ssl_ca_cert The file containing concatenated
320
336
  # certificate authority certificates used to validate certs passed from the
321
337
  # other end of the connection. Intermediate certificates should NOT be
@@ -462,11 +478,42 @@ module Mongo
462
478
  @srv_records = nil
463
479
  end
464
480
 
481
+ options = self.class.canonicalize_ruby_options(options)
482
+
483
+ # The server API version is specified to be a string.
484
+ # However, it is very annoying to always provide the number 1 as a string,
485
+ # therefore cast to the string type here.
486
+ if server_api = options[:server_api]
487
+ if server_api.is_a?(Hash)
488
+ server_api = Options::Redacted.new(server_api)
489
+ if (version = server_api[:version]).is_a?(Integer)
490
+ options[:server_api] = server_api.merge(version: version.to_s)
491
+ end
492
+ end
493
+ end
494
+
465
495
  # Special handling for sdam_proc as it is only used during client
466
496
  # construction
467
497
  sdam_proc = options.delete(:sdam_proc)
468
498
 
469
- options = default_options(options).merge(options)
499
+ # For gssapi service_name, the default option is given in a hash
500
+ # (one level down from the top level).
501
+ merged_options = default_options(options)
502
+ options.each do |k, v|
503
+ default_v = merged_options[k]
504
+ if Hash === default_v
505
+ v = default_v.merge(v)
506
+ end
507
+ merged_options[k] = v
508
+ end
509
+ options = merged_options
510
+
511
+ options.keys.each do |k|
512
+ if options[k].nil?
513
+ options.delete(k)
514
+ end
515
+ end
516
+
470
517
  @options = validate_new_options!(options)
471
518
  =begin WriteConcern object support
472
519
  if @options[:write_concern].is_a?(WriteConcern::Base)
@@ -479,7 +526,9 @@ module Mongo
479
526
  validate_options!(addresses)
480
527
  validate_authentication_options!
481
528
 
482
- @database = Database.new(self, @options[:database], @options)
529
+ database_options = @options.dup
530
+ database_options.delete(:server_api)
531
+ @database = Database.new(self, @options[:database], database_options)
483
532
 
484
533
  # Temporarily set monitoring so that event subscriptions can be
485
534
  # set up without there being a cluster
@@ -594,15 +643,12 @@ module Mongo
594
643
 
595
644
  # Get a summary of the client state.
596
645
  #
597
- # @note This method is experimental and subject to change.
598
- #
599
- # @example Inspect the client.
600
- # client.summary
646
+ # @note The exact format and layout of the returned summary string is
647
+ # not part of the driver's public API and may be changed at any time.
601
648
  #
602
- # @return [ String ] Summary string.
649
+ # @return [ String ] The summary string.
603
650
  #
604
651
  # @since 2.7.0
605
- # @api experimental
606
652
  def summary
607
653
  "#<Client cluster=#{cluster.summary}>"
608
654
  end
@@ -632,7 +678,7 @@ module Mongo
632
678
  #
633
679
  # @return [ BSON::Document ] The user-defined read preference.
634
680
  # The document may have the following fields:
635
- # - *:read* -- read preference specified as a symbol; valid values are
681
+ # - *:mode* -- read preference specified as a symbol; valid values are
636
682
  # *:primary*, *:primary_preferred*, *:secondary*, *:secondary_preferred*
637
683
  # and *:nearest*.
638
684
  # - *:tag_sets* -- an array of hashes.
@@ -680,9 +726,9 @@ module Mongo
680
726
  # @return [ Mongo::Client ] A new client instance.
681
727
  #
682
728
  # @since 2.0.0
683
- def with(new_options = Options::Redacted.new)
729
+ def with(new_options = nil)
684
730
  clone.tap do |client|
685
- opts = client.update_options(new_options)
731
+ opts = client.update_options(new_options || Options::Redacted.new)
686
732
  Database.create(client)
687
733
  # We can't use the same cluster if some options that would affect it
688
734
  # have changed.
@@ -709,6 +755,8 @@ module Mongo
709
755
  def update_options(new_options)
710
756
  old_options = @options
711
757
 
758
+ new_options = self.class.canonicalize_ruby_options(new_options || {})
759
+
712
760
  validate_new_options!(new_options).tap do |opts|
713
761
  # Our options are frozen
714
762
  options = @options.dup
@@ -758,7 +806,6 @@ module Mongo
758
806
  options[:read_concern]
759
807
  end
760
808
 
761
-
762
809
  # Get the write concern for this client. If no option was provided, then a
763
810
  # default single server acknowledgement will be used.
764
811
  #
@@ -1011,6 +1058,23 @@ module Mongo
1011
1058
  end
1012
1059
  end
1013
1060
 
1061
+ class << self
1062
+ # Lowercases auth mechanism properties, if given, in the specified
1063
+ # options, then converts the options to an instance of Options::Redacted.
1064
+ #
1065
+ # @api private
1066
+ def canonicalize_ruby_options(options)
1067
+ Options::Redacted.new(Hash[options.map do |k, v|
1068
+ if k == :auth_mech_properties || k == 'auth_mech_properties'
1069
+ if v
1070
+ v = Hash[v.map { |pk, pv| [pk.downcase, pv] }]
1071
+ end
1072
+ end
1073
+ [k, v]
1074
+ end])
1075
+ end
1076
+ end
1077
+
1014
1078
  private
1015
1079
 
1016
1080
  # Create a new encrypter object using the client's auto encryption options
@@ -1094,8 +1158,42 @@ module Mongo
1094
1158
  # The argument may contain a subset of options that the client will
1095
1159
  # eventually have; this method validates each of the provided options
1096
1160
  # but does not check for interactions between combinations of options.
1097
- def validate_new_options!(opts = Options::Redacted.new)
1161
+ def validate_new_options!(opts)
1098
1162
  return Options::Redacted.new unless opts
1163
+ if opts[:read_concern]
1164
+ # Raise an error for non user-settable options
1165
+ if opts[:read_concern][:after_cluster_time]
1166
+ raise Mongo::Error::InvalidReadConcern.new(
1167
+ 'The after_cluster_time read_concern option cannot be specified by the user'
1168
+ )
1169
+ end
1170
+
1171
+ given_keys = opts[:read_concern].keys.map(&:to_s)
1172
+ allowed_keys = ['level']
1173
+ invalid_keys = given_keys - allowed_keys
1174
+ # Warn that options are invalid but keep it and forward to the server
1175
+ unless invalid_keys.empty?
1176
+ log_warn("Read concern has invalid keys: #{invalid_keys.join(',')}.")
1177
+ end
1178
+ end
1179
+
1180
+ if server_api = opts[:server_api]
1181
+ unless server_api.is_a?(Hash)
1182
+ raise ArgumentError, ":server_api value must be a hash: #{server_api}"
1183
+ end
1184
+
1185
+ extra_keys = server_api.keys - %w(version strict deprecation_errors)
1186
+ unless extra_keys.empty?
1187
+ raise ArgumentError, "Unknown keys under :server_api: #{extra_keys.map(&:inspect).join(', ')}"
1188
+ end
1189
+
1190
+ if version = server_api[:version]
1191
+ unless VALID_SERVER_API_VERSIONS.include?(version)
1192
+ raise ArgumentError, "Unknown server API version: #{version}"
1193
+ end
1194
+ end
1195
+ end
1196
+
1099
1197
  Lint.validate_underscore_read_preference(opts[:read])
1100
1198
  Lint.validate_read_concern_option(opts[:read_concern])
1101
1199
  opts.each.inject(Options::Redacted.new) do |_options, (k, v)|
@@ -1105,6 +1203,15 @@ module Mongo
1105
1203
  validate_read!(key, opts)
1106
1204
  if key == :compressors
1107
1205
  compressors = valid_compressors(v)
1206
+
1207
+ if compressors.include?('snappy')
1208
+ validate_snappy_compression!
1209
+ end
1210
+
1211
+ if compressors.include?('zstd')
1212
+ validate_zstd_compression!
1213
+ end
1214
+
1108
1215
  _options[key] = compressors unless compressors.empty?
1109
1216
  else
1110
1217
  _options[key] = v
@@ -1261,11 +1368,30 @@ module Mongo
1261
1368
  "This compressor will not be used.")
1262
1369
  false
1263
1370
  else
1371
+
1264
1372
  true
1265
1373
  end
1266
1374
  end
1267
1375
  end
1268
1376
 
1377
+ def validate_snappy_compression!
1378
+ return if defined?(Snappy)
1379
+ require 'snappy'
1380
+ rescue LoadError => e
1381
+ raise Error::UnmetDependency, "Cannot enable snappy compression because the snappy gem " \
1382
+ "has not been installed. Add \"gem 'snappy'\" to your Gemfile and run " \
1383
+ "\"bundle install\" to install the gem. (#{e.class}: #{e})"
1384
+ end
1385
+
1386
+ def validate_zstd_compression!
1387
+ return if defined?(Zstd)
1388
+ require 'zstd-ruby'
1389
+ rescue LoadError => e
1390
+ raise Error::UnmetDependency, "Cannot enable zstd compression because the zstd-ruby gem " \
1391
+ "has not been installed. Add \"gem 'zstd-ruby'\" to your Gemfile and run " \
1392
+ "\"bundle install\" to install the gem. (#{e.class}: #{e})"
1393
+ end
1394
+
1269
1395
  def validate_max_min_pool_size!(option, opts)
1270
1396
  if option == :min_pool_size && opts[:min_pool_size]
1271
1397
  max = opts[:max_pool_size] || Server::ConnectionPool::DEFAULT_MAX_SIZE