mongo 2.11.4 → 2.18.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (1659) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CONTRIBUTING.md +8 -36
  4. data/LICENSE +1 -1
  5. data/README.md +65 -77
  6. data/Rakefile +58 -24
  7. data/lib/mongo/active_support.rb +4 -1
  8. data/lib/mongo/address/ipv4.rb +35 -5
  9. data/lib/mongo/address/ipv6.rb +35 -5
  10. data/lib/mongo/address/unix.rb +6 -3
  11. data/lib/mongo/address/validator.rb +4 -1
  12. data/lib/mongo/address.rb +81 -26
  13. data/lib/mongo/auth/aws/conversation.rb +128 -0
  14. data/lib/mongo/auth/aws/credentials_retriever.rb +222 -0
  15. data/lib/mongo/auth/aws/request.rb +285 -0
  16. data/lib/mongo/auth/aws.rb +40 -0
  17. data/lib/mongo/auth/base.rb +145 -0
  18. data/lib/mongo/auth/conversation_base.rb +87 -0
  19. data/lib/mongo/auth/cr/conversation.rb +21 -86
  20. data/lib/mongo/auth/cr.rb +12 -36
  21. data/lib/mongo/auth/credential_cache.rb +54 -0
  22. data/lib/mongo/auth/gssapi/conversation.rb +100 -0
  23. data/lib/mongo/auth/gssapi.rb +41 -0
  24. data/lib/mongo/auth/ldap/conversation.rb +9 -57
  25. data/lib/mongo/auth/ldap.rb +12 -34
  26. data/lib/mongo/auth/roles.rb +4 -1
  27. data/lib/mongo/auth/sasl_conversation_base.rb +102 -0
  28. data/lib/mongo/auth/scram/conversation.rb +15 -502
  29. data/lib/mongo/auth/scram.rb +42 -51
  30. data/lib/mongo/auth/scram256/conversation.rb +66 -0
  31. data/lib/mongo/auth/scram256.rb +34 -0
  32. data/lib/mongo/auth/scram_conversation_base.rb +378 -0
  33. data/lib/mongo/auth/stringprep/profiles/sasl.rb +5 -1
  34. data/lib/mongo/auth/stringprep/tables.rb +5 -1
  35. data/lib/mongo/auth/stringprep/unicode_normalize/normalize.rb +3 -2
  36. data/lib/mongo/auth/stringprep/unicode_normalize/tables.rb +2 -1
  37. data/lib/mongo/auth/stringprep.rb +9 -5
  38. data/lib/mongo/auth/user/view.rb +20 -10
  39. data/lib/mongo/auth/user.rb +5 -10
  40. data/lib/mongo/auth/x509/conversation.rb +21 -66
  41. data/lib/mongo/auth/x509.rb +17 -32
  42. data/lib/mongo/auth.rb +52 -14
  43. data/lib/mongo/background_thread.rb +27 -4
  44. data/lib/mongo/bson.rb +4 -1
  45. data/lib/mongo/bulk_write/combineable.rb +23 -8
  46. data/lib/mongo/bulk_write/ordered_combiner.rb +4 -1
  47. data/lib/mongo/bulk_write/result.rb +14 -2
  48. data/lib/mongo/bulk_write/result_combiner.rb +6 -5
  49. data/lib/mongo/bulk_write/transformable.rb +12 -10
  50. data/lib/mongo/bulk_write/unordered_combiner.rb +4 -1
  51. data/lib/mongo/bulk_write/validatable.rb +8 -1
  52. data/lib/mongo/bulk_write.rb +187 -42
  53. data/lib/mongo/caching_cursor.rb +77 -0
  54. data/lib/mongo/client.rb +669 -68
  55. data/lib/mongo/client_encryption.rb +209 -0
  56. data/lib/mongo/cluster/periodic_executor.rb +8 -4
  57. data/lib/mongo/cluster/reapers/cursor_reaper.rb +120 -46
  58. data/lib/mongo/cluster/reapers/socket_reaper.rb +4 -1
  59. data/lib/mongo/cluster/sdam_flow.rb +112 -74
  60. data/lib/mongo/cluster/topology/base.rb +17 -10
  61. data/lib/mongo/cluster/topology/load_balanced.rb +102 -0
  62. data/lib/mongo/cluster/topology/no_replica_set_options.rb +4 -1
  63. data/lib/mongo/cluster/topology/replica_set_no_primary.rb +7 -3
  64. data/lib/mongo/cluster/topology/replica_set_with_primary.rb +4 -1
  65. data/lib/mongo/cluster/topology/sharded.rb +5 -2
  66. data/lib/mongo/cluster/topology/single.rb +6 -3
  67. data/lib/mongo/cluster/topology/unknown.rb +4 -1
  68. data/lib/mongo/cluster/topology.rb +44 -4
  69. data/lib/mongo/cluster.rb +344 -155
  70. data/lib/mongo/cluster_time.rb +4 -1
  71. data/lib/mongo/collection/helpers.rb +43 -0
  72. data/lib/mongo/collection/queryable_encryption.rb +122 -0
  73. data/lib/mongo/collection/view/aggregation.rb +96 -23
  74. data/lib/mongo/collection/view/builder/aggregation.rb +20 -18
  75. data/lib/mongo/collection/view/builder/map_reduce.rb +19 -50
  76. data/lib/mongo/collection/view/builder.rb +4 -5
  77. data/lib/mongo/collection/view/change_stream/retryable.rb +4 -1
  78. data/lib/mongo/collection/view/change_stream.rb +83 -28
  79. data/lib/mongo/collection/view/explainable.rb +31 -9
  80. data/lib/mongo/collection/view/immutable.rb +4 -1
  81. data/lib/mongo/collection/view/iterable.rb +135 -23
  82. data/lib/mongo/collection/view/map_reduce.rb +78 -24
  83. data/lib/mongo/collection/view/readable.rb +162 -71
  84. data/lib/mongo/collection/view/writable.rb +356 -140
  85. data/lib/mongo/collection/view.rb +47 -42
  86. data/lib/mongo/collection.rb +244 -68
  87. data/lib/mongo/config/options.rb +62 -0
  88. data/lib/mongo/config/validators/option.rb +26 -0
  89. data/lib/mongo/config.rb +42 -0
  90. data/lib/mongo/crypt/auto_decryption_context.rb +43 -0
  91. data/lib/mongo/crypt/auto_encrypter.rb +304 -0
  92. data/lib/mongo/crypt/auto_encryption_context.rb +47 -0
  93. data/lib/mongo/crypt/binary.rb +158 -0
  94. data/lib/mongo/crypt/binding.rb +1601 -0
  95. data/lib/mongo/crypt/context.rb +141 -0
  96. data/lib/mongo/crypt/data_key_context.rb +73 -0
  97. data/lib/mongo/crypt/encryption_io.rb +343 -0
  98. data/lib/mongo/crypt/explicit_decryption_context.rb +43 -0
  99. data/lib/mongo/crypt/explicit_encrypter.rb +237 -0
  100. data/lib/mongo/crypt/explicit_encryption_context.rb +115 -0
  101. data/lib/mongo/crypt/handle.rb +392 -0
  102. data/lib/mongo/crypt/hooks.rb +116 -0
  103. data/lib/mongo/crypt/kms/aws.rb +136 -0
  104. data/lib/mongo/crypt/kms/azure.rb +144 -0
  105. data/lib/mongo/crypt/kms/credentials.rb +81 -0
  106. data/lib/mongo/crypt/kms/gcp.rb +189 -0
  107. data/lib/mongo/crypt/kms/kmip.rb +116 -0
  108. data/lib/mongo/crypt/kms/local.rb +82 -0
  109. data/lib/mongo/crypt/kms/master_key_document.rb +65 -0
  110. data/lib/mongo/crypt/kms.rb +117 -0
  111. data/lib/mongo/crypt/kms_context.rb +70 -0
  112. data/lib/mongo/crypt/rewrap_many_data_key_context.rb +46 -0
  113. data/lib/mongo/crypt/rewrap_many_data_key_result.rb +37 -0
  114. data/lib/mongo/crypt/status.rb +140 -0
  115. data/lib/mongo/crypt.rb +39 -0
  116. data/lib/mongo/cursor/kill_spec.rb +76 -0
  117. data/lib/mongo/cursor.rb +175 -70
  118. data/lib/mongo/database/view.rb +41 -9
  119. data/lib/mongo/database.rb +142 -25
  120. data/lib/mongo/dbref.rb +5 -99
  121. data/lib/mongo/distinguishing_semaphore.rb +58 -0
  122. data/lib/mongo/error/auth_error.rb +4 -1
  123. data/lib/mongo/error/bad_load_balancer_target.rb +26 -0
  124. data/lib/mongo/error/bulk_write_error.rb +60 -14
  125. data/lib/mongo/error/change_stream_resumable.rb +4 -1
  126. data/lib/mongo/error/closed_stream.rb +4 -1
  127. data/lib/mongo/error/connection_check_out_timeout.rb +4 -1
  128. data/lib/mongo/error/connection_perished.rb +26 -0
  129. data/lib/mongo/error/credential_check_error.rb +29 -0
  130. data/lib/mongo/error/crypt_error.rb +34 -0
  131. data/lib/mongo/error/extra_file_chunk.rb +4 -1
  132. data/lib/mongo/error/{failed_stringprep_validation.rb → failed_string_prep_validation.rb} +3 -0
  133. data/lib/mongo/error/file_not_found.rb +4 -1
  134. data/lib/mongo/error/handshake_error.rb +4 -1
  135. data/lib/mongo/error/insufficient_iteration_count.rb +4 -1
  136. data/lib/mongo/error/internal_driver_error.rb +25 -0
  137. data/lib/mongo/error/invalid_address.rb +4 -1
  138. data/lib/mongo/error/invalid_application_name.rb +4 -1
  139. data/lib/mongo/error/invalid_bulk_operation.rb +4 -1
  140. data/lib/mongo/error/invalid_bulk_operation_type.rb +4 -1
  141. data/lib/mongo/error/invalid_collection_name.rb +4 -1
  142. data/lib/mongo/error/invalid_config_option.rb +20 -0
  143. data/lib/mongo/error/invalid_cursor_operation.rb +30 -0
  144. data/lib/mongo/error/invalid_database_name.rb +4 -1
  145. data/lib/mongo/error/invalid_document.rb +4 -1
  146. data/lib/mongo/error/invalid_file.rb +4 -1
  147. data/lib/mongo/error/invalid_file_revision.rb +4 -1
  148. data/lib/mongo/error/invalid_min_pool_size.rb +4 -1
  149. data/lib/mongo/error/invalid_nonce.rb +5 -2
  150. data/lib/mongo/error/invalid_read_concern.rb +31 -0
  151. data/lib/mongo/error/invalid_read_option.rb +4 -1
  152. data/lib/mongo/error/invalid_replacement_document.rb +31 -10
  153. data/lib/mongo/error/invalid_server_auth_host.rb +25 -0
  154. data/lib/mongo/error/invalid_server_auth_response.rb +26 -0
  155. data/lib/mongo/error/invalid_server_preference.rb +9 -1
  156. data/lib/mongo/error/invalid_session.rb +6 -2
  157. data/lib/mongo/error/invalid_signature.rb +4 -1
  158. data/lib/mongo/error/invalid_transaction_operation.rb +4 -1
  159. data/lib/mongo/error/invalid_txt_record.rb +4 -1
  160. data/lib/mongo/error/invalid_update_document.rb +31 -8
  161. data/lib/mongo/error/invalid_uri.rb +4 -1
  162. data/lib/mongo/error/invalid_write_concern.rb +4 -1
  163. data/{spec/support/crud/context.rb → lib/mongo/error/kms_error.rb} +8 -6
  164. data/lib/mongo/error/labelable.rb +72 -0
  165. data/lib/mongo/error/lint_error.rb +4 -1
  166. data/lib/mongo/error/max_bson_size.rb +18 -4
  167. data/lib/mongo/error/max_message_size.rb +4 -1
  168. data/lib/mongo/error/mismatched_domain.rb +4 -1
  169. data/lib/mongo/error/missing_connection.rb +25 -0
  170. data/lib/mongo/error/missing_file_chunk.rb +12 -3
  171. data/lib/mongo/error/missing_password.rb +4 -1
  172. data/lib/mongo/error/missing_resume_token.rb +4 -1
  173. data/lib/mongo/error/missing_scram_server_signature.rb +30 -0
  174. data/lib/mongo/error/missing_service_id.rb +26 -0
  175. data/lib/mongo/error/mongocryptd_spawn_error.rb +25 -0
  176. data/lib/mongo/error/multi_index_drop.rb +4 -1
  177. data/lib/mongo/error/need_primary_server.rb +4 -1
  178. data/lib/mongo/error/no_server_available.rb +12 -4
  179. data/lib/mongo/error/no_service_connection_available.rb +49 -0
  180. data/lib/mongo/error/no_srv_records.rb +4 -1
  181. data/lib/mongo/error/notable.rb +34 -17
  182. data/lib/mongo/error/operation_failure.rb +107 -117
  183. data/lib/mongo/error/parser.rb +85 -18
  184. data/lib/mongo/error/pool_closed_error.rb +4 -1
  185. data/lib/mongo/error/raise_original_error.rb +32 -0
  186. data/lib/mongo/error/read_write_retryable.rb +108 -0
  187. data/lib/mongo/error/sdam_error_detection.rb +16 -5
  188. data/lib/mongo/error/server_api_conflict.rb +26 -0
  189. data/lib/mongo/error/server_api_not_supported.rb +27 -0
  190. data/lib/mongo/error/server_certificate_revoked.rb +25 -0
  191. data/lib/mongo/error/session_ended.rb +4 -1
  192. data/lib/mongo/error/session_not_materialized.rb +29 -0
  193. data/lib/mongo/error/sessions_not_supported.rb +38 -0
  194. data/lib/mongo/error/snapshot_session_invalid_server_version.rb +31 -0
  195. data/lib/mongo/error/snapshot_session_transaction_prohibited.rb +30 -0
  196. data/lib/mongo/error/socket_error.rb +4 -1
  197. data/lib/mongo/error/socket_timeout_error.rb +4 -1
  198. data/lib/mongo/error/unchangeable_collection_option.rb +4 -1
  199. data/lib/mongo/error/unexpected_chunk_length.rb +4 -1
  200. data/lib/mongo/error/unexpected_response.rb +4 -1
  201. data/lib/mongo/error/unknown_payload_type.rb +4 -1
  202. data/lib/mongo/{cursor/builder.rb → error/unmet_dependency.rb} +11 -5
  203. data/lib/mongo/error/unsupported_array_filters.rb +10 -2
  204. data/lib/mongo/error/unsupported_collation.rb +10 -2
  205. data/lib/mongo/error/unsupported_features.rb +4 -1
  206. data/lib/mongo/error/unsupported_message_type.rb +4 -1
  207. data/lib/mongo/error/unsupported_option.rb +104 -0
  208. data/lib/mongo/error/write_retryable.rb +4 -1
  209. data/lib/mongo/error.rb +50 -34
  210. data/lib/mongo/event/base.rb +10 -1
  211. data/lib/mongo/event/listeners.rb +4 -1
  212. data/lib/mongo/event/publisher.rb +4 -1
  213. data/lib/mongo/event/subscriber.rb +4 -1
  214. data/lib/mongo/event.rb +4 -1
  215. data/lib/mongo/grid/file/chunk.rb +7 -2
  216. data/lib/mongo/grid/file/info.rb +7 -3
  217. data/lib/mongo/grid/file.rb +9 -1
  218. data/lib/mongo/grid/fs_bucket.rb +108 -61
  219. data/lib/mongo/grid/stream/read.rb +29 -8
  220. data/lib/mongo/grid/stream/write.rb +13 -4
  221. data/lib/mongo/grid/stream.rb +4 -1
  222. data/lib/mongo/grid.rb +4 -1
  223. data/lib/mongo/id.rb +11 -6
  224. data/lib/mongo/index/view.rb +103 -43
  225. data/lib/mongo/index.rb +5 -1
  226. data/lib/mongo/lint.rb +14 -0
  227. data/lib/mongo/loggable.rb +4 -1
  228. data/lib/mongo/logger.rb +7 -4
  229. data/lib/mongo/monitoring/cmap_log_subscriber.rb +4 -1
  230. data/lib/mongo/monitoring/command_log_subscriber.rb +23 -5
  231. data/lib/mongo/monitoring/event/cmap/base.rb +4 -1
  232. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +5 -2
  233. data/lib/mongo/monitoring/event/cmap/connection_check_out_started.rb +4 -1
  234. data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +4 -1
  235. data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +4 -1
  236. data/lib/mongo/monitoring/event/cmap/connection_closed.rb +4 -1
  237. data/lib/mongo/monitoring/event/cmap/connection_created.rb +4 -1
  238. data/lib/mongo/monitoring/event/cmap/connection_ready.rb +4 -1
  239. data/lib/mongo/monitoring/event/cmap/pool_cleared.rb +11 -5
  240. data/lib/mongo/monitoring/event/cmap/pool_closed.rb +4 -1
  241. data/lib/mongo/monitoring/event/cmap/pool_created.rb +4 -1
  242. data/lib/mongo/monitoring/event/cmap.rb +4 -1
  243. data/lib/mongo/monitoring/event/command_failed.rb +50 -6
  244. data/lib/mongo/monitoring/event/command_started.rb +70 -4
  245. data/lib/mongo/monitoring/event/command_succeeded.rb +48 -4
  246. data/lib/mongo/monitoring/event/secure.rb +44 -4
  247. data/lib/mongo/monitoring/event/server_closed.rb +5 -2
  248. data/lib/mongo/monitoring/event/server_description_changed.rb +31 -5
  249. data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +39 -18
  250. data/lib/mongo/monitoring/event/server_heartbeat_started.rb +13 -3
  251. data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +34 -13
  252. data/lib/mongo/monitoring/event/server_opening.rb +5 -2
  253. data/lib/mongo/monitoring/event/topology_changed.rb +5 -2
  254. data/lib/mongo/monitoring/event/topology_closed.rb +5 -2
  255. data/lib/mongo/monitoring/event/topology_opening.rb +5 -2
  256. data/lib/mongo/monitoring/event.rb +4 -1
  257. data/lib/mongo/monitoring/publishable.rb +43 -17
  258. data/lib/mongo/monitoring/sdam_log_subscriber.rb +4 -1
  259. data/lib/mongo/monitoring/server_closed_log_subscriber.rb +4 -1
  260. data/lib/mongo/monitoring/server_description_changed_log_subscriber.rb +13 -2
  261. data/lib/mongo/monitoring/server_opening_log_subscriber.rb +4 -1
  262. data/lib/mongo/monitoring/topology_changed_log_subscriber.rb +5 -2
  263. data/lib/mongo/monitoring/topology_closed_log_subscriber.rb +4 -1
  264. data/lib/mongo/monitoring/topology_opening_log_subscriber.rb +4 -1
  265. data/lib/mongo/monitoring/unified_sdam_log_subscriber.rb +4 -1
  266. data/lib/mongo/monitoring.rb +51 -1
  267. data/lib/mongo/operation/aggregate/command.rb +16 -5
  268. data/lib/mongo/operation/aggregate/op_msg.rb +4 -1
  269. data/lib/mongo/operation/aggregate/result.rb +13 -9
  270. data/lib/mongo/operation/aggregate.rb +4 -1
  271. data/lib/mongo/operation/{delete/legacy.rb → collections_info/command.rb} +15 -21
  272. data/lib/mongo/operation/collections_info/result.rb +25 -2
  273. data/lib/mongo/operation/collections_info.rb +18 -28
  274. data/lib/mongo/operation/command/command.rb +6 -3
  275. data/lib/mongo/operation/command/op_msg.rb +10 -1
  276. data/lib/mongo/operation/command.rb +4 -1
  277. data/lib/mongo/operation/context.rb +138 -0
  278. data/lib/mongo/operation/count/command.rb +12 -3
  279. data/lib/mongo/operation/count/op_msg.rb +13 -1
  280. data/lib/mongo/operation/count.rb +4 -1
  281. data/lib/mongo/operation/create/command.rb +13 -4
  282. data/lib/mongo/operation/create/op_msg.rb +14 -1
  283. data/lib/mongo/operation/create.rb +4 -1
  284. data/lib/mongo/operation/create_index/command.rb +24 -5
  285. data/lib/mongo/operation/create_index/op_msg.rb +23 -3
  286. data/lib/mongo/operation/create_index.rb +4 -1
  287. data/lib/mongo/operation/create_user/command.rb +7 -4
  288. data/lib/mongo/operation/create_user/op_msg.rb +5 -2
  289. data/lib/mongo/operation/create_user.rb +4 -1
  290. data/lib/mongo/operation/delete/bulk_result.rb +6 -1
  291. data/lib/mongo/operation/delete/command.rb +13 -7
  292. data/lib/mongo/operation/delete/op_msg.rb +18 -6
  293. data/lib/mongo/operation/delete/result.rb +8 -2
  294. data/lib/mongo/operation/delete.rb +4 -2
  295. data/lib/mongo/operation/distinct/command.rb +12 -3
  296. data/lib/mongo/operation/distinct/op_msg.rb +14 -1
  297. data/lib/mongo/operation/distinct.rb +4 -1
  298. data/lib/mongo/operation/drop/command.rb +6 -3
  299. data/lib/mongo/operation/drop/op_msg.rb +4 -1
  300. data/lib/mongo/operation/drop.rb +4 -1
  301. data/lib/mongo/operation/drop_database/command.rb +6 -3
  302. data/lib/mongo/operation/drop_database/op_msg.rb +4 -1
  303. data/lib/mongo/operation/drop_database.rb +4 -1
  304. data/lib/mongo/operation/drop_index/command.rb +7 -4
  305. data/lib/mongo/operation/drop_index/op_msg.rb +10 -3
  306. data/lib/mongo/operation/drop_index.rb +4 -1
  307. data/lib/mongo/operation/explain/command.rb +22 -3
  308. data/lib/mongo/operation/explain/legacy.rb +17 -3
  309. data/lib/mongo/operation/explain/op_msg.rb +18 -1
  310. data/lib/mongo/operation/explain/result.rb +7 -1
  311. data/lib/mongo/operation/explain.rb +4 -1
  312. data/lib/mongo/operation/find/builder/command.rb +111 -0
  313. data/lib/mongo/{collection/view → operation/find}/builder/flags.rb +14 -15
  314. data/lib/mongo/operation/find/builder/legacy.rb +123 -0
  315. data/lib/mongo/{collection/view → operation/find}/builder/modifiers.rb +35 -26
  316. data/lib/mongo/operation/find/builder.rb +21 -0
  317. data/lib/mongo/operation/find/command.rb +15 -3
  318. data/lib/mongo/operation/find/legacy/result.rb +6 -1
  319. data/lib/mongo/operation/find/legacy.rb +15 -3
  320. data/lib/mongo/operation/find/op_msg.rb +17 -9
  321. data/lib/mongo/operation/find/result.rb +17 -1
  322. data/lib/mongo/operation/find.rb +5 -1
  323. data/lib/mongo/operation/get_more/command.rb +7 -3
  324. data/lib/mongo/operation/get_more/command_builder.rb +42 -0
  325. data/lib/mongo/operation/get_more/legacy.rb +5 -2
  326. data/lib/mongo/operation/get_more/op_msg.rb +6 -9
  327. data/lib/mongo/operation/get_more/result.rb +7 -1
  328. data/lib/mongo/operation/get_more.rb +5 -1
  329. data/lib/mongo/operation/indexes/command.rb +6 -3
  330. data/lib/mongo/operation/indexes/legacy.rb +7 -4
  331. data/lib/mongo/operation/indexes/op_msg.rb +4 -1
  332. data/lib/mongo/operation/indexes/result.rb +9 -1
  333. data/lib/mongo/operation/indexes.rb +19 -2
  334. data/lib/mongo/operation/insert/bulk_result.rb +18 -2
  335. data/lib/mongo/operation/insert/command.rb +10 -10
  336. data/lib/mongo/operation/insert/op_msg.rb +15 -9
  337. data/lib/mongo/operation/insert/result.rb +18 -4
  338. data/lib/mongo/operation/insert.rb +6 -3
  339. data/lib/mongo/operation/kill_cursors/command.rb +14 -3
  340. data/lib/mongo/operation/kill_cursors/{legacy.rb → command_builder.rb} +9 -11
  341. data/lib/mongo/operation/kill_cursors/op_msg.rb +14 -1
  342. data/lib/mongo/operation/kill_cursors.rb +5 -2
  343. data/lib/mongo/operation/list_collections/command.rb +7 -4
  344. data/lib/mongo/operation/list_collections/op_msg.rb +9 -3
  345. data/lib/mongo/operation/list_collections/result.rb +13 -2
  346. data/lib/mongo/operation/list_collections.rb +4 -1
  347. data/lib/mongo/operation/map_reduce/command.rb +14 -3
  348. data/lib/mongo/operation/map_reduce/op_msg.rb +5 -2
  349. data/lib/mongo/operation/map_reduce/result.rb +30 -1
  350. data/lib/mongo/operation/map_reduce.rb +4 -1
  351. data/lib/mongo/operation/op_msg_base.rb +6 -3
  352. data/lib/mongo/operation/parallel_scan/command.rb +8 -6
  353. data/lib/mongo/operation/parallel_scan/op_msg.rb +5 -2
  354. data/lib/mongo/operation/parallel_scan/result.rb +8 -1
  355. data/lib/mongo/operation/parallel_scan.rb +4 -1
  356. data/lib/mongo/operation/remove_user/command.rb +7 -4
  357. data/lib/mongo/operation/remove_user/op_msg.rb +5 -2
  358. data/lib/mongo/operation/remove_user.rb +4 -1
  359. data/lib/mongo/operation/result.rb +126 -37
  360. data/lib/mongo/operation/shared/bypass_document_validation.rb +14 -4
  361. data/lib/mongo/operation/shared/causal_consistency_supported.rb +7 -3
  362. data/lib/mongo/operation/shared/executable.rb +92 -28
  363. data/lib/mongo/operation/shared/executable_no_validate.rb +6 -3
  364. data/lib/mongo/operation/shared/executable_transaction_label.rb +4 -1
  365. data/lib/mongo/operation/shared/idable.rb +6 -2
  366. data/lib/mongo/operation/shared/limited.rb +14 -2
  367. data/lib/mongo/operation/shared/object_id_generator.rb +5 -1
  368. data/lib/mongo/operation/shared/op_msg_or_command.rb +7 -8
  369. data/lib/mongo/operation/shared/op_msg_or_find_command.rb +8 -9
  370. data/lib/mongo/operation/shared/polymorphic_lookup.rb +4 -1
  371. data/lib/mongo/operation/shared/polymorphic_operation.rb +54 -0
  372. data/lib/mongo/operation/shared/polymorphic_result.rb +4 -1
  373. data/lib/mongo/operation/shared/read_preference_supported.rb +82 -23
  374. data/lib/mongo/operation/shared/response_handling.rb +97 -17
  375. data/lib/mongo/operation/shared/result/aggregatable.rb +5 -1
  376. data/lib/mongo/operation/shared/result/use_legacy_error_parser.rb +4 -1
  377. data/lib/mongo/operation/shared/sessions_supported.rb +126 -26
  378. data/lib/mongo/operation/shared/specifiable.rb +36 -38
  379. data/lib/mongo/operation/shared/validatable.rb +87 -0
  380. data/lib/mongo/operation/shared/write.rb +37 -24
  381. data/lib/mongo/operation/shared/write_concern_supported.rb +10 -6
  382. data/lib/mongo/operation/update/bulk_result.rb +4 -1
  383. data/lib/mongo/operation/update/command.rb +13 -7
  384. data/lib/mongo/operation/update/op_msg.rb +16 -8
  385. data/lib/mongo/operation/update/result.rb +13 -2
  386. data/lib/mongo/operation/update.rb +4 -2
  387. data/lib/mongo/operation/update_user/command.rb +7 -4
  388. data/lib/mongo/operation/update_user/op_msg.rb +5 -2
  389. data/lib/mongo/operation/update_user.rb +4 -1
  390. data/lib/mongo/operation/users_info/command.rb +7 -4
  391. data/lib/mongo/operation/users_info/op_msg.rb +5 -2
  392. data/lib/mongo/operation/users_info/result.rb +7 -1
  393. data/lib/mongo/operation/users_info.rb +4 -1
  394. data/lib/mongo/operation/write_command/command.rb +51 -0
  395. data/lib/mongo/operation/write_command/op_msg.rb +43 -0
  396. data/lib/mongo/operation/write_command.rb +32 -0
  397. data/lib/mongo/operation.rb +17 -1
  398. data/lib/mongo/options/mapper.rb +4 -1
  399. data/lib/mongo/options/redacted.rb +4 -1
  400. data/lib/mongo/options.rb +4 -1
  401. data/lib/mongo/protocol/bit_vector.rb +6 -2
  402. data/lib/mongo/protocol/caching_hash.rb +69 -0
  403. data/lib/mongo/protocol/compressed.rb +61 -11
  404. data/lib/mongo/protocol/delete.rb +4 -1
  405. data/lib/mongo/protocol/get_more.rb +4 -1
  406. data/lib/mongo/protocol/insert.rb +7 -2
  407. data/lib/mongo/protocol/kill_cursors.rb +4 -1
  408. data/lib/mongo/protocol/message.rb +158 -21
  409. data/lib/mongo/protocol/msg.rb +268 -41
  410. data/lib/mongo/protocol/query.rb +97 -42
  411. data/lib/mongo/protocol/registry.rb +4 -1
  412. data/lib/mongo/protocol/reply.rb +4 -1
  413. data/lib/mongo/protocol/serializers.rb +47 -16
  414. data/lib/mongo/protocol/update.rb +4 -1
  415. data/lib/mongo/protocol.rb +4 -0
  416. data/lib/mongo/query_cache.rb +300 -0
  417. data/lib/mongo/retryable.rb +114 -43
  418. data/lib/mongo/semaphore.rb +4 -1
  419. data/lib/mongo/server/app_metadata.rb +128 -35
  420. data/lib/mongo/server/connection.rb +105 -127
  421. data/lib/mongo/server/connection_base.rb +173 -32
  422. data/lib/mongo/server/connection_common.rb +208 -0
  423. data/lib/mongo/server/connection_pool/generation_manager.rb +71 -0
  424. data/lib/mongo/server/connection_pool/populator.rb +5 -2
  425. data/lib/mongo/server/connection_pool.rb +206 -42
  426. data/lib/mongo/server/description/features.rb +41 -23
  427. data/lib/mongo/{srv/warning_result.rb → server/description/load_balancer.rb} +13 -15
  428. data/lib/mongo/server/description.rb +183 -30
  429. data/lib/mongo/server/monitor/app_metadata.rb +5 -2
  430. data/lib/mongo/server/monitor/connection.rb +148 -117
  431. data/lib/mongo/server/monitor.rb +183 -79
  432. data/lib/mongo/server/pending_connection.rb +247 -1
  433. data/lib/mongo/server/push_monitor/connection.rb +31 -0
  434. data/lib/mongo/server/push_monitor.rb +207 -0
  435. data/lib/mongo/server/round_trip_time_averager.rb +18 -6
  436. data/lib/mongo/server.rb +154 -52
  437. data/lib/mongo/server_selector/{selectable.rb → base.rb} +197 -91
  438. data/lib/mongo/server_selector/nearest.rb +32 -25
  439. data/lib/mongo/server_selector/primary.rb +30 -32
  440. data/lib/mongo/server_selector/primary_preferred.rb +38 -29
  441. data/lib/mongo/server_selector/secondary.rb +32 -25
  442. data/lib/mongo/server_selector/secondary_preferred.rb +30 -38
  443. data/lib/mongo/server_selector.rb +5 -2
  444. data/lib/mongo/session/server_session.rb +4 -1
  445. data/lib/mongo/session/session_pool.rb +33 -4
  446. data/lib/mongo/session.rb +178 -39
  447. data/lib/mongo/socket/ocsp_cache.rb +99 -0
  448. data/lib/mongo/socket/ocsp_verifier.rb +344 -0
  449. data/lib/mongo/socket/ssl.rb +165 -55
  450. data/lib/mongo/socket/tcp.rb +48 -25
  451. data/lib/mongo/socket/unix.rb +17 -6
  452. data/lib/mongo/socket.rb +168 -47
  453. data/lib/mongo/srv/monitor.rb +64 -47
  454. data/lib/mongo/srv/resolver.rb +42 -14
  455. data/lib/mongo/srv/result.rb +4 -2
  456. data/lib/mongo/srv.rb +4 -1
  457. data/lib/mongo/timeout.rb +54 -0
  458. data/lib/mongo/topology_version.rb +92 -0
  459. data/lib/mongo/uri/options_mapper.rb +626 -0
  460. data/lib/mongo/uri/srv_protocol.rb +23 -13
  461. data/lib/mongo/uri.rb +103 -388
  462. data/lib/mongo/utils.rb +105 -0
  463. data/lib/mongo/version.rb +5 -2
  464. data/lib/mongo/write_concern/acknowledged.rb +4 -1
  465. data/lib/mongo/write_concern/base.rb +4 -1
  466. data/lib/mongo/write_concern/unacknowledged.rb +4 -1
  467. data/lib/mongo/write_concern.rb +4 -1
  468. data/lib/mongo.rb +67 -2
  469. data/mongo.gemspec +12 -8
  470. data/spec/NOTES.aws-auth.md +296 -0
  471. data/spec/README.aws-auth.md +318 -0
  472. data/spec/README.md +386 -15
  473. data/spec/atlas/atlas_connectivity_spec.rb +3 -0
  474. data/spec/atlas/operations_spec.rb +3 -0
  475. data/spec/integration/auth_spec.rb +130 -14
  476. data/spec/integration/awaited_ismaster_spec.rb +31 -0
  477. data/spec/integration/aws_auth_request_spec.rb +77 -0
  478. data/spec/integration/aws_credentials_retriever_spec.rb +106 -0
  479. data/spec/integration/aws_lambda_examples_spec.rb +68 -0
  480. data/spec/integration/bson_symbol_spec.rb +8 -3
  481. data/spec/integration/bulk_insert_spec.rb +3 -0
  482. data/spec/integration/bulk_write_error_message_spec.rb +73 -0
  483. data/spec/integration/bulk_write_spec.rb +86 -0
  484. data/spec/integration/change_stream_examples_spec.rb +9 -2
  485. data/spec/integration/change_stream_spec.rb +133 -57
  486. data/spec/integration/check_clean_slate_spec.rb +19 -0
  487. data/spec/integration/{client_options_spec.rb → client_authentication_options_spec.rb} +123 -46
  488. data/spec/integration/client_connectivity_spec.rb +4 -1
  489. data/spec/integration/client_construction_aws_auth_spec.rb +194 -0
  490. data/spec/integration/client_construction_spec.rb +225 -2
  491. data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +360 -0
  492. data/spec/integration/client_side_encryption/auto_encryption_command_monitoring_spec.rb +306 -0
  493. data/spec/integration/client_side_encryption/auto_encryption_mongocryptd_spawn_spec.rb +74 -0
  494. data/spec/integration/client_side_encryption/auto_encryption_old_wire_version_spec.rb +82 -0
  495. data/spec/integration/client_side_encryption/auto_encryption_reconnect_spec.rb +255 -0
  496. data/spec/integration/client_side_encryption/auto_encryption_spec.rb +711 -0
  497. data/spec/integration/client_side_encryption/bson_size_limit_spec.rb +190 -0
  498. data/spec/integration/client_side_encryption/bypass_mongocryptd_spawn_spec.rb +81 -0
  499. data/spec/integration/client_side_encryption/client_close_spec.rb +66 -0
  500. data/spec/integration/client_side_encryption/corpus_spec.rb +265 -0
  501. data/spec/integration/client_side_encryption/custom_endpoint_spec.rb +132 -0
  502. data/spec/integration/client_side_encryption/data_key_spec.rb +258 -0
  503. data/spec/integration/client_side_encryption/decryption_events_prose_spec.rb +158 -0
  504. data/spec/integration/client_side_encryption/explicit_encryption_spec.rb +176 -0
  505. data/spec/integration/client_side_encryption/explicit_queryable_encryption_spec.rb +147 -0
  506. data/spec/integration/client_side_encryption/external_key_vault_spec.rb +144 -0
  507. data/spec/integration/client_side_encryption/kms_tls_options_spec.rb +436 -0
  508. data/spec/integration/client_side_encryption/kms_tls_spec.rb +92 -0
  509. data/spec/integration/client_side_encryption/queryable_encryption_examples_spec.rb +111 -0
  510. data/spec/integration/client_side_encryption/unique_index_on_key_alt_names_prose_spec.rb +85 -0
  511. data/spec/integration/client_side_encryption/views_spec.rb +47 -0
  512. data/spec/integration/client_spec.rb +7 -2
  513. data/spec/integration/client_update_spec.rb +157 -0
  514. data/spec/integration/collection_indexes_prose_spec.rb +58 -0
  515. data/spec/integration/command_monitoring_spec.rb +95 -31
  516. data/spec/integration/command_spec.rb +59 -20
  517. data/spec/integration/connect_single_rs_name_spec.rb +15 -7
  518. data/spec/integration/connection_pool_populator_spec.rb +7 -2
  519. data/spec/integration/connection_spec.rb +121 -38
  520. data/spec/integration/crud_spec.rb +338 -5
  521. data/spec/integration/cursor_pinning_spec.rb +121 -0
  522. data/spec/integration/cursor_reaping_spec.rb +75 -28
  523. data/spec/integration/docs_examples_spec.rb +16 -0
  524. data/spec/integration/error_detection_spec.rb +3 -0
  525. data/spec/integration/fork_reconnect_spec.rb +207 -0
  526. data/spec/integration/get_more_spec.rb +13 -3
  527. data/spec/integration/grid_fs_bucket_spec.rb +51 -0
  528. data/spec/integration/heartbeat_events_spec.rb +11 -27
  529. data/spec/integration/map_reduce_spec.rb +77 -0
  530. data/spec/integration/mmapv1_spec.rb +3 -0
  531. data/spec/integration/mongos_pinning_spec.rb +3 -0
  532. data/spec/integration/ocsp_connectivity_spec.rb +29 -0
  533. data/spec/integration/ocsp_verifier_cache_spec.rb +191 -0
  534. data/spec/integration/ocsp_verifier_spec.rb +358 -0
  535. data/spec/integration/operation_failure_code_spec.rb +4 -1
  536. data/spec/integration/operation_failure_message_spec.rb +90 -0
  537. data/spec/integration/query_cache_spec.rb +1256 -0
  538. data/spec/integration/query_cache_transactions_spec.rb +193 -0
  539. data/spec/integration/read_concern_spec.rb +5 -2
  540. data/spec/integration/read_preference_spec.rb +86 -23
  541. data/spec/integration/reconnect_spec.rb +42 -19
  542. data/spec/integration/retryable_errors_spec.rb +36 -14
  543. data/spec/integration/{retryable_writes_spec.rb → retryable_writes/retryable_writes_36_and_older_spec.rb} +60 -53
  544. data/spec/integration/retryable_writes/retryable_writes_40_and_newer_spec.rb +405 -0
  545. data/spec/integration/retryable_writes/shared/adds_diagnostics.rb +18 -0
  546. data/spec/integration/retryable_writes/shared/does_not_support_retries.rb +27 -0
  547. data/spec/integration/retryable_writes/shared/only_supports_legacy_retries.rb +28 -0
  548. data/spec/integration/retryable_writes/shared/performs_legacy_retries.rb +220 -0
  549. data/spec/integration/retryable_writes/shared/performs_modern_retries.rb +235 -0
  550. data/spec/integration/retryable_writes/shared/performs_no_retries.rb +113 -0
  551. data/spec/integration/retryable_writes/shared/supports_legacy_retries.rb +22 -0
  552. data/spec/integration/retryable_writes/shared/supports_modern_retries.rb +28 -0
  553. data/spec/integration/retryable_writes/shared/supports_retries.rb +19 -0
  554. data/spec/integration/retryable_writes_errors_spec.rb +3 -0
  555. data/spec/integration/sdam_error_handling_spec.rb +235 -25
  556. data/spec/integration/sdam_events_spec.rb +142 -7
  557. data/spec/integration/sdam_prose_spec.rb +67 -0
  558. data/spec/integration/secondary_reads_spec.rb +102 -0
  559. data/spec/integration/server_description_spec.rb +3 -0
  560. data/spec/integration/server_monitor_spec.rb +31 -2
  561. data/spec/integration/server_selection_spec.rb +39 -0
  562. data/spec/integration/server_selector_spec.rb +25 -5
  563. data/spec/integration/server_spec.rb +47 -26
  564. data/spec/integration/shell_examples_spec.rb +3 -0
  565. data/spec/integration/size_limit_spec.rb +118 -0
  566. data/spec/integration/snappy_compression_spec.rb +28 -0
  567. data/spec/integration/snapshot_query_examples_spec.rb +127 -0
  568. data/spec/integration/srv_monitoring_spec.rb +93 -9
  569. data/spec/integration/srv_spec.rb +60 -0
  570. data/spec/integration/ssl_uri_options_spec.rb +5 -2
  571. data/spec/integration/step_down_spec.rb +38 -19
  572. data/spec/integration/time_zone_querying_spec.rb +3 -0
  573. data/spec/integration/transaction_pinning_spec.rb +120 -0
  574. data/spec/integration/transactions_api_examples_spec.rb +62 -0
  575. data/spec/integration/transactions_examples_spec.rb +31 -9
  576. data/spec/integration/truncated_utf8_spec.rb +26 -0
  577. data/spec/integration/versioned_api_examples_spec.rb +120 -0
  578. data/spec/integration/x509_auth_spec.rb +112 -0
  579. data/spec/integration/zlib_compression_spec.rb +28 -0
  580. data/spec/integration/zstd_compression_spec.rb +29 -0
  581. data/spec/kerberos/kerberos_spec.rb +94 -0
  582. data/spec/lite_spec_helper.rb +88 -44
  583. data/spec/mongo/address/ipv4_spec.rb +4 -1
  584. data/spec/mongo/address/ipv6_spec.rb +10 -0
  585. data/spec/mongo/address/unix_spec.rb +4 -0
  586. data/spec/mongo/address/validator_spec.rb +3 -0
  587. data/spec/mongo/address_spec.rb +27 -13
  588. data/spec/mongo/auth/aws/request_region_spec.rb +45 -0
  589. data/spec/mongo/auth/aws/request_spec.rb +79 -0
  590. data/spec/mongo/auth/cr_spec.rb +20 -10
  591. data/spec/mongo/auth/gssapi/conversation_spec.rb +124 -0
  592. data/spec/mongo/auth/invalid_mechanism_spec.rb +4 -1
  593. data/spec/mongo/auth/ldap/conversation_spec.rb +5 -2
  594. data/spec/mongo/auth/ldap_spec.rb +18 -8
  595. data/spec/mongo/auth/scram/conversation_spec.rb +125 -338
  596. data/spec/mongo/auth/scram256/conversation_spec.rb +174 -0
  597. data/spec/mongo/auth/{scram/negotiation_spec.rb → scram_negotiation_spec.rb} +83 -75
  598. data/spec/mongo/auth/scram_spec.rb +60 -88
  599. data/spec/mongo/auth/stringprep/profiles/sasl_spec.rb +3 -0
  600. data/spec/mongo/auth/stringprep_spec.rb +3 -0
  601. data/spec/mongo/auth/user/view_spec.rb +7 -7
  602. data/spec/mongo/auth/user_spec.rb +5 -2
  603. data/spec/mongo/auth/x509/conversation_spec.rb +7 -4
  604. data/spec/mongo/auth/x509_spec.rb +18 -12
  605. data/spec/mongo/auth_spec.rb +7 -4
  606. data/spec/mongo/bson_spec.rb +3 -0
  607. data/spec/mongo/bulk_write/ordered_combiner_spec.rb +3 -0
  608. data/spec/mongo/bulk_write/result_spec.rb +29 -8
  609. data/spec/mongo/bulk_write/unordered_combiner_spec.rb +3 -0
  610. data/spec/mongo/bulk_write_spec.rb +333 -5
  611. data/spec/mongo/caching_cursor_spec.rb +73 -0
  612. data/spec/mongo/client_construction_spec.rb +1662 -284
  613. data/spec/mongo/client_encryption_spec.rb +402 -0
  614. data/spec/mongo/client_spec.rb +425 -6
  615. data/spec/mongo/cluster/cursor_reaper_spec.rb +78 -31
  616. data/spec/mongo/cluster/periodic_executor_spec.rb +6 -1
  617. data/spec/mongo/cluster/socket_reaper_spec.rb +17 -3
  618. data/spec/mongo/cluster/topology/replica_set_spec.rb +65 -19
  619. data/spec/mongo/cluster/topology/sharded_spec.rb +6 -3
  620. data/spec/mongo/cluster/topology/single_spec.rb +24 -10
  621. data/spec/mongo/cluster/topology/unknown_spec.rb +4 -1
  622. data/spec/mongo/cluster/topology_spec.rb +4 -1
  623. data/spec/mongo/cluster_spec.rb +71 -81
  624. data/spec/mongo/cluster_time_spec.rb +3 -0
  625. data/spec/mongo/collection/view/aggregation_spec.rb +186 -86
  626. data/spec/mongo/collection/view/builder/find_command_spec.rb +24 -6
  627. data/spec/mongo/collection/view/builder/op_query_spec.rb +7 -0
  628. data/spec/mongo/collection/view/change_stream_resume_spec.rb +397 -0
  629. data/spec/mongo/collection/view/change_stream_spec.rb +21 -323
  630. data/spec/mongo/collection/view/explainable_spec.rb +90 -4
  631. data/spec/mongo/collection/view/immutable_spec.rb +3 -0
  632. data/spec/mongo/collection/view/iterable_spec.rb +41 -0
  633. data/spec/mongo/collection/view/map_reduce_spec.rb +44 -6
  634. data/spec/mongo/collection/view/readable_spec.rb +745 -2
  635. data/spec/mongo/collection/view/writable_spec.rb +323 -1
  636. data/spec/mongo/collection/view_spec.rb +4 -1
  637. data/spec/mongo/collection_crud_spec.rb +4415 -0
  638. data/spec/mongo/collection_ddl_spec.rb +537 -0
  639. data/spec/mongo/collection_spec.rb +103 -4367
  640. data/spec/mongo/config/options_spec.rb +75 -0
  641. data/spec/mongo/config_spec.rb +73 -0
  642. data/spec/mongo/crypt/auto_decryption_context_spec.rb +109 -0
  643. data/spec/mongo/crypt/auto_encrypter_spec.rb +441 -0
  644. data/spec/mongo/crypt/auto_encryption_context_spec.rb +126 -0
  645. data/spec/mongo/crypt/binary_spec.rb +113 -0
  646. data/spec/mongo/crypt/binding/binary_spec.rb +54 -0
  647. data/spec/mongo/crypt/binding/context_spec.rb +305 -0
  648. data/spec/mongo/crypt/binding/helpers_spec.rb +44 -0
  649. data/spec/mongo/crypt/binding/mongocrypt_spec.rb +113 -0
  650. data/spec/mongo/crypt/binding/status_spec.rb +97 -0
  651. data/spec/mongo/crypt/binding/version_spec.rb +53 -0
  652. data/spec/mongo/crypt/binding_unloaded_spec.rb +37 -0
  653. data/spec/mongo/crypt/data_key_context_spec.rb +144 -0
  654. data/spec/mongo/crypt/encryption_io_spec.rb +141 -0
  655. data/spec/mongo/crypt/explicit_decryption_context_spec.rb +106 -0
  656. data/spec/mongo/crypt/explicit_encryption_context_spec.rb +266 -0
  657. data/spec/mongo/crypt/handle_spec.rb +251 -0
  658. data/spec/mongo/crypt/helpers/mongo_crypt_spec_helper.rb +111 -0
  659. data/spec/mongo/crypt/hooks_spec.rb +30 -0
  660. data/spec/mongo/crypt/kms/credentials_spec.rb +357 -0
  661. data/spec/mongo/crypt/kms_spec.rb +59 -0
  662. data/spec/mongo/crypt/status_spec.rb +150 -0
  663. data/spec/mongo/cursor/builder/get_more_command_spec.rb +15 -1
  664. data/spec/mongo/cursor/builder/op_get_more_spec.rb +15 -1
  665. data/spec/mongo/cursor_spec.rb +209 -17
  666. data/spec/mongo/database_spec.rb +526 -27
  667. data/spec/mongo/distinguishing_semaphore_spec.rb +66 -0
  668. data/spec/mongo/error/bulk_write_error_spec.rb +52 -0
  669. data/spec/mongo/error/crypt_error_spec.rb +29 -0
  670. data/spec/mongo/error/max_bson_size_spec.rb +38 -0
  671. data/spec/mongo/error/no_server_available_spec.rb +15 -2
  672. data/spec/mongo/error/notable_spec.rb +62 -0
  673. data/spec/mongo/error/operation_failure_heavy_spec.rb +110 -0
  674. data/spec/mongo/error/operation_failure_spec.rb +231 -70
  675. data/spec/mongo/error/parser_spec.rb +40 -6
  676. data/spec/mongo/error/unsupported_option_spec.rb +57 -0
  677. data/spec/mongo/event/publisher_spec.rb +3 -0
  678. data/spec/mongo/event/subscriber_spec.rb +3 -0
  679. data/spec/mongo/grid/file/chunk_spec.rb +7 -4
  680. data/spec/mongo/grid/file/info_spec.rb +3 -0
  681. data/spec/mongo/grid/file_spec.rb +4 -1
  682. data/spec/mongo/grid/fs_bucket_spec.rb +58 -17
  683. data/spec/mongo/grid/stream/read_spec.rb +33 -10
  684. data/spec/mongo/grid/stream/write_spec.rb +38 -9
  685. data/spec/mongo/grid/stream_spec.rb +4 -1
  686. data/spec/mongo/id_spec.rb +3 -0
  687. data/spec/mongo/index/view_spec.rb +446 -0
  688. data/spec/mongo/lint_spec.rb +3 -0
  689. data/spec/mongo/logger_spec.rb +16 -11
  690. data/spec/mongo/monitoring/command_log_subscriber_spec.rb +3 -0
  691. data/spec/mongo/monitoring/event/cmap/connection_check_out_failed_spec.rb +3 -0
  692. data/spec/mongo/monitoring/event/cmap/connection_check_out_started_spec.rb +3 -0
  693. data/spec/mongo/monitoring/event/cmap/connection_checked_in_spec.rb +3 -0
  694. data/spec/mongo/monitoring/event/cmap/connection_checked_out_spec.rb +3 -0
  695. data/spec/mongo/monitoring/event/cmap/connection_closed_spec.rb +3 -0
  696. data/spec/mongo/monitoring/event/cmap/connection_created_spec.rb +3 -0
  697. data/spec/mongo/monitoring/event/cmap/connection_ready_spec.rb +3 -0
  698. data/spec/mongo/monitoring/event/cmap/pool_cleared_spec.rb +3 -0
  699. data/spec/mongo/monitoring/event/cmap/pool_closed_spec.rb +3 -0
  700. data/spec/mongo/monitoring/event/cmap/pool_created_spec.rb +3 -0
  701. data/spec/mongo/monitoring/event/command_failed_spec.rb +59 -2
  702. data/spec/mongo/monitoring/event/command_started_spec.rb +3 -0
  703. data/spec/mongo/monitoring/event/command_succeeded_spec.rb +46 -6
  704. data/spec/mongo/monitoring/event/secure_spec.rb +28 -4
  705. data/spec/mongo/monitoring/event/server_closed_spec.rb +4 -1
  706. data/spec/mongo/monitoring/event/server_description_changed_spec.rb +4 -4
  707. data/spec/mongo/monitoring/event/server_heartbeat_failed_spec.rb +4 -1
  708. data/spec/mongo/monitoring/event/server_heartbeat_started_spec.rb +3 -0
  709. data/spec/mongo/monitoring/event/server_heartbeat_succeeded_spec.rb +4 -1
  710. data/spec/mongo/monitoring/event/server_opening_spec.rb +4 -1
  711. data/spec/mongo/monitoring/event/topology_changed_spec.rb +4 -1
  712. data/spec/mongo/monitoring/event/topology_closed_spec.rb +4 -1
  713. data/spec/mongo/monitoring/event/topology_opening_spec.rb +4 -1
  714. data/spec/mongo/monitoring_spec.rb +3 -0
  715. data/spec/mongo/operation/aggregate/result_spec.rb +11 -1
  716. data/spec/mongo/operation/aggregate_spec.rb +5 -1
  717. data/spec/mongo/operation/collections_info_spec.rb +7 -1
  718. data/spec/mongo/operation/command_spec.rb +11 -5
  719. data/spec/mongo/operation/create/op_msg_spec.rb +244 -0
  720. data/spec/mongo/operation/create_index_spec.rb +9 -3
  721. data/spec/mongo/operation/create_user_spec.rb +9 -3
  722. data/spec/mongo/operation/delete/bulk_spec.rb +24 -6
  723. data/spec/mongo/operation/delete/command_spec.rb +3 -0
  724. data/spec/mongo/operation/delete/op_msg_spec.rb +40 -25
  725. data/spec/mongo/operation/delete_spec.rb +13 -36
  726. data/spec/mongo/operation/drop_index_spec.rb +9 -2
  727. data/spec/mongo/{collection/view → operation/find}/builder/flags_spec.rb +5 -2
  728. data/spec/mongo/{collection/view → operation/find}/builder/modifiers_spec.rb +5 -2
  729. data/spec/mongo/operation/find/legacy_spec.rb +34 -7
  730. data/spec/mongo/operation/get_more_spec.rb +11 -1
  731. data/spec/mongo/operation/indexes_spec.rb +8 -1
  732. data/spec/mongo/operation/insert/bulk_spec.rb +28 -8
  733. data/spec/mongo/operation/insert/command_spec.rb +7 -0
  734. data/spec/mongo/operation/insert/op_msg_spec.rb +46 -30
  735. data/spec/mongo/operation/insert_spec.rb +17 -43
  736. data/spec/mongo/operation/limited_spec.rb +8 -3
  737. data/spec/mongo/operation/map_reduce_spec.rb +8 -2
  738. data/spec/mongo/operation/read_preference_legacy_spec.rb +360 -0
  739. data/spec/mongo/operation/read_preference_op_msg_spec.rb +332 -0
  740. data/spec/mongo/operation/remove_user_spec.rb +9 -3
  741. data/spec/mongo/operation/result_spec.rb +34 -4
  742. data/spec/mongo/operation/specifiable_spec.rb +3 -0
  743. data/spec/mongo/operation/update/bulk_spec.rb +25 -7
  744. data/spec/mongo/operation/update/command_spec.rb +7 -0
  745. data/spec/mongo/operation/update/op_msg_spec.rb +41 -24
  746. data/spec/mongo/operation/update_spec.rb +12 -35
  747. data/spec/mongo/operation/update_user_spec.rb +7 -1
  748. data/spec/mongo/options/redacted_spec.rb +3 -0
  749. data/spec/mongo/protocol/caching_hash_spec.rb +82 -0
  750. data/spec/mongo/protocol/compressed_spec.rb +29 -13
  751. data/spec/mongo/protocol/delete_spec.rb +12 -8
  752. data/spec/mongo/protocol/get_more_spec.rb +12 -8
  753. data/spec/mongo/protocol/insert_spec.rb +12 -8
  754. data/spec/mongo/protocol/kill_cursors_spec.rb +9 -5
  755. data/spec/mongo/protocol/msg_spec.rb +111 -53
  756. data/spec/mongo/protocol/query_spec.rb +18 -15
  757. data/spec/mongo/protocol/registry_spec.rb +4 -1
  758. data/spec/mongo/protocol/reply_spec.rb +4 -1
  759. data/spec/mongo/protocol/update_spec.rb +13 -9
  760. data/spec/mongo/query_cache_middleware_spec.rb +55 -0
  761. data/spec/mongo/query_cache_spec.rb +453 -0
  762. data/spec/mongo/retryable_spec.rb +109 -75
  763. data/spec/mongo/semaphore_spec.rb +54 -0
  764. data/spec/mongo/server/app_metadata_spec.rb +53 -21
  765. data/spec/mongo/server/connection_auth_spec.rb +42 -24
  766. data/spec/mongo/server/connection_common_spec.rb +87 -0
  767. data/spec/mongo/server/connection_pool/populator_spec.rb +6 -1
  768. data/spec/mongo/server/connection_pool_spec.rb +189 -80
  769. data/spec/mongo/server/connection_spec.rb +323 -246
  770. data/spec/mongo/server/description/features_spec.rb +27 -0
  771. data/spec/mongo/server/description_query_methods_spec.rb +4 -1
  772. data/spec/mongo/server/description_spec.rb +625 -594
  773. data/spec/mongo/server/monitor/app_metadata_spec.rb +10 -1
  774. data/spec/mongo/server/monitor/connection_spec.rb +60 -69
  775. data/spec/mongo/server/monitor_spec.rb +95 -24
  776. data/spec/mongo/server/push_monitor_spec.rb +95 -0
  777. data/spec/mongo/server/round_trip_time_averager_spec.rb +8 -3
  778. data/spec/mongo/server_selector/nearest_spec.rb +32 -25
  779. data/spec/mongo/server_selector/primary_preferred_spec.rb +35 -28
  780. data/spec/mongo/server_selector/primary_spec.rb +35 -11
  781. data/spec/mongo/server_selector/secondary_preferred_spec.rb +52 -29
  782. data/spec/mongo/server_selector/secondary_spec.rb +27 -20
  783. data/spec/mongo/server_selector_spec.rb +145 -21
  784. data/spec/mongo/server_spec.rb +18 -2
  785. data/spec/mongo/session/server_session_spec.rb +3 -0
  786. data/spec/mongo/session/session_pool_spec.rb +51 -12
  787. data/spec/mongo/session_spec.rb +58 -0
  788. data/spec/mongo/session_transaction_spec.rb +17 -36
  789. data/spec/mongo/socket/ssl_spec.rb +91 -69
  790. data/spec/mongo/socket/tcp_spec.rb +5 -2
  791. data/spec/mongo/socket/unix_spec.rb +6 -2
  792. data/spec/mongo/socket_spec.rb +14 -11
  793. data/spec/mongo/srv/monitor_spec.rb +91 -69
  794. data/spec/mongo/srv/result_spec.rb +3 -0
  795. data/spec/mongo/timeout_spec.rb +42 -0
  796. data/spec/mongo/tls_context_hooks_spec.rb +40 -0
  797. data/spec/mongo/uri/srv_protocol_spec.rb +171 -37
  798. data/spec/mongo/uri_option_parsing_spec.rb +52 -16
  799. data/spec/mongo/uri_spec.rb +165 -48
  800. data/spec/mongo/utils_spec.rb +42 -0
  801. data/spec/mongo/write_concern/acknowledged_spec.rb +3 -0
  802. data/spec/mongo/write_concern/unacknowledged_spec.rb +3 -0
  803. data/spec/mongo/write_concern_spec.rb +16 -1
  804. data/spec/{support → runners}/auth.rb +45 -9
  805. data/spec/runners/change_streams/outcome.rb +45 -0
  806. data/spec/runners/change_streams/spec.rb +60 -0
  807. data/spec/runners/change_streams/test.rb +232 -0
  808. data/spec/{support → runners}/cmap/verifier.rb +4 -1
  809. data/spec/{support → runners}/cmap.rb +7 -4
  810. data/spec/{support → runners}/command_monitoring.rb +8 -36
  811. data/spec/runners/connection_string.rb +283 -6
  812. data/spec/{support/transactions → runners/crud}/context.rb +12 -15
  813. data/spec/{support → runners}/crud/operation.rb +201 -61
  814. data/spec/{support → runners}/crud/outcome.rb +4 -1
  815. data/spec/runners/crud/requirement.rb +139 -0
  816. data/spec/{support → runners}/crud/spec.rb +21 -11
  817. data/spec/{support → runners}/crud/test.rb +12 -27
  818. data/spec/runners/crud/test_base.rb +53 -0
  819. data/spec/{support → runners}/crud/verifier.rb +47 -15
  820. data/spec/{support → runners}/crud.rb +34 -12
  821. data/spec/{support → runners}/gridfs.rb +5 -2
  822. data/spec/runners/read_write_concern_document.rb +4 -1
  823. data/spec/runners/sdam/verifier.rb +29 -8
  824. data/spec/{support/server_discovery_and_monitoring.rb → runners/sdam.rb} +49 -26
  825. data/spec/runners/server_selection.rb +365 -0
  826. data/spec/{support → runners}/server_selection_rtt.rb +5 -2
  827. data/spec/runners/transactions/operation.rb +328 -0
  828. data/spec/{support → runners}/transactions/spec.rb +6 -3
  829. data/spec/runners/transactions/test.rb +329 -0
  830. data/spec/{support → runners}/transactions.rb +30 -27
  831. data/spec/runners/unified/assertions.rb +362 -0
  832. data/spec/runners/unified/change_stream_operations.rb +41 -0
  833. data/spec/runners/unified/client_side_encryption_operations.rb +83 -0
  834. data/spec/runners/unified/crud_operations.rb +323 -0
  835. data/spec/runners/unified/ddl_operations.rb +179 -0
  836. data/spec/runners/unified/entity_map.rb +42 -0
  837. data/spec/runners/unified/error.rb +29 -0
  838. data/spec/runners/unified/event_subscriber.rb +104 -0
  839. data/spec/runners/unified/exceptions.rb +24 -0
  840. data/spec/runners/unified/grid_fs_operations.rb +79 -0
  841. data/spec/runners/unified/support_operations.rb +269 -0
  842. data/spec/runners/unified/test.rb +511 -0
  843. data/spec/runners/unified/test_group.rb +31 -0
  844. data/spec/runners/unified.rb +106 -0
  845. data/spec/shared/LICENSE +20 -0
  846. data/spec/shared/bin/get-mongodb-download-url +17 -0
  847. data/spec/shared/bin/s3-copy +45 -0
  848. data/spec/shared/bin/s3-upload +69 -0
  849. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  850. data/spec/shared/lib/mrss/cluster_config.rb +231 -0
  851. data/spec/shared/lib/mrss/constraints.rb +378 -0
  852. data/spec/shared/lib/mrss/docker_runner.rb +291 -0
  853. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  854. data/spec/shared/lib/mrss/event_subscriber.rb +210 -0
  855. data/spec/shared/lib/mrss/lite_constraints.rb +230 -0
  856. data/spec/shared/lib/mrss/server_version_registry.rb +120 -0
  857. data/spec/shared/lib/mrss/session_registry.rb +69 -0
  858. data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
  859. data/spec/shared/lib/mrss/spec_organizer.rb +179 -0
  860. data/spec/shared/lib/mrss/utils.rb +15 -0
  861. data/spec/shared/share/Dockerfile.erb +325 -0
  862. data/spec/shared/share/haproxy-1.conf +16 -0
  863. data/spec/shared/share/haproxy-2.conf +17 -0
  864. data/spec/shared/shlib/config.sh +27 -0
  865. data/spec/shared/shlib/distro.sh +74 -0
  866. data/spec/shared/shlib/server.sh +392 -0
  867. data/spec/shared/shlib/set_env.sh +169 -0
  868. data/spec/solo/clean_exit_spec.rb +29 -0
  869. data/spec/spec_helper.rb +10 -9
  870. data/spec/spec_tests/auth_spec.rb +33 -14
  871. data/spec/spec_tests/change_streams_unified_spec.rb +13 -0
  872. data/spec/spec_tests/client_side_encryption_spec.rb +14 -0
  873. data/spec/spec_tests/client_side_encryption_unified_spec.rb +16 -0
  874. data/spec/spec_tests/cmap_spec.rb +19 -4
  875. data/spec/spec_tests/collection_management_spec.rb +13 -0
  876. data/spec/spec_tests/command_monitoring_unified_spec.rb +13 -0
  877. data/spec/spec_tests/connection_string_spec.rb +6 -1
  878. data/spec/spec_tests/crud_spec.rb +5 -10
  879. data/spec/spec_tests/crud_unified_spec.rb +13 -0
  880. data/spec/spec_tests/data/auth/connection-string.yml +69 -0
  881. data/spec/spec_tests/data/change_streams_unified/change-streams-errors.yml +124 -0
  882. data/spec/spec_tests/data/change_streams_unified/change-streams-pre_and_post_images.yml +351 -0
  883. data/spec/spec_tests/data/change_streams_unified/change-streams-resume-allowlist.yml +1171 -0
  884. data/spec/spec_tests/data/change_streams_unified/change-streams-resume-errorLabels.yml +1071 -0
  885. data/spec/spec_tests/data/change_streams_unified/change-streams-showExpandedEvents.yml +298 -0
  886. data/spec/spec_tests/data/change_streams_unified/change-streams.yml +927 -0
  887. data/spec/spec_tests/data/client_side_encryption/aggregate.yml +120 -0
  888. data/spec/spec_tests/data/client_side_encryption/azureKMS.yml +46 -0
  889. data/spec/spec_tests/data/client_side_encryption/badQueries.yml +536 -0
  890. data/spec/spec_tests/data/client_side_encryption/badSchema.yml +73 -0
  891. data/spec/spec_tests/data/client_side_encryption/basic.yml +102 -0
  892. data/spec/spec_tests/data/client_side_encryption/bulk.yml +81 -0
  893. data/spec/spec_tests/data/client_side_encryption/bypassAutoEncryption.yml +100 -0
  894. data/spec/spec_tests/data/client_side_encryption/bypassedCommand.yml +42 -0
  895. data/spec/spec_tests/data/client_side_encryption/count.yml +54 -0
  896. data/spec/spec_tests/data/client_side_encryption/countDocuments.yml +52 -0
  897. data/spec/spec_tests/data/client_side_encryption/create-and-createIndexes.yml +58 -0
  898. data/spec/spec_tests/data/client_side_encryption/delete.yml +91 -0
  899. data/spec/spec_tests/data/client_side_encryption/distinct.yml +66 -0
  900. data/spec/spec_tests/data/client_side_encryption/explain.yml +57 -0
  901. data/spec/spec_tests/data/client_side_encryption/find.yml +105 -0
  902. data/spec/spec_tests/data/client_side_encryption/findOneAndDelete.yml +50 -0
  903. data/spec/spec_tests/data/client_side_encryption/findOneAndReplace.yml +50 -0
  904. data/spec/spec_tests/data/client_side_encryption/findOneAndUpdate.yml +50 -0
  905. data/spec/spec_tests/data/client_side_encryption/fle2-BypassQueryAnalysis.yml +101 -0
  906. data/spec/spec_tests/data/client_side_encryption/fle2-Compact.yml +80 -0
  907. data/spec/spec_tests/data/client_side_encryption/fle2-CreateCollection.yml +1263 -0
  908. data/spec/spec_tests/data/client_side_encryption/fle2-DecryptExistingData.yml +64 -0
  909. data/spec/spec_tests/data/client_side_encryption/fle2-Delete.yml +107 -0
  910. data/spec/spec_tests/data/client_side_encryption/fle2-EncryptedFields-vs-EncryptedFieldsMap.yml +80 -0
  911. data/spec/spec_tests/data/client_side_encryption/fle2-EncryptedFields-vs-jsonSchema.yml +90 -0
  912. data/spec/spec_tests/data/client_side_encryption/fle2-EncryptedFieldsMap-defaults.yml +57 -0
  913. data/spec/spec_tests/data/client_side_encryption/fle2-FindOneAndUpdate.yml +213 -0
  914. data/spec/spec_tests/data/client_side_encryption/fle2-InsertFind-Indexed.yml +86 -0
  915. data/spec/spec_tests/data/client_side_encryption/fle2-InsertFind-Unindexed.yml +83 -0
  916. data/spec/spec_tests/data/client_side_encryption/fle2-MissingKey.yml +41 -0
  917. data/spec/spec_tests/data/client_side_encryption/fle2-NoEncryption.yml +42 -0
  918. data/spec/spec_tests/data/client_side_encryption/fle2-Update.yml +221 -0
  919. data/spec/spec_tests/data/client_side_encryption/fle2-validatorAndPartialFieldExpression.yml +168 -0
  920. data/spec/spec_tests/data/client_side_encryption/gcpKMS.yml +46 -0
  921. data/spec/spec_tests/data/client_side_encryption/getMore.yml +61 -0
  922. data/spec/spec_tests/data/client_side_encryption/insert.yml +88 -0
  923. data/spec/spec_tests/data/client_side_encryption/keyAltName.yml +64 -0
  924. data/spec/spec_tests/data/client_side_encryption/localKMS.yml +47 -0
  925. data/spec/spec_tests/data/client_side_encryption/localSchema.yml +65 -0
  926. data/spec/spec_tests/data/client_side_encryption/malformedCiphertext.yml +69 -0
  927. data/spec/spec_tests/data/client_side_encryption/maxWireVersion.yml +22 -0
  928. data/spec/spec_tests/data/client_side_encryption/missingKey.yml +42 -0
  929. data/spec/spec_tests/data/client_side_encryption/noSchema.yml +39 -0
  930. data/spec/spec_tests/data/client_side_encryption/replaceOne.yml +57 -0
  931. data/spec/spec_tests/data/client_side_encryption/types.yml +501 -0
  932. data/spec/spec_tests/data/client_side_encryption/unified/addKeyAltName.yml +194 -0
  933. data/spec/spec_tests/data/client_side_encryption/unified/createDataKey-kms_providers-invalid.yml +67 -0
  934. data/spec/spec_tests/data/client_side_encryption/unified/createDataKey.yml +309 -0
  935. data/spec/spec_tests/data/client_side_encryption/unified/deleteKey.yml +159 -0
  936. data/spec/spec_tests/data/client_side_encryption/unified/getKey.yml +105 -0
  937. data/spec/spec_tests/data/client_side_encryption/unified/getKeyByAltName.yml +104 -0
  938. data/spec/spec_tests/data/client_side_encryption/unified/getKeys.yml +122 -0
  939. data/spec/spec_tests/data/client_side_encryption/unified/removeKeyAltName.yml +157 -0
  940. data/spec/spec_tests/data/client_side_encryption/unified/rewrapManyDataKey-decrypt_failure.yml +69 -0
  941. data/spec/spec_tests/data/client_side_encryption/unified/rewrapManyDataKey-encrypt_failure.yml +122 -0
  942. data/spec/spec_tests/data/client_side_encryption/unified/rewrapManyDataKey.yml +432 -0
  943. data/spec/spec_tests/data/client_side_encryption/unsupportedCommand.yml +25 -0
  944. data/spec/spec_tests/data/client_side_encryption/updateMany.yml +70 -0
  945. data/spec/spec_tests/data/client_side_encryption/updateOne.yml +164 -0
  946. data/spec/spec_tests/data/client_side_encryption/validatorAndPartialFieldExpression.yml +166 -0
  947. data/spec/spec_tests/data/cmap/pool-checkout-connection.yml +6 -2
  948. data/spec/spec_tests/data/cmap/pool-create-min-size.yml +3 -0
  949. data/spec/spec_tests/data/collection_management/clustered-indexes.yml +135 -0
  950. data/spec/spec_tests/data/collection_management/createCollection-pre_and_post_images.yml +50 -0
  951. data/spec/spec_tests/data/collection_management/modifyCollection-pre_and_post_images.yml +58 -0
  952. data/spec/spec_tests/data/collection_management/timeseries-collection.yml +129 -0
  953. data/spec/spec_tests/data/command_monitoring_unified/bulkWrite.yml +68 -0
  954. data/spec/spec_tests/data/command_monitoring_unified/command.yml +50 -0
  955. data/spec/spec_tests/data/command_monitoring_unified/deleteMany.yml +79 -0
  956. data/spec/spec_tests/data/command_monitoring_unified/deleteOne.yml +79 -0
  957. data/spec/spec_tests/data/command_monitoring_unified/find.yml +254 -0
  958. data/spec/spec_tests/data/command_monitoring_unified/insertMany.yml +79 -0
  959. data/spec/spec_tests/data/command_monitoring_unified/insertOne.yml +77 -0
  960. data/spec/spec_tests/data/command_monitoring_unified/pre-42-server-connection-id.yml +56 -0
  961. data/spec/spec_tests/data/command_monitoring_unified/redacted-commands.yml +340 -0
  962. data/spec/spec_tests/data/command_monitoring_unified/server-connection-id.yml +56 -0
  963. data/spec/spec_tests/data/command_monitoring_unified/unacknowledgedBulkWrite.yml +55 -0
  964. data/spec/spec_tests/data/command_monitoring_unified/updateMany.yml +87 -0
  965. data/spec/spec_tests/data/command_monitoring_unified/updateOne.yml +118 -0
  966. data/spec/spec_tests/data/connection_string/valid-warnings.yml +24 -0
  967. data/spec/spec_tests/data/crud/read/aggregate-collation.yml +2 -1
  968. data/spec/spec_tests/data/crud/read/aggregate-out.yml +1 -0
  969. data/spec/spec_tests/data/crud/read/count-collation.yml +2 -1
  970. data/spec/spec_tests/data/crud/read/distinct-collation.yml +2 -1
  971. data/spec/spec_tests/data/crud/read/find-collation.yml +2 -1
  972. data/spec/spec_tests/data/crud/write/bulkWrite-collation.yml +2 -1
  973. data/spec/spec_tests/data/crud/write/bulkWrite.yml +26 -22
  974. data/spec/spec_tests/data/crud/write/deleteMany-collation.yml +2 -1
  975. data/spec/spec_tests/data/crud/write/deleteOne-collation.yml +2 -1
  976. data/spec/spec_tests/data/crud/write/findOneAndDelete-collation.yml +3 -2
  977. data/spec/spec_tests/data/crud/write/findOneAndReplace-collation.yml +2 -1
  978. data/spec/spec_tests/data/crud/write/findOneAndUpdate-collation.yml +3 -2
  979. data/spec/spec_tests/data/crud/write/insertMany.yml +26 -22
  980. data/spec/spec_tests/data/crud/write/replaceOne-collation.yml +3 -2
  981. data/spec/spec_tests/data/crud/write/updateMany-collation.yml +2 -1
  982. data/spec/spec_tests/data/crud/write/updateOne-collation.yml +2 -1
  983. data/spec/spec_tests/data/crud_unified/aggregate-allowdiskuse.yml +75 -0
  984. data/spec/spec_tests/data/crud_unified/aggregate-let.yml +138 -0
  985. data/spec/spec_tests/data/crud_unified/aggregate-merge.yml +185 -0
  986. data/spec/spec_tests/data/crud_unified/aggregate-out-readConcern.yml +171 -0
  987. data/spec/spec_tests/data/crud_unified/aggregate-write-readPreference.yml +155 -0
  988. data/spec/spec_tests/data/crud_unified/aggregate.yml +215 -0
  989. data/spec/spec_tests/data/crud_unified/bulkWrite-arrayFilters-clientError.yml +98 -0
  990. data/spec/spec_tests/data/crud_unified/bulkWrite-arrayFilters.yml +174 -0
  991. data/spec/spec_tests/data/crud_unified/bulkWrite-comment.yml +189 -0
  992. data/spec/spec_tests/data/crud_unified/bulkWrite-delete-hint-clientError.yml +113 -0
  993. data/spec/spec_tests/data/crud_unified/bulkWrite-delete-hint-serverError.yml +142 -0
  994. data/spec/spec_tests/data/crud_unified/bulkWrite-delete-hint.yml +154 -0
  995. data/spec/spec_tests/data/crud_unified/bulkWrite-deleteMany-hint-unacknowledged.yml +98 -0
  996. data/spec/spec_tests/data/crud_unified/bulkWrite-deleteMany-let.yml +86 -0
  997. data/spec/spec_tests/data/crud_unified/bulkWrite-deleteOne-hint-unacknowledged.yml +97 -0
  998. data/spec/spec_tests/data/crud_unified/bulkWrite-deleteOne-let.yml +86 -0
  999. data/spec/spec_tests/data/crud_unified/bulkWrite-insertOne-dots_and_dollars.yml +138 -0
  1000. data/spec/spec_tests/data/crud_unified/bulkWrite-replaceOne-dots_and_dollars.yml +165 -0
  1001. data/spec/spec_tests/data/crud_unified/bulkWrite-replaceOne-hint-unacknowledged.yml +103 -0
  1002. data/spec/spec_tests/data/crud_unified/bulkWrite-replaceOne-let.yml +93 -0
  1003. data/spec/spec_tests/data/crud_unified/bulkWrite-update-hint-clientError.yml +148 -0
  1004. data/spec/spec_tests/data/crud_unified/bulkWrite-update-hint-serverError.yml +239 -0
  1005. data/spec/spec_tests/data/crud_unified/bulkWrite-update-hint.yml +256 -0
  1006. data/spec/spec_tests/data/crud_unified/bulkWrite-update-validation.yml +73 -0
  1007. data/spec/spec_tests/data/crud_unified/bulkWrite-updateMany-dots_and_dollars.yml +150 -0
  1008. data/spec/spec_tests/data/crud_unified/bulkWrite-updateMany-hint-unacknowledged.yml +104 -0
  1009. data/spec/spec_tests/data/crud_unified/bulkWrite-updateMany-let.yml +96 -0
  1010. data/spec/spec_tests/data/crud_unified/bulkWrite-updateOne-dots_and_dollars.yml +150 -0
  1011. data/spec/spec_tests/data/crud_unified/bulkWrite-updateOne-hint-unacknowledged.yml +103 -0
  1012. data/spec/spec_tests/data/crud_unified/bulkWrite-updateOne-let.yml +95 -0
  1013. data/spec/spec_tests/data/crud_unified/countDocuments-comment.yml +92 -0
  1014. data/spec/spec_tests/data/crud_unified/db-aggregate-write-readPreference.yml +151 -0
  1015. data/spec/spec_tests/data/crud_unified/db-aggregate.yml +73 -0
  1016. data/spec/spec_tests/data/crud_unified/deleteMany-comment.yml +97 -0
  1017. data/spec/spec_tests/data/crud_unified/deleteMany-hint-clientError.yml +87 -0
  1018. data/spec/spec_tests/data/crud_unified/deleteMany-hint-serverError.yml +107 -0
  1019. data/spec/spec_tests/data/crud_unified/deleteMany-hint-unacknowledged.yml +90 -0
  1020. data/spec/spec_tests/data/crud_unified/deleteMany-hint.yml +99 -0
  1021. data/spec/spec_tests/data/crud_unified/deleteMany-let.yml +93 -0
  1022. data/spec/spec_tests/data/crud_unified/deleteOne-comment.yml +98 -0
  1023. data/spec/spec_tests/data/crud_unified/deleteOne-hint-clientError.yml +80 -0
  1024. data/spec/spec_tests/data/crud_unified/deleteOne-hint-serverError.yml +100 -0
  1025. data/spec/spec_tests/data/crud_unified/deleteOne-hint-unacknowledged.yml +89 -0
  1026. data/spec/spec_tests/data/crud_unified/deleteOne-hint.yml +95 -0
  1027. data/spec/spec_tests/data/crud_unified/deleteOne-let.yml +91 -0
  1028. data/spec/spec_tests/data/crud_unified/distinct-comment.yml +98 -0
  1029. data/spec/spec_tests/data/crud_unified/estimatedDocumentCount-comment.yml +95 -0
  1030. data/spec/spec_tests/data/crud_unified/estimatedDocumentCount.yml +137 -0
  1031. data/spec/spec_tests/data/crud_unified/find-allowdiskuse-clientError.yml +55 -0
  1032. data/spec/spec_tests/data/crud_unified/find-allowdiskuse-serverError.yml +68 -0
  1033. data/spec/spec_tests/data/crud_unified/find-allowdiskuse.yml +79 -0
  1034. data/spec/spec_tests/data/crud_unified/find-comment.yml +166 -0
  1035. data/spec/spec_tests/data/crud_unified/find-let.yml +71 -0
  1036. data/spec/spec_tests/data/crud_unified/find.yml +68 -0
  1037. data/spec/spec_tests/data/crud_unified/findOneAndDelete-comment.yml +96 -0
  1038. data/spec/spec_tests/data/crud_unified/findOneAndDelete-hint-clientError.yml +91 -0
  1039. data/spec/spec_tests/data/crud_unified/findOneAndDelete-hint-serverError.yml +107 -0
  1040. data/spec/spec_tests/data/crud_unified/findOneAndDelete-hint-unacknowledged.yml +88 -0
  1041. data/spec/spec_tests/data/crud_unified/findOneAndDelete-hint.yml +102 -0
  1042. data/spec/spec_tests/data/crud_unified/findOneAndDelete-let.yml +86 -0
  1043. data/spec/spec_tests/data/crud_unified/findOneAndReplace-comment.yml +101 -0
  1044. data/spec/spec_tests/data/crud_unified/findOneAndReplace-dots_and_dollars.yml +140 -0
  1045. data/spec/spec_tests/data/crud_unified/findOneAndReplace-hint-clientError.yml +83 -0
  1046. data/spec/spec_tests/data/crud_unified/findOneAndReplace-hint-serverError.yml +99 -0
  1047. data/spec/spec_tests/data/crud_unified/findOneAndReplace-hint-unacknowledged.yml +96 -0
  1048. data/spec/spec_tests/data/crud_unified/findOneAndReplace-hint.yml +98 -0
  1049. data/spec/spec_tests/data/crud_unified/findOneAndReplace-let.yml +94 -0
  1050. data/spec/spec_tests/data/crud_unified/findOneAndUpdate-comment.yml +95 -0
  1051. data/spec/spec_tests/data/crud_unified/findOneAndUpdate-dots_and_dollars.yml +127 -0
  1052. data/spec/spec_tests/data/crud_unified/findOneAndUpdate-hint-clientError.yml +84 -0
  1053. data/spec/spec_tests/data/crud_unified/findOneAndUpdate-hint-serverError.yml +100 -0
  1054. data/spec/spec_tests/data/crud_unified/findOneAndUpdate-hint-unacknowledged.yml +92 -0
  1055. data/spec/spec_tests/data/crud_unified/findOneAndUpdate-hint.yml +99 -0
  1056. data/spec/spec_tests/data/crud_unified/findOneAndUpdate-let.yml +96 -0
  1057. data/spec/spec_tests/data/crud_unified/insertMany-comment.yml +93 -0
  1058. data/spec/spec_tests/data/crud_unified/insertMany-dots_and_dollars.yml +128 -0
  1059. data/spec/spec_tests/data/crud_unified/insertOne-comment.yml +91 -0
  1060. data/spec/spec_tests/data/crud_unified/insertOne-dots_and_dollars.yml +238 -0
  1061. data/spec/spec_tests/data/crud_unified/replaceOne-comment.yml +105 -0
  1062. data/spec/spec_tests/data/crud_unified/replaceOne-dots_and_dollars.yml +180 -0
  1063. data/spec/spec_tests/data/crud_unified/replaceOne-hint-unacknowledged.yml +95 -0
  1064. data/spec/spec_tests/data/crud_unified/replaceOne-hint.yml +108 -0
  1065. data/spec/spec_tests/data/crud_unified/replaceOne-let.yml +98 -0
  1066. data/spec/spec_tests/data/crud_unified/replaceOne-validation.yml +37 -0
  1067. data/spec/spec_tests/data/crud_unified/updateMany-comment.yml +104 -0
  1068. data/spec/spec_tests/data/crud_unified/updateMany-dots_and_dollars.yml +138 -0
  1069. data/spec/spec_tests/data/crud_unified/updateMany-hint-clientError.yml +91 -0
  1070. data/spec/spec_tests/data/crud_unified/updateMany-hint-serverError.yml +115 -0
  1071. data/spec/spec_tests/data/crud_unified/updateMany-hint-unacknowledged.yml +96 -0
  1072. data/spec/spec_tests/data/crud_unified/updateMany-hint.yml +115 -0
  1073. data/spec/spec_tests/data/crud_unified/updateMany-let.yml +107 -0
  1074. data/spec/spec_tests/data/crud_unified/updateMany-validation.yml +39 -0
  1075. data/spec/spec_tests/data/crud_unified/updateOne-comment.yml +104 -0
  1076. data/spec/spec_tests/data/crud_unified/updateOne-dots_and_dollars.yml +138 -0
  1077. data/spec/spec_tests/data/crud_unified/updateOne-hint-clientError.yml +85 -0
  1078. data/spec/spec_tests/data/crud_unified/updateOne-hint-serverError.yml +109 -0
  1079. data/spec/spec_tests/data/crud_unified/updateOne-hint-unacknowledged.yml +95 -0
  1080. data/spec/spec_tests/data/crud_unified/updateOne-hint.yml +109 -0
  1081. data/spec/spec_tests/data/crud_unified/updateOne-let.yml +102 -0
  1082. data/spec/spec_tests/data/crud_unified/updateOne-validation.yml +37 -0
  1083. data/spec/spec_tests/data/crud_unified/updateWithPipelines.yml +299 -0
  1084. data/spec/spec_tests/data/gridfs_unified/delete.yml +198 -0
  1085. data/spec/spec_tests/data/gridfs_unified/download.yml +241 -0
  1086. data/spec/spec_tests/data/gridfs_unified/downloadByName.yml +159 -0
  1087. data/spec/spec_tests/data/gridfs_unified/upload-disableMD5.yml +92 -0
  1088. data/spec/spec_tests/data/gridfs_unified/upload.yml +288 -0
  1089. data/spec/spec_tests/data/load_balancers/event-monitoring.yml +99 -0
  1090. data/spec/spec_tests/data/load_balancers/lb-connection-establishment.yml +36 -0
  1091. data/spec/spec_tests/data/load_balancers/non-lb-connection-establishment.yml +56 -0
  1092. data/spec/spec_tests/data/load_balancers/server-selection.yml +50 -0
  1093. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/DefaultNoMaxStaleness.yml +2 -2
  1094. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/LastUpdateTime.yml +3 -3
  1095. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/MaxStalenessTooSmall.yml +15 -0
  1096. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Nearest.yml +3 -3
  1097. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Nearest2.yml +3 -3
  1098. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/NoKnownServers.yml +4 -3
  1099. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred.yml +2 -2
  1100. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred_tags.yml +2 -2
  1101. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Secondary.yml +4 -4
  1102. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred.yml +2 -2
  1103. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred_tags.yml +4 -4
  1104. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/ZeroMaxStaleness.yml +2 -2
  1105. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/DefaultNoMaxStaleness.yml +2 -2
  1106. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LastUpdateTime.yml +3 -3
  1107. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LongHeartbeat.yml +2 -2
  1108. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LongHeartbeat2.yml +2 -2
  1109. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/MaxStalenessTooSmall.yml +2 -2
  1110. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/MaxStalenessWithModePrimary.yml +2 -2
  1111. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest.yml +3 -3
  1112. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest2.yml +3 -3
  1113. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest_tags.yml +2 -2
  1114. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred.yml +2 -2
  1115. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred.yml +2 -2
  1116. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags.yml +5 -5
  1117. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags2.yml +3 -3
  1118. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Secondary_tags.yml +5 -5
  1119. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Secondary_tags2.yml +3 -3
  1120. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/ZeroMaxStaleness.yml +2 -2
  1121. data/spec/spec_tests/data/max_staleness/Sharded/SmallMaxStaleness.yml +2 -2
  1122. data/spec/spec_tests/data/max_staleness/Single/SmallMaxStaleness.yml +1 -1
  1123. data/spec/spec_tests/data/max_staleness/Unknown/SmallMaxStaleness.yml +1 -0
  1124. data/spec/spec_tests/data/read_write_concern/connection-string/write-concern.yml +1 -4
  1125. data/spec/spec_tests/data/read_write_concern/operation/default-write-concern-2.6.yml +215 -0
  1126. data/spec/spec_tests/data/read_write_concern/operation/default-write-concern-3.2.yml +58 -0
  1127. data/spec/spec_tests/data/read_write_concern/operation/default-write-concern-3.4.yml +95 -0
  1128. data/spec/spec_tests/data/read_write_concern/operation/default-write-concern-4.2.yml +36 -0
  1129. data/spec/spec_tests/data/retryable_reads/{aggregate-serverErrors.yml → legacy/aggregate-serverErrors.yml} +1 -1
  1130. data/spec/spec_tests/data/retryable_reads/{changeStreams-client.watch-serverErrors.yml → legacy/changeStreams-client.watch-serverErrors.yml} +7 -6
  1131. data/spec/spec_tests/data/retryable_reads/{changeStreams-client.watch.yml → legacy/changeStreams-client.watch.yml} +2 -1
  1132. data/spec/spec_tests/data/retryable_reads/{changeStreams-db.coll.watch-serverErrors.yml → legacy/changeStreams-db.coll.watch-serverErrors.yml} +7 -6
  1133. data/spec/spec_tests/data/retryable_reads/{changeStreams-db.coll.watch.yml → legacy/changeStreams-db.coll.watch.yml} +2 -1
  1134. data/spec/spec_tests/data/retryable_reads/{changeStreams-db.watch-serverErrors.yml → legacy/changeStreams-db.watch-serverErrors.yml} +7 -6
  1135. data/spec/spec_tests/data/retryable_reads/{changeStreams-db.watch.yml → legacy/changeStreams-db.watch.yml} +2 -1
  1136. data/spec/spec_tests/data/retryable_reads/{count-serverErrors.yml → legacy/count-serverErrors.yml} +1 -1
  1137. data/spec/spec_tests/data/retryable_reads/{countDocuments-serverErrors.yml → legacy/countDocuments-serverErrors.yml} +1 -1
  1138. data/spec/spec_tests/data/retryable_reads/{distinct-serverErrors.yml → legacy/distinct-serverErrors.yml} +1 -1
  1139. data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount-serverErrors.yml → legacy/estimatedDocumentCount-serverErrors.yml} +1 -1
  1140. data/spec/spec_tests/data/retryable_reads/{find-serverErrors.yml → legacy/find-serverErrors.yml} +1 -1
  1141. data/spec/spec_tests/data/retryable_reads/{findOne-serverErrors.yml → legacy/findOne-serverErrors.yml} +1 -1
  1142. data/spec/spec_tests/data/retryable_reads/{gridfs-download-serverErrors.yml → legacy/gridfs-download-serverErrors.yml} +1 -1
  1143. data/spec/spec_tests/data/retryable_reads/{gridfs-downloadByName-serverErrors.yml → legacy/gridfs-downloadByName-serverErrors.yml} +1 -1
  1144. data/spec/spec_tests/data/retryable_reads/{listCollectionNames-serverErrors.yml → legacy/listCollectionNames-serverErrors.yml} +1 -1
  1145. data/spec/spec_tests/data/retryable_reads/{listCollectionObjects-serverErrors.yml → legacy/listCollectionObjects-serverErrors.yml} +1 -1
  1146. data/spec/spec_tests/data/retryable_reads/{listCollections-serverErrors.yml → legacy/listCollections-serverErrors.yml} +1 -1
  1147. data/spec/spec_tests/data/retryable_reads/{listDatabaseNames-serverErrors.yml → legacy/listDatabaseNames-serverErrors.yml} +1 -1
  1148. data/spec/spec_tests/data/retryable_reads/{listDatabaseObjects-serverErrors.yml → legacy/listDatabaseObjects-serverErrors.yml} +1 -1
  1149. data/spec/spec_tests/data/retryable_reads/{listDatabases-serverErrors.yml → legacy/listDatabases-serverErrors.yml} +1 -1
  1150. data/spec/spec_tests/data/retryable_reads/{listIndexNames-serverErrors.yml → legacy/listIndexNames-serverErrors.yml} +1 -1
  1151. data/spec/spec_tests/data/retryable_reads/{listIndexNames.yml → legacy/listIndexNames.yml} +1 -1
  1152. data/spec/spec_tests/data/retryable_reads/{listIndexes-serverErrors.yml → legacy/listIndexes-serverErrors.yml} +1 -1
  1153. data/spec/spec_tests/data/retryable_reads/{mapReduce.yml → legacy/mapReduce.yml} +3 -1
  1154. data/spec/spec_tests/data/retryable_reads/unified/handshakeError.yml +129 -0
  1155. data/spec/spec_tests/data/retryable_writes/legacy/bulkWrite-errorLabels.yml +77 -0
  1156. data/spec/spec_tests/data/retryable_writes/{bulkWrite-serverErrors.yml → legacy/bulkWrite-serverErrors.yml} +37 -0
  1157. data/spec/spec_tests/data/retryable_writes/{bulkWrite.yml → legacy/bulkWrite.yml} +30 -24
  1158. data/spec/spec_tests/data/retryable_writes/legacy/deleteOne-errorLabels.yml +48 -0
  1159. data/spec/spec_tests/data/retryable_writes/{deleteOne-serverErrors.yml → legacy/deleteOne-serverErrors.yml} +22 -0
  1160. data/spec/spec_tests/data/retryable_writes/legacy/findOneAndDelete-errorLabels.yml +49 -0
  1161. data/spec/spec_tests/data/retryable_writes/{findOneAndDelete-serverErrors.yml → legacy/findOneAndDelete-serverErrors.yml} +23 -0
  1162. data/spec/spec_tests/data/retryable_writes/legacy/findOneAndReplace-errorLabels.yml +52 -0
  1163. data/spec/spec_tests/data/retryable_writes/{findOneAndReplace-serverErrors.yml → legacy/findOneAndReplace-serverErrors.yml} +25 -0
  1164. data/spec/spec_tests/data/retryable_writes/legacy/findOneAndUpdate-errorLabels.yml +52 -0
  1165. data/spec/spec_tests/data/retryable_writes/{findOneAndUpdate-serverErrors.yml → legacy/findOneAndUpdate-serverErrors.yml} +24 -0
  1166. data/spec/spec_tests/data/retryable_writes/legacy/insertMany-errorLabels.yml +54 -0
  1167. data/spec/spec_tests/data/retryable_writes/{insertMany-serverErrors.yml → legacy/insertMany-serverErrors.yml} +24 -0
  1168. data/spec/spec_tests/data/retryable_writes/legacy/insertOne-errorLabels.yml +44 -0
  1169. data/spec/spec_tests/data/retryable_writes/{insertOne-serverErrors.yml → legacy/insertOne-serverErrors.yml} +94 -3
  1170. data/spec/spec_tests/data/retryable_writes/legacy/replaceOne-errorLabels.yml +53 -0
  1171. data/spec/spec_tests/data/retryable_writes/{replaceOne-serverErrors.yml → legacy/replaceOne-serverErrors.yml} +23 -0
  1172. data/spec/spec_tests/data/retryable_writes/legacy/updateOne-errorLabels.yml +53 -0
  1173. data/spec/spec_tests/data/retryable_writes/{updateOne-serverErrors.yml → legacy/updateOne-serverErrors.yml} +23 -0
  1174. data/spec/spec_tests/data/retryable_writes/unified/bulkWrite-serverErrors.yml +96 -0
  1175. data/spec/spec_tests/data/retryable_writes/unified/handshakeError.yml +137 -0
  1176. data/spec/spec_tests/data/retryable_writes/unified/insertOne-serverErrors.yml +78 -0
  1177. data/spec/spec_tests/data/sdam/errors/error_handling_handshake.yml +55 -0
  1178. data/spec/spec_tests/data/sdam/errors/non-stale-network-error.yml +47 -0
  1179. data/spec/spec_tests/data/sdam/errors/non-stale-network-timeout-error.yml +38 -0
  1180. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-greater-InterruptedAtShutdown.yml +61 -0
  1181. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-greater-InterruptedDueToReplStateChange.yml +61 -0
  1182. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-greater-LegacyNotPrimary.yml +61 -0
  1183. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-greater-NotPrimaryNoSecondaryOk.yml +61 -0
  1184. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-greater-NotPrimaryOrSecondary.yml +61 -0
  1185. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-greater-NotWritablePrimary.yml +61 -0
  1186. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-greater-PrimarySteppedDown.yml +61 -0
  1187. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-greater-ShutdownInProgress.yml +61 -0
  1188. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-missing-InterruptedAtShutdown.yml +52 -0
  1189. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-missing-InterruptedDueToReplStateChange.yml +52 -0
  1190. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-missing-LegacyNotPrimary.yml +52 -0
  1191. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-missing-NotPrimaryNoSecondaryOk.yml +52 -0
  1192. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-missing-NotPrimaryOrSecondary.yml +52 -0
  1193. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-missing-NotWritablePrimary.yml +52 -0
  1194. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-missing-PrimarySteppedDown.yml +52 -0
  1195. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-missing-ShutdownInProgress.yml +52 -0
  1196. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-proccessId-changed-InterruptedAtShutdown.yml +61 -0
  1197. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-proccessId-changed-InterruptedDueToReplStateChange.yml +61 -0
  1198. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-proccessId-changed-LegacyNotPrimary.yml +61 -0
  1199. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-proccessId-changed-NotPrimaryNoSecondaryOk.yml +61 -0
  1200. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-proccessId-changed-NotPrimaryOrSecondary.yml +61 -0
  1201. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-proccessId-changed-NotWritablePrimary.yml +61 -0
  1202. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-proccessId-changed-PrimarySteppedDown.yml +61 -0
  1203. data/spec/spec_tests/data/sdam/errors/non-stale-topologyVersion-proccessId-changed-ShutdownInProgress.yml +61 -0
  1204. data/spec/spec_tests/data/sdam/errors/post-42-InterruptedAtShutdown.yml +47 -0
  1205. data/spec/spec_tests/data/sdam/errors/post-42-InterruptedDueToReplStateChange.yml +47 -0
  1206. data/spec/spec_tests/data/sdam/errors/post-42-LegacyNotPrimary.yml +47 -0
  1207. data/spec/spec_tests/data/sdam/errors/post-42-NotPrimaryNoSecondaryOk.yml +47 -0
  1208. data/spec/spec_tests/data/sdam/errors/post-42-NotPrimaryOrSecondary.yml +47 -0
  1209. data/spec/spec_tests/data/sdam/errors/post-42-NotWritablePrimary.yml +47 -0
  1210. data/spec/spec_tests/data/sdam/errors/post-42-PrimarySteppedDown.yml +47 -0
  1211. data/spec/spec_tests/data/sdam/errors/post-42-ShutdownInProgress.yml +47 -0
  1212. data/spec/spec_tests/data/sdam/errors/pre-42-InterruptedAtShutdown.yml +47 -0
  1213. data/spec/spec_tests/data/sdam/errors/pre-42-InterruptedDueToReplStateChange.yml +47 -0
  1214. data/spec/spec_tests/data/sdam/errors/pre-42-LegacyNotPrimary.yml +47 -0
  1215. data/spec/spec_tests/data/sdam/errors/pre-42-NotPrimaryNoSecondaryOk.yml +47 -0
  1216. data/spec/spec_tests/data/sdam/errors/pre-42-NotPrimaryOrSecondary.yml +47 -0
  1217. data/spec/spec_tests/data/sdam/errors/pre-42-NotWritablePrimary.yml +47 -0
  1218. data/spec/spec_tests/data/sdam/errors/pre-42-PrimarySteppedDown.yml +47 -0
  1219. data/spec/spec_tests/data/sdam/errors/pre-42-ShutdownInProgress.yml +47 -0
  1220. data/spec/spec_tests/data/sdam/errors/prefer-error-code.yml +54 -0
  1221. data/spec/spec_tests/data/sdam/errors/stale-generation-InterruptedAtShutdown.yml +91 -0
  1222. data/spec/spec_tests/data/sdam/errors/stale-generation-InterruptedDueToReplStateChange.yml +91 -0
  1223. data/spec/spec_tests/data/sdam/errors/stale-generation-NotPrimaryNoSecondaryOk.yml +91 -0
  1224. data/spec/spec_tests/data/sdam/errors/stale-generation-NotPrimaryOrSecondary.yml +91 -0
  1225. data/spec/spec_tests/data/sdam/errors/stale-generation-NotWritablePrimary.yml +91 -0
  1226. data/spec/spec_tests/data/sdam/errors/stale-generation-PrimarySteppedDown.yml +91 -0
  1227. data/spec/spec_tests/data/sdam/errors/stale-generation-ShutdownInProgress.yml +91 -0
  1228. data/spec/spec_tests/data/sdam/errors/stale-generation-afterHandshakeCompletes-InterruptedAtShutdown.yml +91 -0
  1229. data/spec/spec_tests/data/sdam/errors/stale-generation-afterHandshakeCompletes-InterruptedDueToReplStateChange.yml +91 -0
  1230. data/spec/spec_tests/data/sdam/errors/stale-generation-afterHandshakeCompletes-LegacyNotPrimary.yml +91 -0
  1231. data/spec/spec_tests/data/sdam/errors/stale-generation-afterHandshakeCompletes-NotPrimaryNoSecondaryOk.yml +91 -0
  1232. data/spec/spec_tests/data/sdam/errors/stale-generation-afterHandshakeCompletes-NotPrimaryOrSecondary.yml +91 -0
  1233. data/spec/spec_tests/data/sdam/errors/stale-generation-afterHandshakeCompletes-NotWritablePrimary.yml +91 -0
  1234. data/spec/spec_tests/data/sdam/errors/stale-generation-afterHandshakeCompletes-PrimarySteppedDown.yml +91 -0
  1235. data/spec/spec_tests/data/sdam/errors/stale-generation-afterHandshakeCompletes-ShutdownInProgress.yml +91 -0
  1236. data/spec/spec_tests/data/sdam/errors/stale-generation-afterHandshakeCompletes-network.yml +82 -0
  1237. data/spec/spec_tests/data/sdam/errors/stale-generation-afterHandshakeCompletes-timeout.yml +82 -0
  1238. data/spec/spec_tests/data/sdam/errors/stale-generation-beforeHandshakeCompletes-InterruptedAtShutdown.yml +91 -0
  1239. data/spec/spec_tests/data/sdam/errors/stale-generation-beforeHandshakeCompletes-InterruptedDueToReplStateChange.yml +91 -0
  1240. data/spec/spec_tests/data/sdam/errors/stale-generation-beforeHandshakeCompletes-LegacyNotPrimary.yml +91 -0
  1241. data/spec/spec_tests/data/sdam/errors/stale-generation-beforeHandshakeCompletes-NotPrimaryNoSecondaryOk.yml +91 -0
  1242. data/spec/spec_tests/data/sdam/errors/stale-generation-beforeHandshakeCompletes-NotPrimaryOrSecondary.yml +91 -0
  1243. data/spec/spec_tests/data/sdam/errors/stale-generation-beforeHandshakeCompletes-NotWritablePrimary.yml +91 -0
  1244. data/spec/spec_tests/data/sdam/errors/stale-generation-beforeHandshakeCompletes-PrimarySteppedDown.yml +91 -0
  1245. data/spec/spec_tests/data/sdam/errors/stale-generation-beforeHandshakeCompletes-ShutdownInProgress.yml +91 -0
  1246. data/spec/spec_tests/data/sdam/errors/stale-generation-beforeHandshakeCompletes-network.yml +82 -0
  1247. data/spec/spec_tests/data/sdam/errors/stale-generation-beforeHandshakeCompletes-timeout.yml +82 -0
  1248. data/spec/spec_tests/data/sdam/errors/stale-topologyVersion-InterruptedAtShutdown.yml +65 -0
  1249. data/spec/spec_tests/data/sdam/errors/stale-topologyVersion-InterruptedDueToReplStateChange.yml +65 -0
  1250. data/spec/spec_tests/data/sdam/errors/stale-topologyVersion-LegacyNotPrimary.yml +65 -0
  1251. data/spec/spec_tests/data/sdam/errors/stale-topologyVersion-NotPrimaryNoSecondaryOk.yml +65 -0
  1252. data/spec/spec_tests/data/sdam/errors/stale-topologyVersion-NotPrimaryOrSecondary.yml +65 -0
  1253. data/spec/spec_tests/data/sdam/errors/stale-topologyVersion-NotWritablePrimary.yml +65 -0
  1254. data/spec/spec_tests/data/sdam/errors/stale-topologyVersion-PrimarySteppedDown.yml +65 -0
  1255. data/spec/spec_tests/data/sdam/errors/stale-topologyVersion-ShutdownInProgress.yml +65 -0
  1256. data/spec/spec_tests/data/sdam/errors/write_errors_ignored.yml +42 -0
  1257. data/spec/spec_tests/data/sdam/load-balanced/discover_load_balancer.yml +25 -0
  1258. data/spec/spec_tests/data/sdam/rs/compatible.yml +6 -2
  1259. data/spec/spec_tests/data/sdam/rs/compatible_unknown.yml +4 -1
  1260. data/spec/spec_tests/data/sdam/rs/discover_arbiters.yml +4 -3
  1261. data/spec/spec_tests/data/sdam/rs/discover_arbiters_replicaset.yml +44 -0
  1262. data/spec/spec_tests/data/sdam/rs/discover_ghost.yml +36 -0
  1263. data/spec/spec_tests/data/sdam/rs/{ghost_discovered.yml → discover_ghost_replicaset.yml} +3 -2
  1264. data/spec/spec_tests/data/sdam/rs/discover_hidden.yml +51 -0
  1265. data/spec/spec_tests/data/sdam/rs/discover_hidden_replicaset.yml +51 -0
  1266. data/spec/spec_tests/data/sdam/rs/discover_passives.yml +6 -4
  1267. data/spec/spec_tests/data/sdam/rs/discover_passives_replicaset.yml +83 -0
  1268. data/spec/spec_tests/data/sdam/rs/discover_primary.yml +4 -3
  1269. data/spec/spec_tests/data/sdam/rs/discover_primary_replicaset.yml +43 -0
  1270. data/spec/spec_tests/data/sdam/rs/discover_rsother.yml +50 -0
  1271. data/spec/spec_tests/data/sdam/rs/{rsother_discovered.yml → discover_rsother_replicaset.yml} +5 -3
  1272. data/spec/spec_tests/data/sdam/rs/discover_secondary.yml +4 -3
  1273. data/spec/spec_tests/data/sdam/rs/discover_secondary_replicaset.yml +44 -0
  1274. data/spec/spec_tests/data/sdam/rs/discovery.yml +8 -4
  1275. data/spec/spec_tests/data/sdam/rs/equal_electionids.yml +4 -2
  1276. data/spec/spec_tests/data/sdam/rs/hosts_differ_from_seeds.yml +2 -1
  1277. data/spec/spec_tests/data/sdam/rs/incompatible_arbiter.yml +5 -1
  1278. data/spec/spec_tests/data/sdam/rs/incompatible_ghost.yml +7 -5
  1279. data/spec/spec_tests/data/sdam/rs/incompatible_other.yml +6 -2
  1280. data/spec/spec_tests/data/sdam/rs/ls_timeout.yml +12 -6
  1281. data/spec/spec_tests/data/sdam/rs/member_reconfig.yml +4 -2
  1282. data/spec/spec_tests/data/sdam/rs/member_standalone.yml +4 -2
  1283. data/spec/spec_tests/data/sdam/rs/new_primary.yml +4 -2
  1284. data/spec/spec_tests/data/sdam/rs/new_primary_new_electionid.yml +6 -3
  1285. data/spec/spec_tests/data/sdam/rs/new_primary_new_setversion.yml +6 -3
  1286. data/spec/spec_tests/data/sdam/rs/new_primary_wrong_set_name.yml +4 -2
  1287. data/spec/spec_tests/data/sdam/rs/non_rs_member.yml +1 -0
  1288. data/spec/spec_tests/data/sdam/rs/normalize_case.yml +2 -1
  1289. data/spec/spec_tests/data/sdam/rs/normalize_case_me.yml +4 -2
  1290. data/spec/spec_tests/data/sdam/rs/null_election_id.yml +8 -4
  1291. data/spec/spec_tests/data/sdam/rs/primary_becomes_ghost.yml +4 -2
  1292. data/spec/spec_tests/data/sdam/rs/primary_becomes_mongos.yml +4 -2
  1293. data/spec/spec_tests/data/sdam/rs/primary_becomes_standalone.yml +2 -1
  1294. data/spec/spec_tests/data/sdam/rs/primary_changes_set_name.yml +4 -2
  1295. data/spec/spec_tests/data/sdam/rs/primary_disconnect.yml +2 -1
  1296. data/spec/spec_tests/data/sdam/rs/primary_disconnect_electionid.yml +10 -5
  1297. data/spec/spec_tests/data/sdam/rs/primary_disconnect_setversion.yml +10 -5
  1298. data/spec/spec_tests/data/sdam/rs/primary_hint_from_secondary_with_mismatched_me.yml +4 -2
  1299. data/spec/spec_tests/data/sdam/rs/primary_mismatched_me.yml +24 -27
  1300. data/spec/spec_tests/data/sdam/rs/primary_mismatched_me_not_removed.yml +75 -0
  1301. data/spec/spec_tests/data/sdam/rs/primary_reports_new_member.yml +8 -4
  1302. data/spec/spec_tests/data/sdam/rs/primary_to_no_primary_mismatched_me.yml +81 -56
  1303. data/spec/spec_tests/data/sdam/rs/primary_wrong_set_name.yml +2 -1
  1304. data/spec/spec_tests/data/sdam/rs/repeated.yml +105 -0
  1305. data/spec/spec_tests/data/sdam/rs/replicaset_rsnp.yml +21 -0
  1306. data/spec/spec_tests/data/sdam/rs/response_from_removed.yml +4 -2
  1307. data/spec/spec_tests/data/sdam/rs/{primary_address_change.yml → ruby_primary_address_change.yml} +2 -0
  1308. data/spec/spec_tests/data/sdam/rs/sec_not_auth.yml +4 -2
  1309. data/spec/spec_tests/data/sdam/rs/secondary_ignore_ok_0.yml +4 -2
  1310. data/spec/spec_tests/data/sdam/rs/secondary_mismatched_me.yml +5 -3
  1311. data/spec/spec_tests/data/sdam/rs/secondary_wrong_set_name.yml +2 -1
  1312. data/spec/spec_tests/data/sdam/rs/secondary_wrong_set_name_with_primary.yml +4 -2
  1313. data/spec/spec_tests/data/sdam/rs/setversion_without_electionid.yml +4 -2
  1314. data/spec/spec_tests/data/sdam/rs/stepdown_change_set_name.yml +4 -2
  1315. data/spec/spec_tests/data/sdam/rs/too_new.yml +6 -2
  1316. data/spec/spec_tests/data/sdam/rs/too_old.yml +4 -2
  1317. data/spec/spec_tests/data/sdam/rs/topology_version_equal.yml +68 -0
  1318. data/spec/spec_tests/data/sdam/rs/topology_version_greater.yml +194 -0
  1319. data/spec/spec_tests/data/sdam/rs/topology_version_less.yml +64 -0
  1320. data/spec/spec_tests/data/sdam/rs/unexpected_mongos.yml +2 -1
  1321. data/spec/spec_tests/data/sdam/rs/use_setversion_without_electionid.yml +6 -3
  1322. data/spec/spec_tests/data/sdam/rs/wrong_set_name.yml +2 -1
  1323. data/spec/spec_tests/data/sdam/sharded/compatible.yml +4 -2
  1324. data/spec/spec_tests/data/sdam/sharded/discover_single_mongos.yml +24 -0
  1325. data/spec/spec_tests/data/sdam/sharded/ls_timeout_mongos.yml +9 -5
  1326. data/spec/spec_tests/data/sdam/sharded/mongos_disconnect.yml +6 -3
  1327. data/spec/spec_tests/data/sdam/sharded/multiple_mongoses.yml +4 -2
  1328. data/spec/spec_tests/data/sdam/sharded/non_mongos_removed.yml +4 -2
  1329. data/spec/spec_tests/data/sdam/sharded/{primary_address_change.yml → ruby_primary_different_address.yml} +1 -1
  1330. data/spec/spec_tests/data/sdam/sharded/{primary_mismatched_me.yml → ruby_primary_mismatched_me.yml} +1 -1
  1331. data/spec/spec_tests/data/sdam/sharded/too_new.yml +4 -2
  1332. data/spec/spec_tests/data/sdam/sharded/too_old.yml +4 -2
  1333. data/spec/spec_tests/data/sdam/single/compatible.yml +2 -1
  1334. data/spec/spec_tests/data/sdam/single/direct_connection_external_ip.yml +3 -2
  1335. data/spec/spec_tests/data/sdam/single/direct_connection_mongos.yml +4 -3
  1336. data/spec/spec_tests/data/sdam/single/direct_connection_replicaset.yml +23 -0
  1337. data/spec/spec_tests/data/sdam/single/direct_connection_rsarbiter.yml +4 -3
  1338. data/spec/spec_tests/data/sdam/single/direct_connection_rsprimary.yml +4 -3
  1339. data/spec/spec_tests/data/sdam/single/direct_connection_rssecondary.yml +4 -3
  1340. data/spec/spec_tests/data/sdam/single/direct_connection_standalone.yml +4 -3
  1341. data/spec/spec_tests/data/sdam/single/{unavailable_seed.yml → direct_connection_unavailable_seed.yml} +2 -2
  1342. data/spec/spec_tests/data/sdam/single/direct_connection_wrong_set_name.yml +40 -0
  1343. data/spec/spec_tests/data/sdam/single/discover_standalone.yml +35 -0
  1344. data/spec/spec_tests/data/sdam/single/discover_unavailable_seed.yml +28 -0
  1345. data/spec/spec_tests/data/sdam/single/ls_timeout_standalone.yml +2 -1
  1346. data/spec/spec_tests/data/sdam/single/not_ok_response.yml +5 -3
  1347. data/spec/spec_tests/data/sdam/single/{primary_address_change.yml → ruby_primary_different_address.yml} +1 -1
  1348. data/spec/spec_tests/data/sdam/single/{primary_mismatched_me.yml → ruby_primary_mismatched_me.yml} +1 -1
  1349. data/spec/spec_tests/data/sdam/single/standalone_removed.yml +2 -1
  1350. data/spec/spec_tests/data/sdam/single/{direct_connection_slave.yml → standalone_using_legacy_hello.yml} +2 -2
  1351. data/spec/spec_tests/data/sdam/single/too_new.yml +2 -1
  1352. data/spec/spec_tests/data/sdam/single/too_old.yml +2 -1
  1353. data/spec/spec_tests/data/sdam/single/too_old_then_upgraded.yml +48 -0
  1354. data/spec/spec_tests/data/sdam_integration/cancel-server-check.yml +96 -0
  1355. data/spec/spec_tests/data/sdam_integration/connectTimeoutMS.yml +88 -0
  1356. data/spec/spec_tests/data/sdam_integration/find-network-error.yml +85 -0
  1357. data/spec/spec_tests/data/sdam_integration/find-shutdown-error.yml +118 -0
  1358. data/spec/spec_tests/data/sdam_integration/hello-command-error.yml +152 -0
  1359. data/spec/spec_tests/data/sdam_integration/hello-network-error.yml +148 -0
  1360. data/spec/spec_tests/data/sdam_integration/hello-timeout.yml +219 -0
  1361. data/spec/spec_tests/data/sdam_integration/insert-network-error.yml +88 -0
  1362. data/spec/spec_tests/data/sdam_integration/insert-shutdown-error.yml +117 -0
  1363. data/spec/spec_tests/data/sdam_integration/rediscover-quickly-after-step-down.yml +98 -0
  1364. data/spec/spec_tests/data/sdam_monitoring/discovered_standalone.yml +2 -4
  1365. data/spec/spec_tests/data/sdam_monitoring/load_balancer.yml +65 -0
  1366. data/spec/spec_tests/data/sdam_monitoring/{replica_set_with_primary_change.yml → replica_set_primary_address_change.yml} +27 -5
  1367. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_me_mismatch.yml +26 -74
  1368. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_no_primary.yml +2 -1
  1369. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_primary.yml +2 -1
  1370. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_removal.yml +21 -16
  1371. data/spec/spec_tests/data/sdam_monitoring/required_replica_set.yml +2 -1
  1372. data/spec/spec_tests/data/sdam_monitoring/standalone.yml +3 -3
  1373. data/spec/spec_tests/data/sdam_monitoring/standalone_repeated.yml +2 -2
  1374. data/spec/spec_tests/data/sdam_monitoring/standalone_suppress_equal_description_changes.yml +73 -0
  1375. data/spec/spec_tests/data/sdam_monitoring/standalone_to_rs_with_me_mismatch.yml +2 -2
  1376. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-directConnection.yml +13 -0
  1377. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-no-results.yml +5 -0
  1378. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-replicaSet-errors.yml +6 -0
  1379. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-true-multiple-hosts.yml +5 -0
  1380. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-true-txt.yml +10 -0
  1381. data/spec/spec_tests/data/seed_list_discovery/load-balanced/srvMaxHosts-conflicts_with_loadBalanced-true-txt.yml +5 -0
  1382. data/spec/spec_tests/data/seed_list_discovery/load-balanced/srvMaxHosts-conflicts_with_loadBalanced-true.yml +5 -0
  1383. data/spec/spec_tests/data/seed_list_discovery/load-balanced/srvMaxHosts-zero-txt.yml +10 -0
  1384. data/spec/spec_tests/data/seed_list_discovery/load-balanced/srvMaxHosts-zero.yml +10 -0
  1385. data/spec/spec_tests/data/seed_list_discovery/replica-set/direct-connection-false.yml +10 -0
  1386. data/spec/spec_tests/data/seed_list_discovery/replica-set/direct-connection-true.yml +5 -0
  1387. data/spec/spec_tests/data/seed_list_discovery/replica-set/encoded-userinfo-and-db.yml +15 -0
  1388. data/spec/spec_tests/data/seed_list_discovery/replica-set/loadBalanced-false-txt.yml +10 -0
  1389. data/spec/spec_tests/data/seed_list_discovery/replica-set/srv-service-name.yml +11 -0
  1390. data/spec/spec_tests/data/seed_list_discovery/replica-set/srvMaxHosts-conflicts_with_replicaSet-txt.yml +5 -0
  1391. data/spec/spec_tests/data/seed_list_discovery/replica-set/srvMaxHosts-conflicts_with_replicaSet.yml +5 -0
  1392. data/spec/spec_tests/data/seed_list_discovery/replica-set/srvMaxHosts-equal_to_srv_records.yml +16 -0
  1393. data/spec/spec_tests/data/seed_list_discovery/replica-set/srvMaxHosts-greater_than_srv_records.yml +15 -0
  1394. data/spec/spec_tests/data/seed_list_discovery/replica-set/srvMaxHosts-less_than_srv_records.yml +15 -0
  1395. data/spec/spec_tests/data/seed_list_discovery/replica-set/srvMaxHosts-zero-txt.yml +15 -0
  1396. data/spec/spec_tests/data/seed_list_discovery/replica-set/srvMaxHosts-zero.yml +15 -0
  1397. data/spec/spec_tests/data/seed_list_discovery/replica-set/uri-with-admin-database.yml +13 -0
  1398. data/spec/spec_tests/data/seed_list_discovery/replica-set/uri-with-auth.yml +12 -0
  1399. data/spec/spec_tests/data/seed_list_discovery/sharded/srvMaxHosts-equal_to_srv_records.yml +13 -0
  1400. data/spec/spec_tests/data/seed_list_discovery/sharded/srvMaxHosts-greater_than_srv_records.yml +12 -0
  1401. data/spec/spec_tests/data/seed_list_discovery/sharded/srvMaxHosts-less_than_srv_records.yml +10 -0
  1402. data/spec/spec_tests/data/seed_list_discovery/sharded/srvMaxHosts-zero.yml +11 -0
  1403. data/spec/spec_tests/data/server_selection/Unknown/read/ghost.yml +11 -0
  1404. data/spec/spec_tests/data/server_selection/Unknown/write/ghost.yml +11 -0
  1405. data/spec/spec_tests/data/sessions_unified/driver-sessions-server-support.yml +123 -0
  1406. data/spec/spec_tests/data/sessions_unified/snapshot-sessions-not-supported-client-error.yml +75 -0
  1407. data/spec/spec_tests/data/sessions_unified/snapshot-sessions-not-supported-server-error.yml +102 -0
  1408. data/spec/spec_tests/data/sessions_unified/snapshot-sessions-unsupported-ops.yml +258 -0
  1409. data/spec/spec_tests/data/sessions_unified/snapshot-sessions.yml +482 -0
  1410. data/spec/spec_tests/data/transactions/create-collection.yml +131 -0
  1411. data/spec/spec_tests/data/transactions/create-index.yml +152 -0
  1412. data/spec/spec_tests/data/transactions/error-labels.yml +90 -21
  1413. data/spec/spec_tests/data/transactions/errors-client.yml +8 -9
  1414. data/spec/spec_tests/data/transactions/mongos-pin-auto.yml +3 -0
  1415. data/spec/spec_tests/data/transactions/mongos-recovery-token.yml +3 -0
  1416. data/spec/spec_tests/data/transactions/pin-mongos.yml +8 -6
  1417. data/spec/spec_tests/data/transactions/retryable-abort-errorLabels.yml +124 -0
  1418. data/spec/spec_tests/data/transactions/retryable-abort.yml +20 -5
  1419. data/spec/spec_tests/data/transactions/retryable-commit-errorLabels.yml +132 -0
  1420. data/spec/spec_tests/data/transactions/retryable-commit.yml +27 -12
  1421. data/spec/spec_tests/data/transactions_unified/do-not-retry-read-in-transaction.yml +64 -0
  1422. data/spec/spec_tests/data/transactions_unified/mongos-unpin.yml +172 -0
  1423. data/spec/spec_tests/data/transactions_unified/retryable-abort-handshake.yml +118 -0
  1424. data/spec/spec_tests/data/transactions_unified/retryable-commit-handshake.yml +118 -0
  1425. data/spec/spec_tests/data/unified/invalid/expectedEventsForClient-ignoreExtraEvents-type.yml +15 -0
  1426. data/spec/spec_tests/data/unified/valid-fail/operation-failure.yml +31 -0
  1427. data/spec/spec_tests/data/unified/valid-fail/operation-unsupported.yml +13 -0
  1428. data/spec/spec_tests/data/unified/valid-pass/expectedEventsForClient-ignoreExtraEvents.yml +78 -0
  1429. data/spec/spec_tests/data/unified/valid-pass/poc-change-streams.yml +223 -0
  1430. data/spec/spec_tests/data/unified/valid-pass/poc-command-monitoring.yml +102 -0
  1431. data/spec/spec_tests/data/unified/valid-pass/poc-crud.yml +184 -0
  1432. data/spec/spec_tests/data/unified/valid-pass/poc-gridfs.yml +155 -0
  1433. data/spec/spec_tests/data/unified/valid-pass/poc-retryable-reads.yml +193 -0
  1434. data/spec/spec_tests/data/unified/valid-pass/poc-retryable-writes.yml +210 -0
  1435. data/spec/spec_tests/data/unified/valid-pass/poc-sessions.yml +215 -0
  1436. data/spec/spec_tests/data/unified/valid-pass/poc-transactions-convenient-api.yml +235 -0
  1437. data/spec/spec_tests/data/unified/valid-pass/poc-transactions-mongos-pin-auto.yml +169 -0
  1438. data/spec/spec_tests/data/unified/valid-pass/poc-transactions.yml +171 -0
  1439. data/spec/spec_tests/data/uri_options/auth-options.yml +35 -0
  1440. data/spec/spec_tests/data/uri_options/compression-options.yml +7 -4
  1441. data/spec/spec_tests/data/uri_options/connection-options.yml +103 -0
  1442. data/spec/spec_tests/data/uri_options/read-preference-options.yml +24 -0
  1443. data/spec/spec_tests/data/uri_options/ruby-auth-options.yml +12 -0
  1444. data/spec/spec_tests/data/uri_options/ruby-connection-options.yml +58 -0
  1445. data/spec/spec_tests/data/uri_options/srv-options.yml +96 -0
  1446. data/spec/spec_tests/data/uri_options/tls-options.yml +233 -6
  1447. data/spec/spec_tests/data/versioned_api/crud-api-version-1-strict.yml +419 -0
  1448. data/spec/spec_tests/data/versioned_api/crud-api-version-1.yml +413 -0
  1449. data/spec/spec_tests/data/versioned_api/runcommand-helper-no-api-version-declared.yml +75 -0
  1450. data/spec/spec_tests/data/versioned_api/test-commands-deprecation-errors.yml +47 -0
  1451. data/spec/spec_tests/data/versioned_api/test-commands-strict-mode.yml +46 -0
  1452. data/spec/spec_tests/data/versioned_api/transaction-handling.yml +128 -0
  1453. data/spec/spec_tests/gridfs_spec.rb +5 -0
  1454. data/spec/spec_tests/gridfs_unified_spec.rb +13 -0
  1455. data/spec/spec_tests/load_balancers_spec.rb +15 -0
  1456. data/spec/spec_tests/max_staleness_spec.rb +7 -140
  1457. data/spec/spec_tests/read_write_concern_connection_string_spec.rb +6 -1
  1458. data/spec/spec_tests/read_write_concern_document_spec.rb +3 -0
  1459. data/spec/spec_tests/read_write_concern_operaton_spec.rb +13 -0
  1460. data/spec/spec_tests/retryable_reads_spec.rb +13 -5
  1461. data/spec/spec_tests/retryable_reads_unified_spec.rb +22 -0
  1462. data/spec/spec_tests/retryable_writes_spec.rb +16 -3
  1463. data/spec/spec_tests/retryable_writes_unified_spec.rb +21 -0
  1464. data/spec/spec_tests/sdam_integration_spec.rb +16 -0
  1465. data/spec/spec_tests/sdam_monitoring_spec.rb +16 -7
  1466. data/spec/spec_tests/sdam_spec.rb +75 -3
  1467. data/spec/spec_tests/seed_list_discovery_spec.rb +127 -0
  1468. data/spec/spec_tests/server_selection_rtt_spec.rb +5 -0
  1469. data/spec/spec_tests/server_selection_spec.rb +7 -114
  1470. data/spec/spec_tests/sessions_unified_spec.rb +13 -0
  1471. data/spec/spec_tests/transactions_api_spec.rb +8 -0
  1472. data/spec/spec_tests/transactions_spec.rb +8 -0
  1473. data/spec/spec_tests/transactions_unified_spec.rb +13 -0
  1474. data/spec/spec_tests/unified_spec.rb +23 -0
  1475. data/spec/spec_tests/uri_options_spec.rb +58 -41
  1476. data/spec/spec_tests/versioned_api_spec.rb +13 -0
  1477. data/spec/stress/cleanup_spec.rb +61 -0
  1478. data/spec/stress/connection_pool_stress_spec.rb +14 -13
  1479. data/spec/stress/connection_pool_timing_spec.rb +13 -9
  1480. data/spec/stress/fork_reconnect_stress_spec.rb +109 -0
  1481. data/spec/stress/push_monitor_close_spec.rb +44 -0
  1482. data/spec/support/authorization.rb +5 -12
  1483. data/spec/support/aws_utils/base.rb +137 -0
  1484. data/spec/support/aws_utils/inspector.rb +227 -0
  1485. data/spec/support/aws_utils/orchestrator.rb +373 -0
  1486. data/spec/support/aws_utils/provisioner.rb +363 -0
  1487. data/spec/support/aws_utils.rb +65 -0
  1488. data/spec/support/background_thread_registry.rb +12 -15
  1489. data/spec/support/certificates/README.md +7 -2
  1490. data/spec/support/certificates/atlas-ocsp-ca.crt +103 -0
  1491. data/spec/support/certificates/atlas-ocsp.crt +152 -0
  1492. data/spec/support/certificates/retrieve-atlas-cert +38 -0
  1493. data/spec/support/certificates/server-second-level-bundle.pem +77 -77
  1494. data/spec/support/certificates/server-second-level.crt +52 -52
  1495. data/spec/support/certificates/server-second-level.key +25 -25
  1496. data/spec/support/certificates/server-second-level.pem +77 -77
  1497. data/spec/support/client_registry.rb +37 -32
  1498. data/spec/support/client_registry_macros.rb +17 -5
  1499. data/spec/support/cluster_tools.rb +11 -3
  1500. data/spec/support/common_shortcuts.rb +160 -6
  1501. data/spec/support/constraints.rb +9 -217
  1502. data/spec/support/crypt/corpus/corpus-encrypted.json +9515 -0
  1503. data/spec/support/crypt/corpus/corpus-key-aws.json +33 -0
  1504. data/spec/support/crypt/corpus/corpus-key-azure.json +33 -0
  1505. data/spec/support/crypt/corpus/corpus-key-gcp.json +35 -0
  1506. data/spec/support/crypt/corpus/corpus-key-kmip.json +32 -0
  1507. data/spec/support/crypt/corpus/corpus-key-local.json +31 -0
  1508. data/spec/support/crypt/corpus/corpus-schema.json +6335 -0
  1509. data/spec/support/crypt/corpus/corpus.json +8619 -0
  1510. data/spec/support/crypt/data_keys/key_document_aws.json +34 -0
  1511. data/spec/support/crypt/data_keys/key_document_azure.json +33 -0
  1512. data/spec/support/crypt/data_keys/key_document_gcp.json +37 -0
  1513. data/spec/support/crypt/data_keys/key_document_kmip.json +32 -0
  1514. data/spec/support/crypt/data_keys/key_document_local.json +31 -0
  1515. data/spec/support/crypt/encryptedFields.json +33 -0
  1516. data/spec/support/crypt/external/external-key.json +31 -0
  1517. data/spec/support/crypt/external/external-schema.json +19 -0
  1518. data/spec/support/crypt/keys/key1-document.json +30 -0
  1519. data/spec/support/crypt/limits/limits-doc.json +102 -0
  1520. data/spec/support/crypt/limits/limits-key.json +31 -0
  1521. data/spec/support/crypt/limits/limits-schema.json +1405 -0
  1522. data/spec/support/crypt/schema_maps/schema_map_aws.json +17 -0
  1523. data/spec/support/crypt/schema_maps/schema_map_aws_key_alt_names.json +12 -0
  1524. data/spec/support/crypt/schema_maps/schema_map_azure.json +17 -0
  1525. data/spec/support/crypt/schema_maps/schema_map_azure_key_alt_names.json +12 -0
  1526. data/spec/support/crypt/schema_maps/schema_map_gcp.json +17 -0
  1527. data/spec/support/crypt/schema_maps/schema_map_gcp_key_alt_names.json +12 -0
  1528. data/spec/support/crypt/schema_maps/schema_map_kmip.json +17 -0
  1529. data/spec/support/crypt/schema_maps/schema_map_kmip_key_alt_names.json +12 -0
  1530. data/spec/support/crypt/schema_maps/schema_map_local.json +18 -0
  1531. data/spec/support/crypt/schema_maps/schema_map_local_key_alt_names.json +12 -0
  1532. data/spec/support/crypt.rb +402 -0
  1533. data/spec/support/dns.rb +3 -0
  1534. data/spec/support/json_ext_formatter.rb +3 -0
  1535. data/spec/support/keyword_struct.rb +29 -0
  1536. data/spec/support/local_resource_registry.rb +3 -0
  1537. data/spec/support/macros.rb +28 -0
  1538. data/spec/support/matchers.rb +52 -1
  1539. data/spec/support/mongos_macros.rb +17 -0
  1540. data/spec/support/monitoring_ext.rb +3 -0
  1541. data/spec/support/ocsp +1 -0
  1542. data/spec/support/primary_socket.rb +3 -0
  1543. data/spec/support/sdam_formatter_integration.rb +3 -0
  1544. data/spec/support/shared/app_metadata.rb +167 -0
  1545. data/spec/support/shared/auth_context.rb +16 -0
  1546. data/spec/support/shared/protocol.rb +5 -0
  1547. data/spec/support/shared/scram_conversation.rb +104 -0
  1548. data/spec/support/shared/server_selector.rb +99 -4
  1549. data/spec/support/shared/session.rb +47 -30
  1550. data/spec/support/spec_config.rb +339 -57
  1551. data/spec/support/spec_setup.rb +55 -38
  1552. data/spec/support/using_hash.rb +31 -0
  1553. data/spec/support/utils.rb +455 -35
  1554. data.tar.gz.sig +0 -0
  1555. metadata +2088 -838
  1556. metadata.gz.sig +0 -0
  1557. data/lib/mongo/cluster/srv_monitor.rb +0 -127
  1558. data/lib/mongo/collection/view/builder/find_command.rb +0 -142
  1559. data/lib/mongo/collection/view/builder/op_query.rb +0 -91
  1560. data/lib/mongo/cursor/builder/get_more_command.rb +0 -77
  1561. data/lib/mongo/cursor/builder/kill_cursors_command.rb +0 -108
  1562. data/lib/mongo/cursor/builder/op_get_more.rb +0 -61
  1563. data/lib/mongo/cursor/builder/op_kill_cursors.rb +0 -103
  1564. data/lib/mongo/operation/insert/legacy.rb +0 -60
  1565. data/lib/mongo/operation/shared/op_msg_or_list_indexes_command.rb +0 -45
  1566. data/lib/mongo/operation/update/legacy/result.rb +0 -102
  1567. data/lib/mongo/operation/update/legacy.rb +0 -65
  1568. data/lib/mongo/server/connectable.rb +0 -107
  1569. data/lib/mongo/server/context.rb +0 -69
  1570. data/spec/enterprise_auth/kerberos_spec.rb +0 -58
  1571. data/spec/mongo/cluster/srv_monitor_spec.rb +0 -214
  1572. data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +0 -56
  1573. data/spec/mongo/dbref_spec.rb +0 -149
  1574. data/spec/mongo/operation/kill_cursors_spec.rb +0 -41
  1575. data/spec/mongo/operation/read_preference_spec.rb +0 -245
  1576. data/spec/spec_tests/change_streams_spec.rb +0 -55
  1577. data/spec/spec_tests/command_monitoring_spec.rb +0 -53
  1578. data/spec/spec_tests/data/change_streams/change-streams-errors.yml +0 -76
  1579. data/spec/spec_tests/data/change_streams/change-streams.yml +0 -536
  1580. data/spec/spec_tests/data/command_monitoring/bulkWrite.yml +0 -49
  1581. data/spec/spec_tests/data/command_monitoring/command.yml +0 -61
  1582. data/spec/spec_tests/data/command_monitoring/deleteMany.yml +0 -55
  1583. data/spec/spec_tests/data/command_monitoring/deleteOne.yml +0 -55
  1584. data/spec/spec_tests/data/command_monitoring/find.yml +0 -266
  1585. data/spec/spec_tests/data/command_monitoring/insertMany.yml +0 -75
  1586. data/spec/spec_tests/data/command_monitoring/insertOne.yml +0 -51
  1587. data/spec/spec_tests/data/command_monitoring/unacknowledgedBulkWrite.yml +0 -34
  1588. data/spec/spec_tests/data/command_monitoring/updateMany.yml +0 -65
  1589. data/spec/spec_tests/data/command_monitoring/updateOne.yml +0 -90
  1590. data/spec/spec_tests/data/crud_v2/aggregate-merge.yml +0 -103
  1591. data/spec/spec_tests/data/crud_v2/aggregate-out-readConcern.yml +0 -110
  1592. data/spec/spec_tests/data/crud_v2/bulkWrite-arrayFilters.yml +0 -81
  1593. data/spec/spec_tests/data/crud_v2/db-aggregate.yml +0 -38
  1594. data/spec/spec_tests/data/crud_v2/updateWithPipelines.yml +0 -92
  1595. data/spec/spec_tests/data/sdam/sharded/single_mongos.yml +0 -33
  1596. data/spec/spec_tests/dns_seedlist_discovery_spec.rb +0 -66
  1597. data/spec/support/change_streams/operation.rb +0 -89
  1598. data/spec/support/change_streams.rb +0 -262
  1599. data/spec/support/cluster_config.rb +0 -194
  1600. data/spec/support/connection_string.rb +0 -354
  1601. data/spec/support/crud/requirement.rb +0 -69
  1602. data/spec/support/crud/test_base.rb +0 -22
  1603. data/spec/support/event_subscriber.rb +0 -112
  1604. data/spec/support/lite_constraints.rb +0 -76
  1605. data/spec/support/sdam_monitoring.rb +0 -89
  1606. data/spec/support/server_selection.rb +0 -148
  1607. data/spec/support/transactions/operation.rb +0 -184
  1608. data/spec/support/transactions/test.rb +0 -252
  1609. /data/spec/spec_tests/data/retryable_reads/{aggregate-merge.yml → legacy/aggregate-merge.yml} +0 -0
  1610. /data/spec/spec_tests/data/retryable_reads/{aggregate.yml → legacy/aggregate.yml} +0 -0
  1611. /data/spec/spec_tests/data/retryable_reads/{count.yml → legacy/count.yml} +0 -0
  1612. /data/spec/spec_tests/data/retryable_reads/{countDocuments.yml → legacy/countDocuments.yml} +0 -0
  1613. /data/spec/spec_tests/data/retryable_reads/{distinct.yml → legacy/distinct.yml} +0 -0
  1614. /data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount.yml → legacy/estimatedDocumentCount.yml} +0 -0
  1615. /data/spec/spec_tests/data/retryable_reads/{find.yml → legacy/find.yml} +0 -0
  1616. /data/spec/spec_tests/data/retryable_reads/{findOne.yml → legacy/findOne.yml} +0 -0
  1617. /data/spec/spec_tests/data/retryable_reads/{gridfs-download.yml → legacy/gridfs-download.yml} +0 -0
  1618. /data/spec/spec_tests/data/retryable_reads/{gridfs-downloadByName.yml → legacy/gridfs-downloadByName.yml} +0 -0
  1619. /data/spec/spec_tests/data/retryable_reads/{listCollectionNames.yml → legacy/listCollectionNames.yml} +0 -0
  1620. /data/spec/spec_tests/data/retryable_reads/{listCollectionObjects.yml → legacy/listCollectionObjects.yml} +0 -0
  1621. /data/spec/spec_tests/data/retryable_reads/{listCollections.yml → legacy/listCollections.yml} +0 -0
  1622. /data/spec/spec_tests/data/retryable_reads/{listDatabaseNames.yml → legacy/listDatabaseNames.yml} +0 -0
  1623. /data/spec/spec_tests/data/retryable_reads/{listDatabaseObjects.yml → legacy/listDatabaseObjects.yml} +0 -0
  1624. /data/spec/spec_tests/data/retryable_reads/{listDatabases.yml → legacy/listDatabases.yml} +0 -0
  1625. /data/spec/spec_tests/data/retryable_reads/{listIndexes.yml → legacy/listIndexes.yml} +0 -0
  1626. /data/spec/spec_tests/data/retryable_writes/{deleteMany.yml → legacy/deleteMany.yml} +0 -0
  1627. /data/spec/spec_tests/data/retryable_writes/{deleteOne.yml → legacy/deleteOne.yml} +0 -0
  1628. /data/spec/spec_tests/data/retryable_writes/{findOneAndDelete.yml → legacy/findOneAndDelete.yml} +0 -0
  1629. /data/spec/spec_tests/data/retryable_writes/{findOneAndReplace.yml → legacy/findOneAndReplace.yml} +0 -0
  1630. /data/spec/spec_tests/data/retryable_writes/{findOneAndUpdate.yml → legacy/findOneAndUpdate.yml} +0 -0
  1631. /data/spec/spec_tests/data/retryable_writes/{insertMany.yml → legacy/insertMany.yml} +0 -0
  1632. /data/spec/spec_tests/data/retryable_writes/{insertOne.yml → legacy/insertOne.yml} +0 -0
  1633. /data/spec/spec_tests/data/retryable_writes/{replaceOne.yml → legacy/replaceOne.yml} +0 -0
  1634. /data/spec/spec_tests/data/retryable_writes/{updateMany.yml → legacy/updateMany.yml} +0 -0
  1635. /data/spec/spec_tests/data/retryable_writes/{updateOne.yml → legacy/updateOne.yml} +0 -0
  1636. /data/spec/spec_tests/data/sdam/rs/{secondary_wrong_set_name_with_primary_second.yml → ruby_secondary_wrong_set_name_with_primary_second.yml} +0 -0
  1637. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/longer-parent-in-return.yml +0 -0
  1638. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/misformatted-option.yml +0 -0
  1639. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/no-results.yml +0 -0
  1640. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/not-enough-parts.yml +0 -0
  1641. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-result-default-port.yml +0 -0
  1642. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-txt-record-multiple-strings.yml +0 -0
  1643. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-txt-record.yml +0 -0
  1644. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch1.yml +0 -0
  1645. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch2.yml +0 -0
  1646. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch3.yml +0 -0
  1647. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch4.yml +0 -0
  1648. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch5.yml +0 -0
  1649. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/returned-parent-too-short.yml +0 -0
  1650. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/returned-parent-wrong.yml +0 -0
  1651. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-results-default-port.yml +0 -0
  1652. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-results-nonstandard-port.yml +0 -0
  1653. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-txt-records.yml +0 -0
  1654. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-not-allowed-option.yml +0 -0
  1655. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-overridden-ssl-option.yml +0 -0
  1656. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-overridden-uri-option.yml +0 -0
  1657. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-unallowed-option.yml +0 -0
  1658. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/uri-with-port.yml +0 -0
  1659. /data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/uri-with-two-hosts.yml +0 -0
@@ -0,0 +1,4415 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ require 'spec_helper'
5
+
6
+ describe Mongo::Collection do
7
+
8
+ let(:subscriber) { Mrss::EventSubscriber.new }
9
+
10
+ let(:client) do
11
+ authorized_client.tap do |client|
12
+ client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
13
+ end
14
+ end
15
+
16
+ let(:authorized_collection) { client['collection_spec'] }
17
+
18
+ before do
19
+ authorized_client['collection_spec'].drop
20
+ end
21
+
22
+ let(:collection_invalid_write_concern) do
23
+ authorized_collection.client.with(write: INVALID_WRITE_CONCERN)[authorized_collection.name]
24
+ end
25
+
26
+ let(:collection_with_validator) do
27
+ authorized_client[:validating]
28
+ end
29
+
30
+ describe '#find' do
31
+
32
+ describe 'updating cluster time' do
33
+
34
+ let(:operation) do
35
+ client[TEST_COLL].find.first
36
+ end
37
+
38
+ let(:operation_with_session) do
39
+ client[TEST_COLL].find({}, session: session).first
40
+ end
41
+
42
+ let(:second_operation) do
43
+ client[TEST_COLL].find({}, session: session).first
44
+ end
45
+
46
+ it_behaves_like 'an operation updating cluster time'
47
+ end
48
+
49
+ context 'when provided a filter' do
50
+
51
+ let(:view) do
52
+ authorized_collection.find(name: 1)
53
+ end
54
+
55
+ it 'returns a authorized_collection view for the filter' do
56
+ expect(view.filter).to eq('name' => 1)
57
+ end
58
+ end
59
+
60
+ context 'when provided no filter' do
61
+
62
+ let(:view) do
63
+ authorized_collection.find
64
+ end
65
+
66
+ it 'returns a authorized_collection view with an empty filter' do
67
+ expect(view.filter).to be_empty
68
+ end
69
+ end
70
+
71
+ context 'when providing a bad filter' do
72
+
73
+ let(:view) do
74
+ authorized_collection.find('$or' => [])
75
+ end
76
+
77
+ it 'raises an exception when iterating' do
78
+ expect {
79
+ view.to_a
80
+ }.to raise_exception(Mongo::Error::OperationFailure)
81
+ end
82
+ end
83
+
84
+ context 'when iterating the authorized_collection view' do
85
+
86
+ before do
87
+ authorized_collection.insert_many([{ field: 'test1' }, { field: 'test2' }])
88
+ end
89
+
90
+ let(:view) do
91
+ authorized_collection.find
92
+ end
93
+
94
+ it 'iterates over the documents' do
95
+ view.each do |document|
96
+ expect(document).to_not be_nil
97
+ end
98
+ end
99
+ end
100
+
101
+ context 'when the user is not authorized' do
102
+ require_auth
103
+
104
+ let(:view) do
105
+ unauthorized_collection.find
106
+ end
107
+
108
+ it 'iterates over the documents' do
109
+ expect {
110
+ view.each{ |document| document }
111
+ }.to raise_error(Mongo::Error::OperationFailure)
112
+ end
113
+ end
114
+
115
+ context 'when documents contain potential error message fields' do
116
+
117
+ [ 'errmsg', 'error', Mongo::Operation::Result::OK ].each do |field|
118
+
119
+ context "when the document contains a '#{field}' field" do
120
+
121
+ let(:value) do
122
+ 'testing'
123
+ end
124
+
125
+ let(:view) do
126
+ authorized_collection.find
127
+ end
128
+
129
+ before do
130
+ authorized_collection.insert_one({ field => value })
131
+ end
132
+
133
+ it 'iterates over the documents' do
134
+ view.each do |document|
135
+ expect(document[field]).to eq(value)
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ context 'when provided options' do
143
+
144
+ context 'when a session is provided' do
145
+ require_wired_tiger
146
+
147
+ let(:operation) do
148
+ authorized_collection.find({}, session: session).to_a
149
+ end
150
+
151
+ let(:session) do
152
+ authorized_client.start_session
153
+ end
154
+
155
+ let(:failed_operation) do
156
+ client[authorized_collection.name].find({ '$._id' => 1 }, session: session).to_a
157
+ end
158
+
159
+ let(:client) do
160
+ authorized_client
161
+ end
162
+
163
+ it_behaves_like 'an operation using a session'
164
+ it_behaves_like 'a failed operation using a session'
165
+ end
166
+
167
+ context 'session id' do
168
+ min_server_fcv '3.6'
169
+ require_topology :replica_set, :sharded
170
+ require_wired_tiger
171
+
172
+ let(:options) do
173
+ { session: session }
174
+ end
175
+
176
+ let(:session) do
177
+ client.start_session
178
+ end
179
+
180
+ let(:view) do
181
+ Mongo::Collection::View.new(client[TEST_COLL], selector, view_options)
182
+ end
183
+
184
+ let(:command) do
185
+ client[TEST_COLL].find({}, session: session).explain
186
+ subscriber.started_events.find { |c| c.command_name == 'explain' }.command
187
+ end
188
+
189
+ it 'sends the session id' do
190
+ expect(command['lsid']).to eq(session.session_id)
191
+ end
192
+ end
193
+
194
+ context 'when a session supporting causal consistency is used' do
195
+ require_wired_tiger
196
+
197
+ let(:operation) do
198
+ collection.find({}, session: session).to_a
199
+ end
200
+
201
+ let(:command) do
202
+ operation
203
+ subscriber.started_events.find { |cmd| cmd.command_name == 'find' }.command
204
+ end
205
+
206
+ it_behaves_like 'an operation supporting causally consistent reads'
207
+ end
208
+
209
+ let(:view) do
210
+ authorized_collection.find({}, options)
211
+ end
212
+
213
+ context 'when provided :allow_partial_results' do
214
+
215
+ let(:options) do
216
+ { allow_partial_results: true }
217
+ end
218
+
219
+ it 'returns a view with :allow_partial_results set' do
220
+ expect(view.options[:allow_partial_results]).to be(options[:allow_partial_results])
221
+ end
222
+ end
223
+
224
+ context 'when provided :batch_size' do
225
+
226
+ let(:options) do
227
+ { batch_size: 100 }
228
+ end
229
+
230
+ it 'returns a view with :batch_size set' do
231
+ expect(view.options[:batch_size]).to eq(options[:batch_size])
232
+ end
233
+ end
234
+
235
+ context 'when provided :comment' do
236
+
237
+ let(:options) do
238
+ { comment: 'slow query' }
239
+ end
240
+
241
+ it 'returns a view with :comment set' do
242
+ expect(view.modifiers[:$comment]).to eq(options[:comment])
243
+ end
244
+ end
245
+
246
+ context 'when provided :cursor_type' do
247
+
248
+ let(:options) do
249
+ { cursor_type: :tailable }
250
+ end
251
+
252
+ it 'returns a view with :cursor_type set' do
253
+ expect(view.options[:cursor_type]).to eq(options[:cursor_type])
254
+ end
255
+ end
256
+
257
+ context 'when provided :max_time_ms' do
258
+
259
+ let(:options) do
260
+ { max_time_ms: 500 }
261
+ end
262
+
263
+ it 'returns a view with :max_time_ms set' do
264
+ expect(view.modifiers[:$maxTimeMS]).to eq(options[:max_time_ms])
265
+ end
266
+ end
267
+
268
+ context 'when provided :modifiers' do
269
+
270
+ let(:options) do
271
+ { modifiers: { '$orderby' => Mongo::Index::ASCENDING } }
272
+ end
273
+
274
+ it 'returns a view with modifiers set' do
275
+ expect(view.modifiers).to eq(options[:modifiers])
276
+ end
277
+
278
+ it 'dups the modifiers hash' do
279
+ expect(view.modifiers).not_to be(options[:modifiers])
280
+ end
281
+ end
282
+
283
+ context 'when provided :no_cursor_timeout' do
284
+
285
+ let(:options) do
286
+ { no_cursor_timeout: true }
287
+ end
288
+
289
+ it 'returns a view with :no_cursor_timeout set' do
290
+ expect(view.options[:no_cursor_timeout]).to eq(options[:no_cursor_timeout])
291
+ end
292
+ end
293
+
294
+ context 'when provided :oplog_replay' do
295
+
296
+ let(:options) do
297
+ { oplog_replay: false }
298
+ end
299
+
300
+ it 'returns a view with :oplog_replay set' do
301
+ expect(view.options[:oplog_replay]).to eq(options[:oplog_replay])
302
+ end
303
+ end
304
+
305
+ context 'when provided :projection' do
306
+
307
+ let(:options) do
308
+ { projection: { 'x' => 1 } }
309
+ end
310
+
311
+ it 'returns a view with :projection set' do
312
+ expect(view.options[:projection]).to eq(options[:projection])
313
+ end
314
+ end
315
+
316
+ context 'when provided :skip' do
317
+
318
+ let(:options) do
319
+ { skip: 5 }
320
+ end
321
+
322
+ it 'returns a view with :skip set' do
323
+ expect(view.options[:skip]).to eq(options[:skip])
324
+ end
325
+ end
326
+
327
+ context 'when provided :sort' do
328
+
329
+ let(:options) do
330
+ { sort: { 'x' => Mongo::Index::ASCENDING } }
331
+ end
332
+
333
+ it 'returns a view with :sort set' do
334
+ expect(view.modifiers[:$orderby]).to eq(options[:sort])
335
+ end
336
+ end
337
+
338
+ context 'when provided :collation' do
339
+
340
+ let(:options) do
341
+ { collation: { 'locale' => 'en_US' } }
342
+ end
343
+
344
+ it 'returns a view with :collation set' do
345
+ expect(view.options[:collation]).to eq(options[:collation])
346
+ end
347
+ end
348
+ end
349
+ end
350
+
351
+ describe '#insert_many' do
352
+
353
+ let(:result) do
354
+ authorized_collection.insert_many([{ name: 'test1' }, { name: 'test2' }])
355
+ end
356
+
357
+ it 'inserts the documents into the collection' do
358
+ expect(result.inserted_count).to eq(2)
359
+ end
360
+
361
+ it 'contains the ids in the result' do
362
+ expect(result.inserted_ids.size).to eq(2)
363
+ end
364
+
365
+ context 'when a session is provided' do
366
+
367
+ let(:session) do
368
+ authorized_client.start_session
369
+ end
370
+
371
+ let(:operation) do
372
+ authorized_collection.insert_many([{ name: 'test1' }, { name: 'test2' }], session: session)
373
+ end
374
+
375
+ let(:failed_operation) do
376
+ authorized_collection.insert_many([{ _id: 'test1' }, { _id: 'test1' }], session: session)
377
+ end
378
+
379
+ let(:client) do
380
+ authorized_client
381
+ end
382
+
383
+ it_behaves_like 'an operation using a session'
384
+ it_behaves_like 'a failed operation using a session'
385
+ end
386
+
387
+ context 'when unacknowledged writes is used with an explicit session' do
388
+
389
+ let(:collection_with_unacknowledged_write_concern) do
390
+ authorized_collection.with(write: { w: 0 })
391
+ end
392
+
393
+ let(:operation) do
394
+ collection_with_unacknowledged_write_concern.insert_many([{ name: 'test1' }, { name: 'test2' }], session: session)
395
+ end
396
+
397
+ it_behaves_like 'an explicit session with an unacknowledged write'
398
+ end
399
+
400
+ context 'when unacknowledged writes is used with an implicit session' do
401
+
402
+ let(:collection_with_unacknowledged_write_concern) do
403
+ client.with(write: { w: 0 })[TEST_COLL]
404
+ end
405
+
406
+ let(:operation) do
407
+ collection_with_unacknowledged_write_concern.insert_many([{ name: 'test1' }, { name: 'test2' }])
408
+ end
409
+
410
+ it_behaves_like 'an implicit session with an unacknowledged write'
411
+ end
412
+
413
+ context 'when a document contains dotted keys' do
414
+
415
+ let(:docs) do
416
+ [ { 'first.name' => 'test1' }, { name: 'test2' } ]
417
+ end
418
+
419
+ let(:view) { authorized_collection.find({}, { sort: { name: 1 } }) }
420
+
421
+ it 'inserts the documents correctly' do
422
+ expect {
423
+ authorized_collection.insert_many(docs)
424
+ }.to_not raise_error
425
+
426
+ expect(view.count).to eq(2)
427
+ expect(view.first['first.name']).to eq('test1')
428
+ expect(view.to_a[1]['name']).to eq('test2')
429
+ end
430
+ end
431
+
432
+ context 'when the client has a custom id generator' do
433
+
434
+ let(:generator) do
435
+ Class.new do
436
+ def generate
437
+ 1
438
+ end
439
+ end.new
440
+ end
441
+
442
+ let(:custom_client) do
443
+ authorized_client.with(id_generator: generator)
444
+ end
445
+
446
+ let(:custom_collection) do
447
+ custom_client['custom_id_generator_test_collection']
448
+ end
449
+
450
+ before do
451
+ custom_collection.delete_many
452
+ custom_collection.insert_many([{ name: 'testing' }])
453
+ expect(custom_collection.count).to eq(1)
454
+ end
455
+
456
+ it 'inserts with the custom id' do
457
+ expect(custom_collection.count).to eq(1)
458
+ expect(custom_collection.find.first[:_id]).to eq(1)
459
+ end
460
+ end
461
+
462
+ context 'when the inserts fail' do
463
+
464
+ let(:result) do
465
+ authorized_collection.insert_many([{ _id: 1 }, { _id: 1 }])
466
+ end
467
+
468
+ it 'raises an BulkWriteError' do
469
+ expect {
470
+ result
471
+ }.to raise_exception(Mongo::Error::BulkWriteError)
472
+ end
473
+ end
474
+
475
+ context "when the documents exceed the max bson size" do
476
+
477
+ let(:documents) do
478
+ [{ '_id' => 1, 'name' => '1'*17000000 }]
479
+ end
480
+
481
+ it 'raises a MaxBSONSize error' do
482
+ expect {
483
+ authorized_collection.insert_many(documents)
484
+ }.to raise_error(Mongo::Error::MaxBSONSize)
485
+ end
486
+ end
487
+
488
+ context 'when the documents are sent with OP_MSG' do
489
+ min_server_fcv '3.6'
490
+
491
+ let(:documents) do
492
+ [{ '_id' => 1, 'name' => '1'*16777191 }, { '_id' => 'y' }]
493
+ end
494
+
495
+ before do
496
+ authorized_collection.insert_many(documents)
497
+ end
498
+
499
+ let(:insert_events) do
500
+ subscriber.started_events.select { |e| e.command_name == 'insert' }
501
+ end
502
+
503
+ it 'sends the documents in one OP_MSG' do
504
+ expect(insert_events.size).to eq(1)
505
+ expect(insert_events[0].command['documents']).to eq(documents)
506
+ end
507
+ end
508
+
509
+ context 'when collection has a validator' do
510
+ min_server_fcv '3.2'
511
+
512
+ around(:each) do |spec|
513
+ authorized_client[:validating].drop
514
+ authorized_client[:validating,
515
+ :validator => { :a => { '$exists' => true } }].tap do |c|
516
+ c.create
517
+ end
518
+ spec.run
519
+ collection_with_validator.drop
520
+ end
521
+
522
+ context 'when the document is valid' do
523
+
524
+ let(:result) do
525
+ collection_with_validator.insert_many([{ a: 1 }, { a: 2 }])
526
+ end
527
+
528
+ it 'inserts successfully' do
529
+ expect(result.inserted_count).to eq(2)
530
+ end
531
+ end
532
+
533
+ context 'when the document is invalid' do
534
+
535
+ context 'when bypass_document_validation is not set' do
536
+
537
+ let(:result2) do
538
+ collection_with_validator.insert_many([{ x: 1 }, { x: 2 }])
539
+ end
540
+
541
+ it 'raises a BulkWriteError' do
542
+ expect {
543
+ result2
544
+ }.to raise_exception(Mongo::Error::BulkWriteError)
545
+ end
546
+ end
547
+
548
+ context 'when bypass_document_validation is true' do
549
+
550
+ let(:result3) do
551
+ collection_with_validator.insert_many(
552
+ [{ x: 1 }, { x: 2 }], :bypass_document_validation => true)
553
+ end
554
+
555
+ it 'inserts successfully' do
556
+ expect(result3.inserted_count).to eq(2)
557
+ end
558
+ end
559
+ end
560
+ end
561
+
562
+ context 'when unacknowledged writes is used' do
563
+
564
+ let(:collection_with_unacknowledged_write_concern) do
565
+ authorized_collection.with(write: { w: 0 })
566
+ end
567
+
568
+ let(:result) do
569
+ collection_with_unacknowledged_write_concern.insert_many([{ _id: 1 }, { _id: 1 }])
570
+ end
571
+
572
+ it 'does not raise an exception' do
573
+ expect(result.inserted_count).to be(0)
574
+ end
575
+ end
576
+
577
+ context 'when various options passed in' do
578
+ # w: 2 requires a replica set
579
+ require_topology :replica_set
580
+
581
+ # https://jira.mongodb.org/browse/RUBY-2306
582
+ min_server_fcv '3.6'
583
+
584
+ let(:session) do
585
+ authorized_client.start_session
586
+ end
587
+
588
+ let(:events) do
589
+ subscriber.command_started_events('insert')
590
+ end
591
+
592
+ let(:collection) do
593
+ authorized_collection.with(write_concern: {w: 2})
594
+ end
595
+
596
+ let!(:command) do
597
+ Utils.get_command_event(authorized_client, 'insert') do |client|
598
+ collection.insert_many([{ name: 'test1' }, { name: 'test2' }], session: session,
599
+ write_concern: {w: 1}, bypass_document_validation: true)
600
+ end.command
601
+ end
602
+
603
+ it 'inserts many successfully with correct options sent to server' do
604
+ expect(events.length).to eq(1)
605
+ expect(command[:writeConcern]).to_not be_nil
606
+ expect(command[:writeConcern][:w]).to eq(1)
607
+ expect(command[:bypassDocumentValidation]).to be(true)
608
+ end
609
+ end
610
+ end
611
+
612
+ describe '#insert_one' do
613
+
614
+ describe 'updating cluster time' do
615
+
616
+ let(:operation) do
617
+ client[TEST_COLL].insert_one({ name: 'testing' })
618
+ end
619
+
620
+ let(:operation_with_session) do
621
+ client[TEST_COLL].insert_one({ name: 'testing' }, session: session)
622
+ end
623
+
624
+ let(:second_operation) do
625
+ client[TEST_COLL].insert_one({ name: 'testing' }, session: session)
626
+ end
627
+
628
+ it_behaves_like 'an operation updating cluster time'
629
+ end
630
+
631
+ let(:result) do
632
+ authorized_collection.insert_one({ name: 'testing' })
633
+ end
634
+
635
+ it 'inserts the document into the collection'do
636
+ expect(result.written_count).to eq(1)
637
+ end
638
+
639
+ it 'contains the id in the result' do
640
+ expect(result.inserted_id).to_not be_nil
641
+ end
642
+
643
+ context 'when a session is provided' do
644
+
645
+ let(:session) do
646
+ authorized_client.start_session
647
+ end
648
+
649
+ let(:operation) do
650
+ authorized_collection.insert_one({ name: 'testing' }, session: session)
651
+ end
652
+
653
+ let(:failed_operation) do
654
+ authorized_collection.insert_one({ _id: 'testing' })
655
+ authorized_collection.insert_one({ _id: 'testing' }, session: session)
656
+ end
657
+
658
+ let(:client) do
659
+ authorized_client
660
+ end
661
+
662
+ it_behaves_like 'an operation using a session'
663
+ it_behaves_like 'a failed operation using a session'
664
+ end
665
+
666
+ context 'when unacknowledged writes is used with an explicit session' do
667
+
668
+ let(:collection_with_unacknowledged_write_concern) do
669
+ authorized_collection.with(write: { w: 0 })
670
+ end
671
+
672
+ let(:operation) do
673
+ collection_with_unacknowledged_write_concern.insert_one({ name: 'testing' }, session: session)
674
+ end
675
+
676
+ it_behaves_like 'an explicit session with an unacknowledged write'
677
+ end
678
+
679
+ context 'when unacknowledged writes is used with an implicit session' do
680
+
681
+ let(:collection_with_unacknowledged_write_concern) do
682
+ client.with(write: { w: 0 })[TEST_COLL]
683
+ end
684
+
685
+ let(:operation) do
686
+ collection_with_unacknowledged_write_concern.insert_one({ name: 'testing' })
687
+ end
688
+
689
+ it_behaves_like 'an implicit session with an unacknowledged write'
690
+ end
691
+
692
+ context 'when various options passed in' do
693
+ # https://jira.mongodb.org/browse/RUBY-2306
694
+ min_server_fcv '3.6'
695
+
696
+ let(:session) do
697
+ authorized_client.start_session
698
+ end
699
+
700
+ let(:events) do
701
+ subscriber.command_started_events('insert')
702
+ end
703
+
704
+ let(:collection) do
705
+ authorized_collection.with(write_concern: {w: 3})
706
+ end
707
+
708
+ let!(:command) do
709
+ Utils.get_command_event(authorized_client, 'insert') do |client|
710
+ collection.insert_one({name: 'test1'}, session: session, write_concern: {w: 1},
711
+ bypass_document_validation: true)
712
+ end.command
713
+ end
714
+
715
+ it 'inserts one successfully with correct options sent to server' do
716
+ expect(events.length).to eq(1)
717
+ expect(command[:writeConcern]).to_not be_nil
718
+ expect(command[:writeConcern][:w]).to eq(1)
719
+ expect(command[:bypassDocumentValidation]).to be(true)
720
+ end
721
+ end
722
+
723
+ context 'when the document contains dotted keys' do
724
+
725
+ let(:doc) do
726
+ { 'testing.test' => 'value' }
727
+ end
728
+
729
+ it 'inserts the document correctly' do
730
+ expect {
731
+ authorized_collection.insert_one(doc)
732
+ }.to_not raise_error
733
+
734
+ expect(authorized_collection.count).to eq(1)
735
+ expect(authorized_collection.find.first['testing.test']).to eq('value')
736
+ end
737
+ end
738
+
739
+ context 'when the document is nil' do
740
+ let(:result) do
741
+ authorized_collection.insert_one(nil)
742
+ end
743
+
744
+ it 'raises an ArgumentError' do
745
+ expect {
746
+ result
747
+ }.to raise_error(ArgumentError, "Document to be inserted cannot be nil")
748
+ end
749
+ end
750
+
751
+ context 'when the insert fails' do
752
+
753
+ let(:result) do
754
+ authorized_collection.insert_one(_id: 1)
755
+ authorized_collection.insert_one(_id: 1)
756
+ end
757
+
758
+ it 'raises an OperationFailure' do
759
+ expect {
760
+ result
761
+ }.to raise_exception(Mongo::Error::OperationFailure)
762
+ end
763
+ end
764
+
765
+ context 'when the client has a custom id generator' do
766
+
767
+ let(:generator) do
768
+ Class.new do
769
+ def generate
770
+ 1
771
+ end
772
+ end.new
773
+ end
774
+
775
+ let(:custom_client) do
776
+ authorized_client.with(id_generator: generator)
777
+ end
778
+
779
+ let(:custom_collection) do
780
+ custom_client[TEST_COLL]
781
+ end
782
+
783
+ before do
784
+ custom_collection.delete_many
785
+ custom_collection.insert_one({ name: 'testing' })
786
+ end
787
+
788
+ it 'inserts with the custom id' do
789
+ expect(custom_collection.find.first[:_id]).to eq(1)
790
+ end
791
+ end
792
+
793
+ context 'when collection has a validator' do
794
+ min_server_fcv '3.2'
795
+
796
+ around(:each) do |spec|
797
+ authorized_client[:validating,
798
+ :validator => { :a => { '$exists' => true } }].tap do |c|
799
+ c.create
800
+ end
801
+ spec.run
802
+ collection_with_validator.drop
803
+ end
804
+
805
+ context 'when the document is valid' do
806
+
807
+ let(:result) do
808
+ collection_with_validator.insert_one({ a: 1 })
809
+ end
810
+
811
+ it 'inserts successfully' do
812
+ expect(result.written_count).to eq(1)
813
+ end
814
+ end
815
+
816
+ context 'when the document is invalid' do
817
+
818
+ context 'when bypass_document_validation is not set' do
819
+
820
+ let(:result2) do
821
+ collection_with_validator.insert_one({ x: 1 })
822
+ end
823
+
824
+ it 'raises a OperationFailure' do
825
+ expect {
826
+ result2
827
+ }.to raise_exception(Mongo::Error::OperationFailure)
828
+ end
829
+ end
830
+
831
+ context 'when bypass_document_validation is true' do
832
+
833
+ let(:result3) do
834
+ collection_with_validator.insert_one(
835
+ { x: 1 }, :bypass_document_validation => true)
836
+ end
837
+
838
+ it 'inserts successfully' do
839
+ expect(result3.written_count).to eq(1)
840
+ end
841
+ end
842
+ end
843
+ end
844
+ end
845
+
846
+ describe '#bulk_write' do
847
+
848
+ context 'when various options passed in' do
849
+ min_server_fcv '3.2'
850
+ require_topology :replica_set
851
+
852
+ # https://jira.mongodb.org/browse/RUBY-2306
853
+ min_server_fcv '3.6'
854
+
855
+ let(:requests) do
856
+ [
857
+ { insert_one: { name: "anne" }},
858
+ { insert_one: { name: "bob" }},
859
+ { insert_one: { name: "charlie" }}
860
+ ]
861
+ end
862
+
863
+ let(:session) do
864
+ authorized_client.start_session
865
+ end
866
+
867
+ let!(:command) do
868
+ Utils.get_command_event(authorized_client, 'insert') do |client|
869
+ collection.bulk_write(requests, session: session, write_concern: {w: 1},
870
+ bypass_document_validation: true)
871
+ end.command
872
+ end
873
+
874
+ let(:events) do
875
+ subscriber.command_started_events('insert')
876
+ end
877
+
878
+ let(:collection) do
879
+ authorized_collection.with(write_concern: {w: 2})
880
+ end
881
+
882
+ it 'inserts successfully with correct options sent to server' do
883
+ expect(collection.count).to eq(3)
884
+ expect(events.length).to eq(1)
885
+ expect(command[:writeConcern]).to_not be_nil
886
+ expect(command[:writeConcern][:w]).to eq(1)
887
+ expect(command[:bypassDocumentValidation]).to eq(true)
888
+ end
889
+ end
890
+ end
891
+
892
+ describe '#aggregate' do
893
+
894
+ describe 'updating cluster time' do
895
+
896
+ let(:operation) do
897
+ client[TEST_COLL].aggregate([]).first
898
+ end
899
+
900
+ let(:operation_with_session) do
901
+ client[TEST_COLL].aggregate([], session: session).first
902
+ end
903
+
904
+ let(:second_operation) do
905
+ client[TEST_COLL].aggregate([], session: session).first
906
+ end
907
+
908
+ it_behaves_like 'an operation updating cluster time'
909
+ end
910
+
911
+ context 'when a session supporting causal consistency is used' do
912
+ require_wired_tiger
913
+
914
+ let(:operation) do
915
+ collection.aggregate([], session: session).first
916
+ end
917
+
918
+ let(:command) do
919
+ operation
920
+ subscriber.started_events.find { |cmd| cmd.command_name == 'aggregate' }.command
921
+ end
922
+
923
+ it_behaves_like 'an operation supporting causally consistent reads'
924
+ end
925
+
926
+ it 'returns an Aggregation object' do
927
+ expect(authorized_collection.aggregate([])).to be_a(Mongo::Collection::View::Aggregation)
928
+ end
929
+
930
+ context 'when options are provided' do
931
+
932
+ let(:options) do
933
+ { :allow_disk_use => true, :bypass_document_validation => true }
934
+ end
935
+
936
+ it 'sets the options on the Aggregation object' do
937
+ expect(authorized_collection.aggregate([], options).options).to eq(BSON::Document.new(options))
938
+ end
939
+
940
+ context 'when the :comment option is provided' do
941
+
942
+ let(:options) do
943
+ { :comment => 'testing' }
944
+ end
945
+
946
+ it 'sets the options on the Aggregation object' do
947
+ expect(authorized_collection.aggregate([], options).options).to eq(BSON::Document.new(options))
948
+ end
949
+ end
950
+
951
+ context 'when a session is provided' do
952
+
953
+ let(:session) do
954
+ authorized_client.start_session
955
+ end
956
+
957
+ let(:operation) do
958
+ authorized_collection.aggregate([], session: session).to_a
959
+ end
960
+
961
+ let(:failed_operation) do
962
+ authorized_collection.aggregate([ { '$invalid' => 1 }], session: session).to_a
963
+ end
964
+
965
+ let(:client) do
966
+ authorized_client
967
+ end
968
+
969
+ it_behaves_like 'an operation using a session'
970
+ it_behaves_like 'a failed operation using a session'
971
+ end
972
+
973
+ context 'when a hint is provided' do
974
+
975
+ let(:options) do
976
+ { 'hint' => { 'y' => 1 } }
977
+ end
978
+
979
+ it 'sets the options on the Aggregation object' do
980
+ expect(authorized_collection.aggregate([], options).options).to eq(options)
981
+ end
982
+ end
983
+
984
+ context 'when collation is provided' do
985
+
986
+ before do
987
+ authorized_collection.insert_many([ { name: 'bang' }, { name: 'bang' }])
988
+ end
989
+
990
+ let(:pipeline) do
991
+ [{ "$match" => { "name" => "BANG" } }]
992
+ end
993
+
994
+ let(:options) do
995
+ { collation: { locale: 'en_US', strength: 2 } }
996
+ end
997
+
998
+ let(:result) do
999
+ authorized_collection.aggregate(pipeline, options).collect { |doc| doc['name']}
1000
+ end
1001
+
1002
+ context 'when the server selected supports collations' do
1003
+ min_server_fcv '3.4'
1004
+
1005
+ it 'applies the collation' do
1006
+ expect(result).to eq(['bang', 'bang'])
1007
+ end
1008
+ end
1009
+
1010
+ context 'when the server selected does not support collations' do
1011
+ max_server_version '3.2'
1012
+
1013
+ it 'raises an exception' do
1014
+ expect {
1015
+ result
1016
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1017
+ end
1018
+
1019
+ context 'when a String key is used' do
1020
+
1021
+ let(:options) do
1022
+ { 'collation' => { locale: 'en_US', strength: 2 } }
1023
+ end
1024
+
1025
+ it 'raises an exception' do
1026
+ expect {
1027
+ result
1028
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1029
+ end
1030
+ end
1031
+ end
1032
+ end
1033
+ end
1034
+ end
1035
+
1036
+ describe '#count_documents' do
1037
+
1038
+ before do
1039
+ authorized_collection.delete_many
1040
+ end
1041
+
1042
+ context 'no argument provided' do
1043
+
1044
+ context 'when collection is empty' do
1045
+ it 'returns 0 matching documents' do
1046
+ expect(authorized_collection.count_documents).to eq(0)
1047
+ end
1048
+ end
1049
+
1050
+ context 'when collection is not empty' do
1051
+
1052
+ let(:documents) do
1053
+ documents = []
1054
+ 1.upto(10) do |index|
1055
+ documents << { key: 'a', _id: "in#{index}" }
1056
+ end
1057
+ documents
1058
+ end
1059
+
1060
+ before do
1061
+ authorized_collection.insert_many(documents)
1062
+ end
1063
+
1064
+ it 'returns 10 matching documents' do
1065
+ expect(authorized_collection.count_documents).to eq(10)
1066
+ end
1067
+ end
1068
+ end
1069
+
1070
+ context 'when transactions are enabled' do
1071
+ require_wired_tiger
1072
+ require_transaction_support
1073
+
1074
+ before do
1075
+ # Ensure that the collection is created
1076
+ authorized_collection.insert_one(x: 1)
1077
+ authorized_collection.delete_many({})
1078
+ end
1079
+
1080
+ let(:session) do
1081
+ authorized_client.start_session
1082
+ end
1083
+
1084
+ it 'successfully starts a transaction and executes a transaction' do
1085
+ session.start_transaction
1086
+ expect(
1087
+ session.instance_variable_get(:@state)
1088
+ ).to eq(Mongo::Session::STARTING_TRANSACTION_STATE)
1089
+
1090
+ expect(authorized_collection.count_documents({}, { session: session })).to eq(0)
1091
+ expect(
1092
+ session.instance_variable_get(:@state)
1093
+ ).to eq(Mongo::Session::TRANSACTION_IN_PROGRESS_STATE)
1094
+
1095
+ authorized_collection.insert_one({ x: 1 }, { session: session })
1096
+ expect(authorized_collection.count_documents({}, { session: session })).to eq(1)
1097
+
1098
+ session.commit_transaction
1099
+ expect(
1100
+ session.instance_variable_get(:@state)
1101
+ ).to eq(Mongo::Session::TRANSACTION_COMMITTED_STATE)
1102
+ end
1103
+ end
1104
+ end
1105
+
1106
+ describe '#count' do
1107
+
1108
+ let(:documents) do
1109
+ (1..10).map{ |i| { field: "test#{i}" }}
1110
+ end
1111
+
1112
+ before do
1113
+ authorized_collection.insert_many(documents)
1114
+ end
1115
+
1116
+ it 'returns an integer count' do
1117
+ expect(authorized_collection.count).to eq(10)
1118
+ end
1119
+
1120
+ context 'when options are provided' do
1121
+
1122
+ it 'passes the options to the count' do
1123
+ expect(authorized_collection.count({}, limit: 5)).to eq(5)
1124
+ end
1125
+
1126
+ context 'when a session is provided' do
1127
+ require_wired_tiger
1128
+
1129
+ let(:session) do
1130
+ authorized_client.start_session
1131
+ end
1132
+
1133
+ let(:operation) do
1134
+ authorized_collection.count({}, session: session)
1135
+ end
1136
+
1137
+ let(:failed_operation) do
1138
+ authorized_collection.count({ '$._id' => 1 }, session: session)
1139
+ end
1140
+
1141
+ let(:client) do
1142
+ authorized_client
1143
+ end
1144
+
1145
+ it_behaves_like 'an operation using a session'
1146
+ it_behaves_like 'a failed operation using a session'
1147
+ end
1148
+
1149
+ context 'when a session supporting causal consistency is used' do
1150
+ require_wired_tiger
1151
+
1152
+ let(:operation) do
1153
+ collection.count({}, session: session)
1154
+ end
1155
+
1156
+ let(:command) do
1157
+ operation
1158
+ subscriber.started_events.find { |cmd| cmd.command_name == 'count' }.command
1159
+ end
1160
+
1161
+ it_behaves_like 'an operation supporting causally consistent reads'
1162
+ end
1163
+
1164
+ context 'when a collation is specified' do
1165
+
1166
+ let(:selector) do
1167
+ { name: 'BANG' }
1168
+ end
1169
+
1170
+ let(:result) do
1171
+ authorized_collection.count(selector, options)
1172
+ end
1173
+
1174
+ before do
1175
+ authorized_collection.insert_one(name: 'bang')
1176
+ end
1177
+
1178
+ let(:options) do
1179
+ { collation: { locale: 'en_US', strength: 2 } }
1180
+ end
1181
+
1182
+ context 'when the server selected supports collations' do
1183
+ min_server_fcv '3.4'
1184
+
1185
+ it 'applies the collation to the count' do
1186
+ expect(result).to eq(1)
1187
+ end
1188
+ end
1189
+
1190
+ context 'when the server selected does not support collations' do
1191
+ max_server_version '3.2'
1192
+
1193
+ it 'raises an exception' do
1194
+ expect {
1195
+ result
1196
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1197
+ end
1198
+
1199
+ context 'when a String key is used' do
1200
+
1201
+ let(:options) do
1202
+ { 'collation' => { locale: 'en_US', strength: 2 } }
1203
+ end
1204
+
1205
+ it 'raises an exception' do
1206
+ expect {
1207
+ result
1208
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1209
+ end
1210
+ end
1211
+ end
1212
+ end
1213
+ end
1214
+ end
1215
+
1216
+ describe '#distinct' do
1217
+
1218
+ let(:documents) do
1219
+ (1..3).map{ |i| { field: "test#{i}" }}
1220
+ end
1221
+
1222
+ before do
1223
+ authorized_collection.insert_many(documents)
1224
+ end
1225
+
1226
+ it 'returns the distinct values' do
1227
+ expect(authorized_collection.distinct(:field).sort).to eq([ 'test1', 'test2', 'test3' ])
1228
+ end
1229
+
1230
+ context 'when a selector is provided' do
1231
+
1232
+ it 'returns the distinct values' do
1233
+ expect(authorized_collection.distinct(:field, field: 'test1')).to eq([ 'test1' ])
1234
+ end
1235
+ end
1236
+
1237
+ context 'when options are provided' do
1238
+
1239
+ it 'passes the options to the distinct command' do
1240
+ expect(authorized_collection.distinct(:field, {}, max_time_ms: 100).sort).to eq([ 'test1', 'test2', 'test3' ])
1241
+ end
1242
+
1243
+ context 'when a session is provided' do
1244
+ require_wired_tiger
1245
+
1246
+ let(:session) do
1247
+ authorized_client.start_session
1248
+ end
1249
+
1250
+ let(:operation) do
1251
+ authorized_collection.distinct(:field, {}, session: session)
1252
+ end
1253
+
1254
+ let(:failed_operation) do
1255
+ authorized_collection.distinct(:field, { '$._id' => 1 }, session: session)
1256
+ end
1257
+
1258
+ let(:client) do
1259
+ authorized_client
1260
+ end
1261
+
1262
+ it_behaves_like 'an operation using a session'
1263
+ it_behaves_like 'a failed operation using a session'
1264
+ end
1265
+ end
1266
+
1267
+ context 'when a session supporting causal consistency is used' do
1268
+ require_wired_tiger
1269
+
1270
+ let(:operation) do
1271
+ collection.distinct(:field, {}, session: session)
1272
+ end
1273
+
1274
+ let(:command) do
1275
+ operation
1276
+ subscriber.started_events.find { |cmd| cmd.command_name == 'distinct' }.command
1277
+ end
1278
+
1279
+ it_behaves_like 'an operation supporting causally consistent reads'
1280
+ end
1281
+
1282
+ context 'when a collation is specified' do
1283
+
1284
+ let(:result) do
1285
+ authorized_collection.distinct(:name, {}, options)
1286
+ end
1287
+
1288
+ before do
1289
+ authorized_collection.insert_one(name: 'bang')
1290
+ authorized_collection.insert_one(name: 'BANG')
1291
+ end
1292
+
1293
+ let(:options) do
1294
+ { collation: { locale: 'en_US', strength: 2 } }
1295
+ end
1296
+
1297
+ context 'when the server selected supports collations' do
1298
+ min_server_fcv '3.4'
1299
+
1300
+ it 'applies the collation to the distinct' do
1301
+ expect(result).to eq(['bang'])
1302
+ end
1303
+ end
1304
+
1305
+ context 'when the server selected does not support collations' do
1306
+ max_server_version '3.2'
1307
+
1308
+ it 'raises an exception' do
1309
+ expect {
1310
+ result
1311
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1312
+ end
1313
+
1314
+ context 'when a String key is used' do
1315
+
1316
+ let(:options) do
1317
+ { 'collation' => { locale: 'en_US', strength: 2 } }
1318
+ end
1319
+
1320
+ it 'raises an exception' do
1321
+ expect {
1322
+ result
1323
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1324
+ end
1325
+ end
1326
+ end
1327
+ end
1328
+
1329
+ context 'when a collation is not specified' do
1330
+
1331
+ let(:result) do
1332
+ authorized_collection.distinct(:name)
1333
+ end
1334
+
1335
+ before do
1336
+ authorized_collection.insert_one(name: 'bang')
1337
+ authorized_collection.insert_one(name: 'BANG')
1338
+ end
1339
+
1340
+ it 'does not apply the collation to the distinct' do
1341
+ expect(result).to match_array(['bang', 'BANG'])
1342
+ end
1343
+ end
1344
+ end
1345
+
1346
+ describe '#delete_one' do
1347
+
1348
+ context 'when a selector was provided' do
1349
+
1350
+ let(:selector) do
1351
+ { field: 'test1' }
1352
+ end
1353
+
1354
+ before do
1355
+ authorized_collection.insert_many([
1356
+ { field: 'test1' },
1357
+ { field: 'test1' },
1358
+ { field: 'test1' }
1359
+ ])
1360
+ end
1361
+
1362
+ let(:response) do
1363
+ authorized_collection.delete_one(selector)
1364
+ end
1365
+
1366
+ it 'deletes the first matching document in the collection' do
1367
+ expect(response.deleted_count).to eq(1)
1368
+ end
1369
+ end
1370
+
1371
+ context 'when no selector was provided' do
1372
+
1373
+ before do
1374
+ authorized_collection.insert_many([{ field: 'test1' }, { field: 'test2' }])
1375
+ end
1376
+
1377
+ let(:response) do
1378
+ authorized_collection.delete_one
1379
+ end
1380
+
1381
+ it 'deletes the first document in the collection' do
1382
+ expect(response.deleted_count).to eq(1)
1383
+ end
1384
+ end
1385
+
1386
+ context 'when the delete fails' do
1387
+ require_topology :single
1388
+
1389
+ let(:result) do
1390
+ collection_invalid_write_concern.delete_one
1391
+ end
1392
+
1393
+ it 'raises an OperationFailure' do
1394
+ expect {
1395
+ result
1396
+ }.to raise_exception(Mongo::Error::OperationFailure)
1397
+ end
1398
+ end
1399
+
1400
+ context 'when a session is provided' do
1401
+
1402
+ let(:session) do
1403
+ authorized_client.start_session
1404
+ end
1405
+
1406
+ let(:operation) do
1407
+ authorized_collection.delete_one({}, session: session)
1408
+ end
1409
+
1410
+ let(:failed_operation) do
1411
+ authorized_collection.delete_one({ '$._id' => 1}, session: session)
1412
+ end
1413
+
1414
+ let(:client) do
1415
+ authorized_client
1416
+ end
1417
+
1418
+ it_behaves_like 'an operation using a session'
1419
+ it_behaves_like 'a failed operation using a session'
1420
+ end
1421
+
1422
+ context 'when unacknowledged writes is used' do
1423
+
1424
+ let(:collection_with_unacknowledged_write_concern) do
1425
+ authorized_collection.with(write: { w: 0 })
1426
+ end
1427
+
1428
+ let(:operation) do
1429
+ collection_with_unacknowledged_write_concern.delete_one({}, session: session)
1430
+ end
1431
+
1432
+ it_behaves_like 'an explicit session with an unacknowledged write'
1433
+ end
1434
+
1435
+ context 'when unacknowledged writes is used with an implicit session' do
1436
+
1437
+ let(:collection_with_unacknowledged_write_concern) do
1438
+ client.with(write: { w: 0 })[TEST_COLL]
1439
+ end
1440
+
1441
+ let(:operation) do
1442
+ collection_with_unacknowledged_write_concern.delete_one
1443
+ end
1444
+
1445
+ it_behaves_like 'an implicit session with an unacknowledged write'
1446
+ end
1447
+
1448
+ context 'when a collation is provided' do
1449
+
1450
+ let(:selector) do
1451
+ { name: 'BANG' }
1452
+ end
1453
+
1454
+ let(:result) do
1455
+ authorized_collection.delete_one(selector, options)
1456
+ end
1457
+
1458
+ before do
1459
+ authorized_collection.insert_one(name: 'bang')
1460
+ end
1461
+
1462
+ let(:options) do
1463
+ { collation: { locale: 'en_US', strength: 2 } }
1464
+ end
1465
+
1466
+ context 'when the server selected supports collations' do
1467
+ min_server_fcv '3.4'
1468
+
1469
+ it 'applies the collation' do
1470
+ expect(result.written_count).to eq(1)
1471
+ expect(authorized_collection.find(name: 'bang').count).to eq(0)
1472
+ end
1473
+
1474
+ context 'when unacknowledged writes is used' do
1475
+
1476
+ let(:collection_with_unacknowledged_write_concern) do
1477
+ authorized_collection.with(write: { w: 0 })
1478
+ end
1479
+
1480
+ let(:result) do
1481
+ collection_with_unacknowledged_write_concern.delete_one(selector, options)
1482
+ end
1483
+
1484
+ it 'raises an exception' do
1485
+ expect {
1486
+ result
1487
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1488
+ end
1489
+
1490
+ context 'when a String key is used' do
1491
+
1492
+ let(:options) do
1493
+ { 'collation' => { locale: 'en_US', strength: 2 } }
1494
+ end
1495
+
1496
+ it 'raises an exception' do
1497
+ expect {
1498
+ result
1499
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1500
+ end
1501
+ end
1502
+ end
1503
+ end
1504
+
1505
+ context 'when the server selected does not support collations' do
1506
+ max_server_version '3.2'
1507
+
1508
+ it 'raises an exception' do
1509
+ expect {
1510
+ result
1511
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1512
+ end
1513
+
1514
+ context 'when a String key is used' do
1515
+
1516
+ let(:options) do
1517
+ { 'collation' => { locale: 'en_US', strength: 2 } }
1518
+ end
1519
+
1520
+ it 'raises an exception' do
1521
+ expect {
1522
+ result
1523
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1524
+ end
1525
+ end
1526
+ end
1527
+ end
1528
+
1529
+ context 'when collation is not specified' do
1530
+
1531
+ let(:selector) do
1532
+ { name: 'BANG' }
1533
+ end
1534
+
1535
+ let(:result) do
1536
+ authorized_collection.delete_one(selector)
1537
+ end
1538
+
1539
+ before do
1540
+ authorized_collection.insert_one(name: 'bang')
1541
+ end
1542
+
1543
+ it 'does not apply the collation' do
1544
+ expect(result.written_count).to eq(0)
1545
+ expect(authorized_collection.find(name: 'bang').count).to eq(1)
1546
+ end
1547
+ end
1548
+
1549
+ context 'when various options passed in' do
1550
+ # w: 2 requires a replica set
1551
+ require_topology :replica_set
1552
+
1553
+ # https://jira.mongodb.org/browse/RUBY-2306
1554
+ min_server_fcv '3.6'
1555
+
1556
+ before do
1557
+ authorized_collection.insert_many([{ name: 'test1' }, { name: 'test2' }])
1558
+ end
1559
+
1560
+ let(:selector) do
1561
+ {name: 'test2'}
1562
+ end
1563
+
1564
+ let(:session) do
1565
+ authorized_client.start_session
1566
+ end
1567
+
1568
+ let(:events) do
1569
+ subscriber.command_started_events('delete')
1570
+ end
1571
+
1572
+ let(:collection) do
1573
+ authorized_collection.with(write_concern: {w: 2})
1574
+ end
1575
+
1576
+ let!(:command) do
1577
+ Utils.get_command_event(authorized_client, 'delete') do |client|
1578
+ collection.delete_one(selector, session: session, write_concern: {w: 1},
1579
+ bypass_document_validation: true)
1580
+ end.command
1581
+ end
1582
+
1583
+ it 'deletes one successfully with correct options sent to server' do
1584
+ expect(events.length).to eq(1)
1585
+ expect(command[:writeConcern]).to_not be_nil
1586
+ expect(command[:writeConcern][:w]).to eq(1)
1587
+ expect(command[:bypassDocumentValidation]).to eq(true)
1588
+ end
1589
+ end
1590
+ end
1591
+
1592
+ describe '#delete_many' do
1593
+
1594
+ before do
1595
+ authorized_collection.insert_many([{ field: 'test1' }, { field: 'test2' }])
1596
+ end
1597
+
1598
+ context 'when a selector was provided' do
1599
+
1600
+ let(:selector) do
1601
+ { field: 'test1' }
1602
+ end
1603
+
1604
+ it 'deletes the matching documents in the collection' do
1605
+ expect(authorized_collection.delete_many(selector).deleted_count).to eq(1)
1606
+ end
1607
+ end
1608
+
1609
+ context 'when no selector was provided' do
1610
+
1611
+ it 'deletes all the documents in the collection' do
1612
+ expect(authorized_collection.delete_many.deleted_count).to eq(2)
1613
+ end
1614
+ end
1615
+
1616
+ context 'when the deletes fail' do
1617
+ require_topology :single
1618
+
1619
+ let(:result) do
1620
+ collection_invalid_write_concern.delete_many
1621
+ end
1622
+
1623
+ it 'raises an OperationFailure' do
1624
+ expect {
1625
+ result
1626
+ }.to raise_exception(Mongo::Error::OperationFailure)
1627
+ end
1628
+ end
1629
+
1630
+ context 'when a session is provided' do
1631
+
1632
+ let(:session) do
1633
+ authorized_client.start_session
1634
+ end
1635
+
1636
+ let(:operation) do
1637
+ authorized_collection.delete_many({}, session: session)
1638
+ end
1639
+
1640
+ let(:failed_operation) do
1641
+ authorized_collection.delete_many({ '$._id' => 1}, session: session)
1642
+ end
1643
+
1644
+ let(:client) do
1645
+ authorized_client
1646
+ end
1647
+
1648
+ it_behaves_like 'an operation using a session'
1649
+ it_behaves_like 'a failed operation using a session'
1650
+ end
1651
+
1652
+ context 'when unacknowledged writes are used with an explicit session' do
1653
+
1654
+ let(:collection_with_unacknowledged_write_concern) do
1655
+ authorized_collection.with(write: { w: 0 })
1656
+ end
1657
+
1658
+ let(:operation) do
1659
+ collection_with_unacknowledged_write_concern.delete_many({ '$._id' => 1}, session: session)
1660
+ end
1661
+
1662
+ it_behaves_like 'an explicit session with an unacknowledged write'
1663
+ end
1664
+
1665
+ context 'when unacknowledged writes are used with an implicit session' do
1666
+
1667
+ let(:collection_with_unacknowledged_write_concern) do
1668
+ client.with(write: { w: 0 })[TEST_COLL]
1669
+ end
1670
+
1671
+ let(:operation) do
1672
+ collection_with_unacknowledged_write_concern.delete_many({ '$._id' => 1 })
1673
+ end
1674
+
1675
+ it_behaves_like 'an implicit session with an unacknowledged write'
1676
+ end
1677
+
1678
+ context 'when a collation is specified' do
1679
+
1680
+ let(:selector) do
1681
+ { name: 'BANG' }
1682
+ end
1683
+
1684
+ let(:result) do
1685
+ authorized_collection.delete_many(selector, options)
1686
+ end
1687
+
1688
+ before do
1689
+ authorized_collection.insert_one(name: 'bang')
1690
+ authorized_collection.insert_one(name: 'bang')
1691
+ end
1692
+
1693
+ let(:options) do
1694
+ { collation: { locale: 'en_US', strength: 2 } }
1695
+ end
1696
+
1697
+ context 'when the server selected supports collations' do
1698
+ min_server_fcv '3.4'
1699
+
1700
+ it 'applies the collation' do
1701
+ expect(result.written_count).to eq(2)
1702
+ expect(authorized_collection.find(name: 'bang').count).to eq(0)
1703
+ end
1704
+
1705
+ context 'when unacknowledged writes is used' do
1706
+
1707
+ let(:collection_with_unacknowledged_write_concern) do
1708
+ authorized_collection.with(write: { w: 0 })
1709
+ end
1710
+
1711
+ let(:result) do
1712
+ collection_with_unacknowledged_write_concern.delete_many(selector, options)
1713
+ end
1714
+
1715
+ it 'raises an exception' do
1716
+ expect {
1717
+ result
1718
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1719
+ end
1720
+
1721
+ context 'when a String key is used' do
1722
+
1723
+ let(:options) do
1724
+ { 'collation' => { locale: 'en_US', strength: 2 } }
1725
+ end
1726
+
1727
+ it 'raises an exception' do
1728
+ expect {
1729
+ result
1730
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1731
+ end
1732
+ end
1733
+ end
1734
+ end
1735
+
1736
+ context 'when the server selected does not support collations' do
1737
+ max_server_version '3.2'
1738
+
1739
+ it 'raises an exception' do
1740
+ expect {
1741
+ result
1742
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1743
+ end
1744
+
1745
+ context 'when a String key is used' do
1746
+
1747
+ let(:options) do
1748
+ { 'collation' => { locale: 'en_US', strength: 2 } }
1749
+ end
1750
+
1751
+ it 'raises an exception' do
1752
+ expect {
1753
+ result
1754
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1755
+ end
1756
+ end
1757
+ end
1758
+ end
1759
+
1760
+ context 'when a collation is not specified' do
1761
+
1762
+ let(:selector) do
1763
+ { name: 'BANG' }
1764
+ end
1765
+
1766
+ let(:result) do
1767
+ authorized_collection.delete_many(selector)
1768
+ end
1769
+
1770
+ before do
1771
+ authorized_collection.insert_one(name: 'bang')
1772
+ authorized_collection.insert_one(name: 'bang')
1773
+ end
1774
+
1775
+ it 'does not apply the collation' do
1776
+ expect(result.written_count).to eq(0)
1777
+ expect(authorized_collection.find(name: 'bang').count).to eq(2)
1778
+ end
1779
+ end
1780
+
1781
+ context 'when various options passed in' do
1782
+ # w: 2 requires a replica set
1783
+ require_topology :replica_set
1784
+
1785
+ # https://jira.mongodb.org/browse/RUBY-2306
1786
+ min_server_fcv '3.6'
1787
+
1788
+ before do
1789
+ collection.insert_many([{ name: 'test1' }, { name: 'test2' }, { name: 'test3'}])
1790
+ end
1791
+
1792
+ let(:selector) do
1793
+ {name: 'test1'}
1794
+ end
1795
+
1796
+ let(:session) do
1797
+ authorized_client.start_session
1798
+ end
1799
+
1800
+ let(:events) do
1801
+ subscriber.command_started_events('delete')
1802
+ end
1803
+
1804
+ let(:collection) do
1805
+ authorized_collection.with(write_concern: {w: 1})
1806
+ end
1807
+
1808
+ let!(:command) do
1809
+ Utils.get_command_event(authorized_client, 'delete') do |client|
1810
+ collection.delete_many(selector, session: session, write_concern: {w: 2},
1811
+ bypass_document_validation: true)
1812
+ end.command
1813
+ end
1814
+
1815
+ it 'deletes many successfully with correct options sent to server' do
1816
+ expect(events.length).to eq(1)
1817
+ expect(command[:writeConcern]).to_not be_nil
1818
+ expect(command[:writeConcern][:w]).to eq(2)
1819
+ expect(command[:bypassDocumentValidation]).to be(true)
1820
+ end
1821
+ end
1822
+ end
1823
+
1824
+ describe '#parallel_scan' do
1825
+ max_server_version '4.0'
1826
+ require_topology :single, :replica_set
1827
+
1828
+ let(:documents) do
1829
+ (1..200).map do |i|
1830
+ { name: "testing-scan-#{i}" }
1831
+ end
1832
+ end
1833
+
1834
+ before do
1835
+ authorized_collection.insert_many(documents)
1836
+ end
1837
+
1838
+ let(:cursors) do
1839
+ authorized_collection.parallel_scan(2)
1840
+ end
1841
+
1842
+ it 'returns an array of cursors' do
1843
+ cursors.each do |cursor|
1844
+ expect(cursor.class).to be(Mongo::Cursor)
1845
+ end
1846
+ end
1847
+
1848
+ it 'returns the correct number of documents' do
1849
+ expect(
1850
+ cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
1851
+ ).to eq(200)
1852
+ end
1853
+
1854
+ context 'when a session is provided' do
1855
+ require_wired_tiger
1856
+
1857
+ let(:cursors) do
1858
+ authorized_collection.parallel_scan(2, session: session)
1859
+ end
1860
+
1861
+ let(:operation) do
1862
+ cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
1863
+ end
1864
+
1865
+ let(:failed_operation) do
1866
+ authorized_collection.parallel_scan(-2, session: session)
1867
+ end
1868
+
1869
+ let(:client) do
1870
+ authorized_client
1871
+ end
1872
+
1873
+ it_behaves_like 'an operation using a session'
1874
+ it_behaves_like 'a failed operation using a session'
1875
+ end
1876
+
1877
+ context 'when a session is not provided' do
1878
+ let(:collection) { client['test'] }
1879
+
1880
+ let(:cursors) do
1881
+ collection.parallel_scan(2)
1882
+ end
1883
+
1884
+ let(:operation) do
1885
+ cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
1886
+ end
1887
+
1888
+ let(:failed_operation) do
1889
+ collection.parallel_scan(-2)
1890
+ end
1891
+
1892
+ let(:command) do
1893
+ operation
1894
+ event = subscriber.started_events.find { |cmd| cmd.command_name == 'parallelCollectionScan' }
1895
+ expect(event).not_to be_nil
1896
+ event.command
1897
+ end
1898
+
1899
+ it_behaves_like 'an operation not using a session'
1900
+ it_behaves_like 'a failed operation not using a session'
1901
+ end
1902
+
1903
+ context 'when a session supporting causal consistency is used' do
1904
+ require_wired_tiger
1905
+
1906
+ before do
1907
+ collection.drop
1908
+ collection.create
1909
+ end
1910
+
1911
+ let(:cursors) do
1912
+ collection.parallel_scan(2, session: session)
1913
+ end
1914
+
1915
+ let(:operation) do
1916
+ cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
1917
+ end
1918
+
1919
+ let(:command) do
1920
+ operation
1921
+ event = subscriber.started_events.find { |cmd| cmd.command_name == 'parallelCollectionScan' }
1922
+ expect(event).not_to be_nil
1923
+ event.command
1924
+ end
1925
+
1926
+ it_behaves_like 'an operation supporting causally consistent reads'
1927
+ end
1928
+
1929
+ context 'when a read concern is provided' do
1930
+ require_wired_tiger
1931
+ min_server_fcv '3.2'
1932
+
1933
+ let(:result) do
1934
+ authorized_collection.with(options).parallel_scan(2)
1935
+ end
1936
+
1937
+ context 'when the read concern is valid' do
1938
+
1939
+ let(:options) do
1940
+ { read_concern: { level: 'local' }}
1941
+ end
1942
+
1943
+ it 'sends the read concern' do
1944
+ expect { result }.to_not raise_error
1945
+ end
1946
+ end
1947
+
1948
+ context 'when the read concern is not valid' do
1949
+
1950
+ let(:options) do
1951
+ { read_concern: { level: 'idontknow' }}
1952
+ end
1953
+
1954
+ it 'raises an exception' do
1955
+ expect {
1956
+ result
1957
+ }.to raise_error(Mongo::Error::OperationFailure)
1958
+ end
1959
+ end
1960
+ end
1961
+
1962
+ context 'when the collection has a read preference' do
1963
+ require_topology :single, :replica_set
1964
+
1965
+ before do
1966
+ allow(collection.client.cluster).to receive(:single?).and_return(false)
1967
+ end
1968
+
1969
+ let(:client) do
1970
+ authorized_client.with(server_selection_timeout: 0.2)
1971
+ end
1972
+
1973
+ let(:collection) do
1974
+ client[authorized_collection.name,
1975
+ read: { :mode => :secondary, :tag_sets => [{ 'non' => 'existent' }] }]
1976
+ end
1977
+
1978
+ let(:result) do
1979
+ collection.parallel_scan(2)
1980
+ end
1981
+
1982
+ it 'uses that read preference' do
1983
+ expect {
1984
+ result
1985
+ }.to raise_exception(Mongo::Error::NoServerAvailable)
1986
+ end
1987
+ end
1988
+
1989
+ context 'when a max time ms value is provided' do
1990
+ require_topology :single, :replica_set
1991
+
1992
+ let(:result) do
1993
+ authorized_collection.parallel_scan(2, options)
1994
+ end
1995
+
1996
+ context 'when the read concern is valid' do
1997
+
1998
+ let(:options) do
1999
+ { max_time_ms: 5 }
2000
+ end
2001
+
2002
+ it 'sends the max time ms value' do
2003
+ expect { result }.to_not raise_error
2004
+ end
2005
+ end
2006
+
2007
+ context 'when the max time ms is not valid' do
2008
+
2009
+ let(:options) do
2010
+ { max_time_ms: 0.1 }
2011
+ end
2012
+
2013
+ it 'raises an exception' do
2014
+ expect {
2015
+ result
2016
+ }.to raise_error(Mongo::Error::OperationFailure)
2017
+ end
2018
+ end
2019
+ end
2020
+ end
2021
+
2022
+ describe '#replace_one' do
2023
+
2024
+ let(:selector) do
2025
+ { field: 'test1' }
2026
+ end
2027
+
2028
+ context 'when a selector was provided' do
2029
+
2030
+ before do
2031
+ authorized_collection.insert_many([{ field: 'test1' }, { field: 'test1' }])
2032
+ end
2033
+
2034
+ let!(:response) do
2035
+ authorized_collection.replace_one(selector, { field: 'testing' })
2036
+ end
2037
+
2038
+ let(:updated) do
2039
+ authorized_collection.find(field: 'testing').first
2040
+ end
2041
+
2042
+ it 'updates the first matching document in the collection' do
2043
+ expect(response.modified_count).to eq(1)
2044
+ end
2045
+
2046
+ it 'updates the documents in the collection' do
2047
+ expect(updated[:field]).to eq('testing')
2048
+ end
2049
+ end
2050
+
2051
+ context 'when upsert is false' do
2052
+
2053
+ let!(:response) do
2054
+ authorized_collection.replace_one(selector, { field: 'test1' }, upsert: false)
2055
+ end
2056
+
2057
+ let(:updated) do
2058
+ authorized_collection.find(field: 'test1').to_a
2059
+ end
2060
+
2061
+ it 'reports that no documents were written' do
2062
+ expect(response.modified_count).to eq(0)
2063
+ end
2064
+
2065
+ it 'does not insert the document' do
2066
+ expect(updated).to be_empty
2067
+ end
2068
+ end
2069
+
2070
+ context 'when upsert is true' do
2071
+
2072
+ let!(:response) do
2073
+ authorized_collection.replace_one(selector, { field: 'test1' }, upsert: true)
2074
+ end
2075
+
2076
+ let(:updated) do
2077
+ authorized_collection.find(field: 'test1').first
2078
+ end
2079
+
2080
+ it 'reports that a document was written' do
2081
+ expect(response.written_count).to eq(1)
2082
+ end
2083
+
2084
+ it 'inserts the document' do
2085
+ expect(updated[:field]).to eq('test1')
2086
+ end
2087
+ end
2088
+
2089
+ context 'when upsert is not specified' do
2090
+
2091
+ let!(:response) do
2092
+ authorized_collection.replace_one(selector, { field: 'test1' })
2093
+ end
2094
+
2095
+ let(:updated) do
2096
+ authorized_collection.find(field: 'test1').to_a
2097
+ end
2098
+
2099
+ it 'reports that no documents were written' do
2100
+ expect(response.modified_count).to eq(0)
2101
+ end
2102
+
2103
+ it 'does not insert the document' do
2104
+ expect(updated).to be_empty
2105
+ end
2106
+ end
2107
+
2108
+ context 'when the replace has an invalid key' do
2109
+
2110
+ context "when validate_update_replace is true" do
2111
+
2112
+ config_override :validate_update_replace, true
2113
+
2114
+ let(:result) do
2115
+ authorized_collection.replace_one(selector, { '$s' => 'test1' })
2116
+ end
2117
+
2118
+ it 'raises an InvalidReplacementDocument error' do
2119
+ expect {
2120
+ result
2121
+ }.to raise_exception(Mongo::Error::InvalidReplacementDocument)
2122
+ end
2123
+ end
2124
+
2125
+ context "when validate_update_replace is false" do
2126
+
2127
+ config_override :validate_update_replace, false
2128
+
2129
+ let(:result) do
2130
+ authorized_collection.replace_one(selector, { '$set' => { 'test1' => 1 } })
2131
+ end
2132
+
2133
+ it 'does not raise an error' do
2134
+ expect {
2135
+ result
2136
+ }.to_not raise_exception
2137
+ end
2138
+ end
2139
+ end
2140
+
2141
+ context 'when collection has a validator' do
2142
+ min_server_fcv '3.2'
2143
+
2144
+ around(:each) do |spec|
2145
+ collection_with_validator.drop
2146
+ authorized_client[:validating,
2147
+ :validator => { :a => { '$exists' => true } }].tap do |c|
2148
+ c.create
2149
+ end
2150
+ spec.run
2151
+ collection_with_validator.drop
2152
+ end
2153
+
2154
+ before do
2155
+ collection_with_validator.insert_one({ a: 1 })
2156
+ end
2157
+
2158
+ context 'when the document is valid' do
2159
+
2160
+ let(:result) do
2161
+ collection_with_validator.replace_one({ a: 1 }, { a: 5 })
2162
+ end
2163
+
2164
+ it 'replaces successfully' do
2165
+ expect(result.modified_count).to eq(1)
2166
+ end
2167
+ end
2168
+
2169
+ context 'when the document is invalid' do
2170
+
2171
+ context 'when bypass_document_validation is not set' do
2172
+
2173
+ let(:result2) do
2174
+ collection_with_validator.replace_one({ a: 1 }, { x: 5 })
2175
+ end
2176
+
2177
+ it 'raises OperationFailure' do
2178
+ expect {
2179
+ result2
2180
+ }.to raise_exception(Mongo::Error::OperationFailure)
2181
+ end
2182
+ end
2183
+
2184
+ context 'when bypass_document_validation is true' do
2185
+
2186
+ let(:result3) do
2187
+ collection_with_validator.replace_one(
2188
+ { a: 1 }, { x: 1 }, :bypass_document_validation => true)
2189
+ end
2190
+
2191
+ it 'replaces successfully' do
2192
+ expect(result3.written_count).to eq(1)
2193
+ end
2194
+ end
2195
+ end
2196
+ end
2197
+
2198
+ context 'when a collation is specified' do
2199
+
2200
+ let(:selector) do
2201
+ { name: 'BANG' }
2202
+ end
2203
+
2204
+ let(:result) do
2205
+ authorized_collection.replace_one(selector, { name: 'doink' }, options)
2206
+ end
2207
+
2208
+ before do
2209
+ authorized_collection.insert_one(name: 'bang')
2210
+ end
2211
+
2212
+ let(:options) do
2213
+ { collation: { locale: 'en_US', strength: 2 } }
2214
+ end
2215
+
2216
+ context 'when the server selected supports collations' do
2217
+ min_server_fcv '3.4'
2218
+
2219
+ it 'applies the collation' do
2220
+ expect(result.written_count).to eq(1)
2221
+ expect(authorized_collection.find(name: 'doink').count).to eq(1)
2222
+ end
2223
+
2224
+ context 'when unacknowledged writes is used' do
2225
+
2226
+ let(:collection_with_unacknowledged_write_concern) do
2227
+ authorized_collection.with(write: { w: 0 })
2228
+ end
2229
+
2230
+ let(:result) do
2231
+ collection_with_unacknowledged_write_concern.replace_one(selector, { name: 'doink' }, options)
2232
+ end
2233
+
2234
+ it 'raises an exception' do
2235
+ expect {
2236
+ result
2237
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
2238
+ end
2239
+
2240
+ context 'when a String key is used' do
2241
+
2242
+ let(:options) do
2243
+ { 'collation' => { locale: 'en_US', strength: 2 } }
2244
+ end
2245
+
2246
+ it 'raises an exception' do
2247
+ expect {
2248
+ result
2249
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
2250
+ end
2251
+ end
2252
+ end
2253
+ end
2254
+
2255
+ context 'when the server selected does not support collations' do
2256
+ max_server_version '3.2'
2257
+
2258
+ it 'raises an exception' do
2259
+ expect {
2260
+ result
2261
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
2262
+ end
2263
+
2264
+ context 'when a String key is used' do
2265
+
2266
+ let(:options) do
2267
+ { 'collation' => { locale: 'en_US', strength: 2 } }
2268
+ end
2269
+
2270
+ it 'raises an exception' do
2271
+ expect {
2272
+ result
2273
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
2274
+ end
2275
+ end
2276
+ end
2277
+ end
2278
+
2279
+ context 'when a collation is not specified' do
2280
+
2281
+ let(:selector) do
2282
+ { name: 'BANG' }
2283
+ end
2284
+
2285
+ let(:result) do
2286
+ authorized_collection.replace_one(selector, { name: 'doink' })
2287
+ end
2288
+
2289
+ before do
2290
+ authorized_collection.insert_one(name: 'bang')
2291
+ end
2292
+
2293
+ it 'does not apply the collation' do
2294
+ expect(result.written_count).to eq(0)
2295
+ expect(authorized_collection.find(name: 'bang').count).to eq(1)
2296
+ end
2297
+ end
2298
+
2299
+ context 'when a session is provided' do
2300
+
2301
+ let(:selector) do
2302
+ { name: 'BANG' }
2303
+ end
2304
+
2305
+ before do
2306
+ authorized_collection.insert_one(name: 'bang')
2307
+ end
2308
+
2309
+ let(:session) do
2310
+ authorized_client.start_session
2311
+ end
2312
+
2313
+ let(:operation) do
2314
+ authorized_collection.replace_one(selector, { name: 'doink' }, session: session)
2315
+ end
2316
+
2317
+ let(:failed_operation) do
2318
+ authorized_collection.replace_one({ '$._id' => 1 }, { name: 'doink' }, session: session)
2319
+ end
2320
+
2321
+ let(:client) do
2322
+ authorized_client
2323
+ end
2324
+
2325
+ it_behaves_like 'an operation using a session'
2326
+ it_behaves_like 'a failed operation using a session'
2327
+ end
2328
+
2329
+ context 'when unacknowledged writes is used with an explicit session' do
2330
+
2331
+ let(:collection_with_unacknowledged_write_concern) do
2332
+ authorized_collection.with(write: { w: 0 })
2333
+ end
2334
+
2335
+ let(:operation) do
2336
+ collection_with_unacknowledged_write_concern.replace_one({ a: 1 }, { x: 5 }, session: session)
2337
+ end
2338
+
2339
+ it_behaves_like 'an explicit session with an unacknowledged write'
2340
+ end
2341
+
2342
+ context 'when unacknowledged writes is used with an implicit session' do
2343
+
2344
+ let(:collection_with_unacknowledged_write_concern) do
2345
+ client.with(write: { w: 0 })[TEST_COLL]
2346
+ end
2347
+
2348
+ let(:operation) do
2349
+ collection_with_unacknowledged_write_concern.replace_one({ a: 1 }, { x: 5 })
2350
+ end
2351
+
2352
+ it_behaves_like 'an implicit session with an unacknowledged write'
2353
+ end
2354
+
2355
+ context 'when various options passed in' do
2356
+ # w: 2 requires a replica set
2357
+ require_topology :replica_set
2358
+
2359
+ # https://jira.mongodb.org/browse/RUBY-2306
2360
+ min_server_fcv '3.6'
2361
+
2362
+ before do
2363
+ authorized_collection.insert_one({field: 'test1'})
2364
+ end
2365
+
2366
+ let(:session) do
2367
+ authorized_client.start_session
2368
+ end
2369
+
2370
+ let(:events) do
2371
+ subscriber.command_started_events('update')
2372
+ end
2373
+
2374
+ let(:collection) do
2375
+ authorized_collection.with(write_concern: {w: 3})
2376
+ end
2377
+
2378
+ let(:updated) do
2379
+ collection.find(field: 'test4').first
2380
+ end
2381
+
2382
+ let!(:command) do
2383
+ Utils.get_command_event(authorized_client, 'update') do |client|
2384
+ collection.replace_one(selector, { field: 'test4'},
2385
+ session: session, :return_document => :after, write_concern: {w: 2},
2386
+ upsert: true, bypass_document_validation: true)
2387
+ end.command
2388
+ end
2389
+
2390
+ it 'replaced one successfully with correct options sent to server' do
2391
+ expect(updated[:field]).to eq('test4')
2392
+ expect(events.length).to eq(1)
2393
+ expect(command[:writeConcern]).to_not be_nil
2394
+ expect(command[:writeConcern][:w]).to eq(2)
2395
+ expect(command[:bypassDocumentValidation]).to be(true)
2396
+ expect(command[:updates][0][:upsert]).to be(true)
2397
+ end
2398
+ end
2399
+ end
2400
+
2401
+ describe '#update_many' do
2402
+
2403
+ let(:selector) do
2404
+ { field: 'test' }
2405
+ end
2406
+
2407
+ context 'when a selector was provided' do
2408
+
2409
+ before do
2410
+ authorized_collection.insert_many([{ field: 'test' }, { field: 'test' }])
2411
+ end
2412
+
2413
+ let!(:response) do
2414
+ authorized_collection.update_many(selector, '$set'=> { field: 'testing' })
2415
+ end
2416
+
2417
+ let(:updated) do
2418
+ authorized_collection.find(field: 'testing').to_a.last
2419
+ end
2420
+
2421
+ it 'returns the number updated' do
2422
+ expect(response.modified_count).to eq(2)
2423
+ end
2424
+
2425
+ it 'updates the documents in the collection' do
2426
+ expect(updated[:field]).to eq('testing')
2427
+ end
2428
+ end
2429
+
2430
+ context 'when upsert is false' do
2431
+
2432
+ let(:response) do
2433
+ authorized_collection.update_many(selector, { '$set'=> { field: 'testing' } },
2434
+ upsert: false)
2435
+ end
2436
+
2437
+ let(:updated) do
2438
+ authorized_collection.find.to_a
2439
+ end
2440
+
2441
+ it 'reports that no documents were updated' do
2442
+ expect(response.modified_count).to eq(0)
2443
+ end
2444
+
2445
+ it 'updates no documents in the collection' do
2446
+ expect(updated).to be_empty
2447
+ end
2448
+ end
2449
+
2450
+ context 'when upsert is true' do
2451
+
2452
+ let!(:response) do
2453
+ authorized_collection.update_many(selector, { '$set'=> { field: 'testing' } },
2454
+ upsert: true)
2455
+ end
2456
+
2457
+ let(:updated) do
2458
+ authorized_collection.find.to_a.last
2459
+ end
2460
+
2461
+ it 'reports that a document was written' do
2462
+ expect(response.written_count).to eq(1)
2463
+ end
2464
+
2465
+ it 'inserts a document into the collection' do
2466
+ expect(updated[:field]).to eq('testing')
2467
+ end
2468
+ end
2469
+
2470
+ context 'when upsert is not specified' do
2471
+
2472
+ let(:response) do
2473
+ authorized_collection.update_many(selector, { '$set'=> { field: 'testing' } })
2474
+ end
2475
+
2476
+ let(:updated) do
2477
+ authorized_collection.find.to_a
2478
+ end
2479
+
2480
+ it 'reports that no documents were updated' do
2481
+ expect(response.modified_count).to eq(0)
2482
+ end
2483
+
2484
+ it 'updates no documents in the collection' do
2485
+ expect(updated).to be_empty
2486
+ end
2487
+ end
2488
+
2489
+ context 'when arrayFilters is provided' do
2490
+
2491
+ let(:selector) do
2492
+ { '$or' => [{ _id: 0 }, { _id: 1 }]}
2493
+ end
2494
+
2495
+ context 'when the server supports arrayFilters' do
2496
+ min_server_fcv '3.6'
2497
+
2498
+ before do
2499
+ authorized_collection.insert_many([{
2500
+ _id: 0, x: [
2501
+ { y: 1 },
2502
+ { y: 2 },
2503
+ { y: 3 }
2504
+ ]
2505
+ },
2506
+ {
2507
+ _id: 1,
2508
+ x: [
2509
+ { y: 3 },
2510
+ { y: 2 },
2511
+ { y: 1 }
2512
+ ]
2513
+ }])
2514
+ end
2515
+
2516
+ let(:result) do
2517
+ authorized_collection.update_many(selector,
2518
+ { '$set' => { 'x.$[i].y' => 5 } },
2519
+ options)
2520
+ end
2521
+
2522
+ context 'when a Symbol key is used' do
2523
+
2524
+ let(:options) do
2525
+ { array_filters: [{ 'i.y' => 3 }] }
2526
+ end
2527
+
2528
+ it 'applies the arrayFilters' do
2529
+ expect(result.matched_count).to eq(2)
2530
+ expect(result.modified_count).to eq(2)
2531
+
2532
+ docs = authorized_collection.find(selector, sort: { _id: 1 }).to_a
2533
+ expect(docs[0]['x']).to eq ([{ 'y' => 1 }, { 'y' => 2 }, { 'y' => 5 }])
2534
+ expect(docs[1]['x']).to eq ([{ 'y' => 5 }, { 'y' => 2 }, { 'y' => 1 }])
2535
+ end
2536
+ end
2537
+
2538
+ context 'when a String key is used' do
2539
+ let(:options) do
2540
+ { 'array_filters' => [{ 'i.y' => 3 }] }
2541
+ end
2542
+
2543
+ it 'applies the arrayFilters' do
2544
+ expect(result.matched_count).to eq(2)
2545
+ expect(result.modified_count).to eq(2)
2546
+
2547
+ docs = authorized_collection.find({}, sort: { _id: 1 }).to_a
2548
+ expect(docs[0]['x']).to eq ([{ 'y' => 1 }, { 'y' => 2 }, { 'y' => 5 }])
2549
+ expect(docs[1]['x']).to eq ([{ 'y' => 5 }, { 'y' => 2 }, { 'y' => 1 }])
2550
+ end
2551
+ end
2552
+ end
2553
+
2554
+ context 'when the server does not support arrayFilters' do
2555
+ max_server_version '3.4'
2556
+
2557
+ let(:result) do
2558
+ authorized_collection.update_many(selector,
2559
+ { '$set' => { 'x.$[i].y' => 5 } },
2560
+ options)
2561
+ end
2562
+
2563
+ context 'when a Symbol key is used' do
2564
+
2565
+ let(:options) do
2566
+ { array_filters: [{ 'i.y' => 3 }] }
2567
+ end
2568
+
2569
+ it 'raises an exception' do
2570
+ expect {
2571
+ result
2572
+ }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
2573
+ end
2574
+ end
2575
+
2576
+ context 'when a String key is used' do
2577
+
2578
+ let(:options) do
2579
+ { 'array_filters' => [{ 'i.y' => 3 }] }
2580
+ end
2581
+
2582
+ it 'raises an exception' do
2583
+ expect {
2584
+ result
2585
+ }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
2586
+ end
2587
+ end
2588
+ end
2589
+ end
2590
+
2591
+ context 'when the updates fail' do
2592
+
2593
+ let(:result) do
2594
+ authorized_collection.update_many(selector, { '$s'=> { field: 'testing' } })
2595
+ end
2596
+
2597
+ it 'raises an OperationFailure' do
2598
+ expect {
2599
+ result
2600
+ }.to raise_exception(Mongo::Error::OperationFailure)
2601
+ end
2602
+ end
2603
+
2604
+ context 'when collection has a validator' do
2605
+ min_server_fcv '3.2'
2606
+
2607
+ around(:each) do |spec|
2608
+ authorized_client[:validating,
2609
+ :validator => { :a => { '$exists' => true } }].tap do |c|
2610
+ c.create
2611
+ end
2612
+ spec.run
2613
+ collection_with_validator.drop
2614
+ end
2615
+
2616
+ before do
2617
+ collection_with_validator.insert_many([{ a: 1 }, { a: 2 }])
2618
+ end
2619
+
2620
+ context 'when the document is valid' do
2621
+
2622
+ let(:result) do
2623
+ collection_with_validator.update_many(
2624
+ { :a => { '$gt' => 0 } }, '$inc' => { :a => 1 } )
2625
+ end
2626
+
2627
+ it 'updates successfully' do
2628
+ expect(result.modified_count).to eq(2)
2629
+ end
2630
+ end
2631
+
2632
+ context 'when the document is invalid' do
2633
+
2634
+ context 'when bypass_document_validation is not set' do
2635
+
2636
+ let(:result2) do
2637
+ collection_with_validator.update_many(
2638
+ { :a => { '$gt' => 0 } }, '$unset' => { :a => '' })
2639
+ end
2640
+
2641
+ it 'raises OperationFailure' do
2642
+ expect {
2643
+ result2
2644
+ }.to raise_exception(Mongo::Error::OperationFailure)
2645
+ end
2646
+ end
2647
+
2648
+ context 'when bypass_document_validation is true' do
2649
+
2650
+ let(:result3) do
2651
+ collection_with_validator.update_many(
2652
+ { :a => { '$gt' => 0 } }, { '$unset' => { :a => '' } },
2653
+ :bypass_document_validation => true)
2654
+ end
2655
+
2656
+ it 'updates successfully' do
2657
+ expect(result3.written_count).to eq(2)
2658
+ end
2659
+ end
2660
+ end
2661
+ end
2662
+
2663
+ context 'when a collation is specified' do
2664
+
2665
+ let(:selector) do
2666
+ { name: 'BANG' }
2667
+ end
2668
+
2669
+ let(:result) do
2670
+ authorized_collection.update_many(selector, { '$set' => { other: 'doink' } }, options)
2671
+ end
2672
+
2673
+ before do
2674
+ authorized_collection.insert_one(name: 'bang')
2675
+ authorized_collection.insert_one(name: 'baNG')
2676
+ end
2677
+
2678
+ let(:options) do
2679
+ { collation: { locale: 'en_US', strength: 2 } }
2680
+ end
2681
+
2682
+ context 'when the server selected supports collations' do
2683
+ min_server_fcv '3.4'
2684
+
2685
+ it 'applies the collation' do
2686
+ expect(result.written_count).to eq(2)
2687
+ expect(authorized_collection.find(other: 'doink').count).to eq(2)
2688
+ end
2689
+
2690
+ context 'when unacknowledged writes is used' do
2691
+
2692
+ let(:collection_with_unacknowledged_write_concern) do
2693
+ authorized_collection.with(write: { w: 0 })
2694
+ end
2695
+
2696
+ let(:result) do
2697
+ collection_with_unacknowledged_write_concern.update_many(selector, { '$set' => { other: 'doink' } }, options)
2698
+ end
2699
+
2700
+ it 'raises an exception' do
2701
+ expect {
2702
+ result
2703
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
2704
+ end
2705
+
2706
+ context 'when a String key is used' do
2707
+
2708
+ let(:options) do
2709
+ { 'collation' => { locale: 'en_US', strength: 2 } }
2710
+ end
2711
+
2712
+ it 'raises an exception' do
2713
+ expect {
2714
+ result
2715
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
2716
+ end
2717
+ end
2718
+ end
2719
+ end
2720
+
2721
+ context 'when the server selected does not support collations' do
2722
+ max_server_version '3.2'
2723
+
2724
+ it 'raises an exception' do
2725
+ expect {
2726
+ result
2727
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
2728
+ end
2729
+
2730
+ context 'when a String key is used' do
2731
+
2732
+ let(:options) do
2733
+ { 'collation' => { locale: 'en_US', strength: 2 } }
2734
+ end
2735
+
2736
+ it 'raises an exception' do
2737
+ expect {
2738
+ result
2739
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
2740
+ end
2741
+ end
2742
+ end
2743
+ end
2744
+
2745
+ context 'when collation is not specified' do
2746
+
2747
+ let(:selector) do
2748
+ {name: 'BANG'}
2749
+ end
2750
+
2751
+ let(:result) do
2752
+ authorized_collection.update_many(selector, { '$set' => {other: 'doink'} })
2753
+ end
2754
+
2755
+ before do
2756
+ authorized_collection.insert_one(name: 'bang')
2757
+ authorized_collection.insert_one(name: 'baNG')
2758
+ end
2759
+
2760
+ it 'does not apply the collation' do
2761
+ expect(result.written_count).to eq(0)
2762
+ end
2763
+ end
2764
+
2765
+ context 'when a session is provided' do
2766
+
2767
+ let(:selector) do
2768
+ { name: 'BANG' }
2769
+ end
2770
+
2771
+ let(:operation) do
2772
+ authorized_collection.update_many(selector, { '$set' => {other: 'doink'} }, session: session)
2773
+ end
2774
+
2775
+ before do
2776
+ authorized_collection.insert_one(name: 'bang')
2777
+ authorized_collection.insert_one(name: 'baNG')
2778
+ end
2779
+
2780
+ let(:session) do
2781
+ authorized_client.start_session
2782
+ end
2783
+
2784
+ let(:failed_operation) do
2785
+ authorized_collection.update_many({ '$._id' => 1 }, { '$set' => {other: 'doink'} }, session: session)
2786
+ end
2787
+
2788
+ let(:client) do
2789
+ authorized_client
2790
+ end
2791
+
2792
+ it_behaves_like 'an operation using a session'
2793
+ it_behaves_like 'a failed operation using a session'
2794
+ end
2795
+
2796
+ context 'when unacknowledged writes is used with an explicit session' do
2797
+
2798
+ let(:collection_with_unacknowledged_write_concern) do
2799
+ authorized_collection.with(write: { w: 0 })
2800
+ end
2801
+
2802
+ let(:operation) do
2803
+ collection_with_unacknowledged_write_concern.update_many({a: 1}, { '$set' => {x: 1} }, session: session)
2804
+ end
2805
+
2806
+ it_behaves_like 'an explicit session with an unacknowledged write'
2807
+ end
2808
+
2809
+ context 'when unacknowledged writes is used with an implicit session' do
2810
+
2811
+ let(:collection_with_unacknowledged_write_concern) do
2812
+ client.with(write: { w: 0 })[TEST_COLL]
2813
+ end
2814
+
2815
+ let(:operation) do
2816
+ collection_with_unacknowledged_write_concern.update_many({a: 1}, {'$set' => {x: 1}})
2817
+ end
2818
+
2819
+ it_behaves_like 'an implicit session with an unacknowledged write'
2820
+ end
2821
+
2822
+ context 'when various options passed in' do
2823
+ # w: 2 requires a replica set
2824
+ require_topology :replica_set
2825
+
2826
+ # https://jira.mongodb.org/browse/RUBY-2306
2827
+ min_server_fcv '3.6'
2828
+
2829
+ before do
2830
+ collection.insert_many([{ field: 'test' }, { field: 'test2' }], session: session)
2831
+ end
2832
+
2833
+ let(:session) do
2834
+ authorized_client.start_session
2835
+ end
2836
+
2837
+ let(:collection) do
2838
+ authorized_collection.with(write_concern: {w: 1})
2839
+ end
2840
+
2841
+ let(:events) do
2842
+ subscriber.command_started_events('update')
2843
+ end
2844
+
2845
+ let!(:command) do
2846
+ Utils.get_command_event(authorized_client, 'update') do |client|
2847
+ collection.update_many(selector, {'$set'=> { field: 'testing' }}, session: session,
2848
+ write_concern: {w: 2}, bypass_document_validation: true, upsert: true)
2849
+ end.command
2850
+ end
2851
+
2852
+ it 'updates many successfully with correct options sent to server' do
2853
+ expect(events.length).to eq(1)
2854
+ expect(collection.options[:write_concern]).to eq(w: 1)
2855
+ expect(command[:writeConcern][:w]).to eq(2)
2856
+ expect(command[:bypassDocumentValidation]).to be(true)
2857
+ expect(command[:updates][0][:upsert]).to be(true)
2858
+ end
2859
+ end
2860
+ end
2861
+
2862
+ describe '#update_one' do
2863
+
2864
+ let(:selector) do
2865
+ { field: 'test1' }
2866
+ end
2867
+
2868
+ context 'when a selector was provided' do
2869
+
2870
+ before do
2871
+ authorized_collection.insert_many([{ field: 'test1' }, { field: 'test1' }])
2872
+ end
2873
+
2874
+ let!(:response) do
2875
+ authorized_collection.update_one(selector, '$set'=> { field: 'testing' })
2876
+ end
2877
+
2878
+ let(:updated) do
2879
+ authorized_collection.find(field: 'testing').first
2880
+ end
2881
+
2882
+ it 'updates the first matching document in the collection' do
2883
+ expect(response.modified_count).to eq(1)
2884
+ end
2885
+
2886
+ it 'updates the documents in the collection' do
2887
+ expect(updated[:field]).to eq('testing')
2888
+ end
2889
+ end
2890
+
2891
+ context 'when upsert is false' do
2892
+
2893
+ let(:response) do
2894
+ authorized_collection.update_one(selector, { '$set'=> { field: 'testing' } },
2895
+ upsert: false)
2896
+ end
2897
+
2898
+ let(:updated) do
2899
+ authorized_collection.find.to_a
2900
+ end
2901
+
2902
+ it 'reports that no documents were updated' do
2903
+ expect(response.modified_count).to eq(0)
2904
+ end
2905
+
2906
+ it 'updates no documents in the collection' do
2907
+ expect(updated).to be_empty
2908
+ end
2909
+ end
2910
+
2911
+ context 'when upsert is true' do
2912
+
2913
+ let!(:response) do
2914
+ authorized_collection.update_one(selector, { '$set'=> { field: 'testing' } },
2915
+ upsert: true)
2916
+ end
2917
+
2918
+ let(:updated) do
2919
+ authorized_collection.find.first
2920
+ end
2921
+
2922
+ it 'reports that a document was written' do
2923
+ expect(response.written_count).to eq(1)
2924
+ end
2925
+
2926
+ it 'inserts a document into the collection' do
2927
+ expect(updated[:field]).to eq('testing')
2928
+ end
2929
+ end
2930
+
2931
+ context 'when upsert is not specified' do
2932
+
2933
+ let(:response) do
2934
+ authorized_collection.update_one(selector, { '$set'=> { field: 'testing' } })
2935
+ end
2936
+
2937
+ let(:updated) do
2938
+ authorized_collection.find.to_a
2939
+ end
2940
+
2941
+ it 'reports that no documents were updated' do
2942
+ expect(response.modified_count).to eq(0)
2943
+ end
2944
+
2945
+ it 'updates no documents in the collection' do
2946
+ expect(updated).to be_empty
2947
+ end
2948
+ end
2949
+
2950
+ context 'when the update fails' do
2951
+
2952
+ let(:result) do
2953
+ authorized_collection.update_one(selector, { '$s'=> { field: 'testing' } })
2954
+ end
2955
+
2956
+ it 'raises an OperationFailure' do
2957
+ expect {
2958
+ result
2959
+ }.to raise_exception(Mongo::Error::OperationFailure)
2960
+ end
2961
+ end
2962
+
2963
+ context 'when collection has a validator' do
2964
+ min_server_fcv '3.2'
2965
+
2966
+ around(:each) do |spec|
2967
+ authorized_client[:validating,
2968
+ :validator => { :a => { '$exists' => true } }].tap do |c|
2969
+ c.create
2970
+ end
2971
+ spec.run
2972
+ collection_with_validator.drop
2973
+ end
2974
+
2975
+ before do
2976
+ collection_with_validator.insert_one({ a: 1 })
2977
+ end
2978
+
2979
+ context 'when the document is valid' do
2980
+
2981
+ let(:result) do
2982
+ collection_with_validator.update_one(
2983
+ { :a => { '$gt' => 0 } }, '$inc' => { :a => 1 } )
2984
+ end
2985
+
2986
+ it 'updates successfully' do
2987
+ expect(result.modified_count).to eq(1)
2988
+ end
2989
+ end
2990
+
2991
+ context 'when the document is invalid' do
2992
+
2993
+ context 'when bypass_document_validation is not set' do
2994
+
2995
+ let(:result2) do
2996
+ collection_with_validator.update_one(
2997
+ { :a => { '$gt' => 0 } }, '$unset' => { :a => '' })
2998
+ end
2999
+
3000
+ it 'raises OperationFailure' do
3001
+ expect {
3002
+ result2
3003
+ }.to raise_exception(Mongo::Error::OperationFailure)
3004
+ end
3005
+ end
3006
+
3007
+ context 'when bypass_document_validation is true' do
3008
+
3009
+ let(:result3) do
3010
+ collection_with_validator.update_one(
3011
+ { :a => { '$gt' => 0 } }, { '$unset' => { :a => '' } },
3012
+ :bypass_document_validation => true)
3013
+ end
3014
+
3015
+ it 'updates successfully' do
3016
+ expect(result3.written_count).to eq(1)
3017
+ end
3018
+ end
3019
+ end
3020
+ end
3021
+
3022
+ context 'when there is a collation specified' do
3023
+
3024
+ let(:selector) do
3025
+ { name: 'BANG' }
3026
+ end
3027
+
3028
+ let(:result) do
3029
+ authorized_collection.update_one(selector, { '$set' => { other: 'doink' } }, options)
3030
+ end
3031
+
3032
+ before do
3033
+ authorized_collection.insert_one(name: 'bang')
3034
+ end
3035
+
3036
+ let(:options) do
3037
+ { collation: { locale: 'en_US', strength: 2 } }
3038
+ end
3039
+
3040
+ context 'when the server selected supports collations' do
3041
+ min_server_fcv '3.4'
3042
+
3043
+ it 'applies the collation' do
3044
+ expect(result.written_count).to eq(1)
3045
+ expect(authorized_collection.find(other: 'doink').count).to eq(1)
3046
+ end
3047
+
3048
+ context 'when unacknowledged writes is used' do
3049
+
3050
+ let(:collection_with_unacknowledged_write_concern) do
3051
+ authorized_collection.with(write: { w: 0 })
3052
+ end
3053
+
3054
+ let(:result) do
3055
+ collection_with_unacknowledged_write_concern.update_one(selector, { '$set' => { other: 'doink' } }, options)
3056
+ end
3057
+
3058
+ it 'raises an exception' do
3059
+ expect {
3060
+ result
3061
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
3062
+ end
3063
+
3064
+ context 'when a String key is used' do
3065
+
3066
+ let(:options) do
3067
+ { 'collation' => { locale: 'en_US', strength: 2 } }
3068
+ end
3069
+
3070
+ it 'raises an exception' do
3071
+ expect {
3072
+ result
3073
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
3074
+ end
3075
+ end
3076
+ end
3077
+ end
3078
+
3079
+ context 'when the server selected does not support collations' do
3080
+ max_server_version '3.2'
3081
+
3082
+ it 'raises an exception' do
3083
+ expect {
3084
+ result
3085
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
3086
+ end
3087
+
3088
+ context 'when a String key is used' do
3089
+
3090
+ let(:options) do
3091
+ { 'collation' => { locale: 'en_US', strength: 2 } }
3092
+ end
3093
+
3094
+ it 'raises an exception' do
3095
+ expect {
3096
+ result
3097
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
3098
+ end
3099
+ end
3100
+ end
3101
+ end
3102
+
3103
+ context 'when a collation is not specified' do
3104
+
3105
+ let(:selector) do
3106
+ { name: 'BANG' }
3107
+ end
3108
+
3109
+ let(:result) do
3110
+ authorized_collection.update_one(selector, { '$set' => { other: 'doink' } })
3111
+ end
3112
+
3113
+ before do
3114
+ authorized_collection.insert_one(name: 'bang')
3115
+ end
3116
+
3117
+ it 'does not apply the collation' do
3118
+ expect(result.written_count).to eq(0)
3119
+ end
3120
+ end
3121
+
3122
+
3123
+ context 'when arrayFilters is provided' do
3124
+
3125
+ let(:selector) do
3126
+ { _id: 0}
3127
+ end
3128
+
3129
+ context 'when the server supports arrayFilters' do
3130
+ min_server_fcv '3.6'
3131
+
3132
+ before do
3133
+ authorized_collection.insert_one(_id: 0, x: [{ y: 1 }, { y: 2 }, {y: 3 }])
3134
+ end
3135
+
3136
+ let(:result) do
3137
+ authorized_collection.update_one(selector,
3138
+ { '$set' => { 'x.$[i].y' => 5 } },
3139
+ options)
3140
+ end
3141
+
3142
+ context 'when a Symbol key is used' do
3143
+
3144
+ let(:options) do
3145
+ { array_filters: [{ 'i.y' => 3 }] }
3146
+ end
3147
+
3148
+ it 'applies the arrayFilters' do
3149
+ expect(result.matched_count).to eq(1)
3150
+ expect(result.modified_count).to eq(1)
3151
+ expect(authorized_collection.find(selector).first['x'].last['y']).to eq(5)
3152
+ end
3153
+ end
3154
+
3155
+ context 'when a String key is used' do
3156
+
3157
+ let(:options) do
3158
+ { 'array_filters' => [{ 'i.y' => 3 }] }
3159
+ end
3160
+
3161
+ it 'applies the arrayFilters' do
3162
+ expect(result.matched_count).to eq(1)
3163
+ expect(result.modified_count).to eq(1)
3164
+ expect(authorized_collection.find(selector).first['x'].last['y']).to eq(5)
3165
+ end
3166
+ end
3167
+ end
3168
+
3169
+ context 'when the server does not support arrayFilters' do
3170
+ max_server_version '3.4'
3171
+
3172
+ let(:result) do
3173
+ authorized_collection.update_one(selector,
3174
+ { '$set' => { 'x.$[i].y' => 5 } },
3175
+ options)
3176
+ end
3177
+
3178
+ context 'when a Symbol key is used' do
3179
+
3180
+ let(:options) do
3181
+ { array_filters: [{ 'i.y' => 3 }] }
3182
+ end
3183
+
3184
+ it 'raises an exception' do
3185
+ expect {
3186
+ result
3187
+ }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
3188
+ end
3189
+ end
3190
+
3191
+ context 'when a String key is used' do
3192
+
3193
+ let(:options) do
3194
+ { 'array_filters' => [{ 'i.y' => 3 }] }
3195
+ end
3196
+
3197
+ it 'raises an exception' do
3198
+ expect {
3199
+ result
3200
+ }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
3201
+ end
3202
+ end
3203
+ end
3204
+ end
3205
+
3206
+ context 'when the documents are sent with OP_MSG' do
3207
+ min_server_fcv '3.6'
3208
+
3209
+ let(:documents) do
3210
+ [{ '_id' => 1, 'name' => '1'*16777191 }, { '_id' => 'y' }]
3211
+ end
3212
+
3213
+ before do
3214
+ authorized_collection.insert_many([{ field: 'test1' }, { field: 'test1' }])
3215
+ client[TEST_COLL].update_one({ a: 1 }, {'$set' => { 'name' => '1'*16777149 }})
3216
+ end
3217
+
3218
+ let(:update_events) do
3219
+ subscriber.started_events.select { |e| e.command_name == 'update' }
3220
+ end
3221
+
3222
+ it 'sends the documents in one OP_MSG' do
3223
+ expect(update_events.size).to eq(1)
3224
+ end
3225
+ end
3226
+
3227
+ context 'when a session is provided' do
3228
+
3229
+ before do
3230
+ authorized_collection.insert_many([{ field: 'test1' }, { field: 'test1' }])
3231
+ end
3232
+
3233
+ let(:session) do
3234
+ authorized_client.start_session
3235
+ end
3236
+
3237
+ let(:operation) do
3238
+ authorized_collection.update_one({ field: 'test' }, { '$set'=> { field: 'testing' } }, session: session)
3239
+ end
3240
+
3241
+ let(:failed_operation) do
3242
+ authorized_collection.update_one({ '$._id' => 1 }, { '$set'=> { field: 'testing' } }, session: session)
3243
+ end
3244
+
3245
+ let(:client) do
3246
+ authorized_client
3247
+ end
3248
+
3249
+ it_behaves_like 'an operation using a session'
3250
+ it_behaves_like 'a failed operation using a session'
3251
+ end
3252
+
3253
+ context 'when unacknowledged writes is used with an explicit session' do
3254
+
3255
+ let(:collection_with_unacknowledged_write_concern) do
3256
+ authorized_collection.with(write: { w: 0 })
3257
+ end
3258
+
3259
+ let(:operation) do
3260
+ collection_with_unacknowledged_write_concern.update_one({ a: 1 }, { '$set' => { x: 1 } }, session: session)
3261
+ end
3262
+
3263
+ it_behaves_like 'an explicit session with an unacknowledged write'
3264
+ end
3265
+
3266
+ context 'when unacknowledged writes is used with an implicit session' do
3267
+
3268
+ let(:collection_with_unacknowledged_write_concern) do
3269
+ client.with(write: { w: 0 })[TEST_COLL]
3270
+ end
3271
+
3272
+ let(:operation) do
3273
+ collection_with_unacknowledged_write_concern.update_one({ a: 1 }, { '$set' => { x: 1 }})
3274
+ end
3275
+
3276
+ it_behaves_like 'an implicit session with an unacknowledged write'
3277
+ end
3278
+
3279
+ context 'when various options passed in' do
3280
+ # w: 2 requires a replica set
3281
+ require_topology :replica_set
3282
+
3283
+ # https://jira.mongodb.org/browse/RUBY-2306
3284
+ min_server_fcv '3.6'
3285
+
3286
+ before do
3287
+ collection.insert_many([{ field: 'test1' }, { field: 'test2' }], session: session)
3288
+ end
3289
+
3290
+ let(:session) do
3291
+ authorized_client.start_session
3292
+ end
3293
+
3294
+ let(:collection) do
3295
+ authorized_collection.with(write_concern: {w: 1})
3296
+ end
3297
+
3298
+ let(:events) do
3299
+ subscriber.command_started_events('update')
3300
+ end
3301
+
3302
+ let!(:command) do
3303
+ Utils.get_command_event(authorized_client, 'update') do |client|
3304
+ collection.update_one(selector, { '$set'=> { field: 'testing' } }, session: session,
3305
+ write_concern: {w: 2}, bypass_document_validation: true, :return_document => :after,
3306
+ upsert: true)
3307
+ end.command
3308
+ end
3309
+
3310
+ it 'updates one successfully with correct options sent to server' do
3311
+ expect(events.length).to eq(1)
3312
+ expect(command[:writeConcern]).to_not be_nil
3313
+ expect(command[:writeConcern][:w]).to eq(2)
3314
+ expect(collection.options[:write_concern]).to eq(w:1)
3315
+ expect(command[:bypassDocumentValidation]).to be(true)
3316
+ expect(command[:updates][0][:upsert]).to be(true)
3317
+ end
3318
+ end
3319
+ end
3320
+
3321
+ describe '#find_one_and_delete' do
3322
+
3323
+ before do
3324
+ authorized_collection.insert_many([{ field: 'test1' }])
3325
+ end
3326
+
3327
+ let(:selector) do
3328
+ { field: 'test1' }
3329
+ end
3330
+
3331
+ context 'when a matching document is found' do
3332
+
3333
+ context 'when a session is provided' do
3334
+
3335
+ let(:operation) do
3336
+ authorized_collection.find_one_and_delete(selector, session: session)
3337
+ end
3338
+
3339
+ let(:failed_operation) do
3340
+ authorized_collection.find_one_and_delete({ '$._id' => 1 }, session: session)
3341
+ end
3342
+
3343
+ let(:session) do
3344
+ authorized_client.start_session
3345
+ end
3346
+
3347
+ let(:client) do
3348
+ authorized_client
3349
+ end
3350
+
3351
+ it_behaves_like 'an operation using a session'
3352
+ it_behaves_like 'a failed operation using a session'
3353
+ end
3354
+
3355
+ context 'when no options are provided' do
3356
+
3357
+ let!(:document) do
3358
+ authorized_collection.find_one_and_delete(selector)
3359
+ end
3360
+
3361
+ it 'deletes the document from the database' do
3362
+ expect(authorized_collection.find.to_a).to be_empty
3363
+ end
3364
+
3365
+ it 'returns the document' do
3366
+ expect(document['field']).to eq('test1')
3367
+ end
3368
+ end
3369
+
3370
+ context 'when a projection is provided' do
3371
+
3372
+ let!(:document) do
3373
+ authorized_collection.find_one_and_delete(selector, projection: { _id: 1 })
3374
+ end
3375
+
3376
+ it 'deletes the document from the database' do
3377
+ expect(authorized_collection.find.to_a).to be_empty
3378
+ end
3379
+
3380
+ it 'returns the document with limited fields' do
3381
+ expect(document['field']).to be_nil
3382
+ expect(document['_id']).to_not be_nil
3383
+ end
3384
+ end
3385
+
3386
+ context 'when a sort is provided' do
3387
+
3388
+ let!(:document) do
3389
+ authorized_collection.find_one_and_delete(selector, sort: { field: 1 })
3390
+ end
3391
+
3392
+ it 'deletes the document from the database' do
3393
+ expect(authorized_collection.find.to_a).to be_empty
3394
+ end
3395
+
3396
+ it 'returns the document with limited fields' do
3397
+ expect(document['field']).to eq('test1')
3398
+ end
3399
+ end
3400
+
3401
+ context 'when max_time_ms is provided' do
3402
+
3403
+ it 'includes the max_time_ms value in the command' do
3404
+ expect {
3405
+ authorized_collection.find_one_and_delete(selector, max_time_ms: 0.1)
3406
+ }.to raise_error(Mongo::Error::OperationFailure)
3407
+ end
3408
+ end
3409
+ end
3410
+
3411
+ context 'when no matching document is found' do
3412
+
3413
+ let(:selector) do
3414
+ { field: 'test5' }
3415
+ end
3416
+
3417
+ let!(:document) do
3418
+ authorized_collection.find_one_and_delete(selector)
3419
+ end
3420
+
3421
+ it 'returns nil' do
3422
+ expect(document).to be_nil
3423
+ end
3424
+ end
3425
+
3426
+ context 'when the operation fails' do
3427
+
3428
+ let(:result) do
3429
+ authorized_collection.find_one_and_delete(selector, max_time_ms: 0.1)
3430
+ end
3431
+
3432
+ it 'raises an OperationFailure' do
3433
+ expect {
3434
+ result
3435
+ }.to raise_exception(Mongo::Error::OperationFailure)
3436
+ end
3437
+ end
3438
+
3439
+ context 'when write_concern is provided' do
3440
+ min_server_fcv '3.2'
3441
+ require_topology :single
3442
+
3443
+ it 'uses the write concern' do
3444
+ expect {
3445
+ authorized_collection.find_one_and_delete(selector,
3446
+ write_concern: { w: 2 })
3447
+ }.to raise_error(Mongo::Error::OperationFailure)
3448
+ end
3449
+ end
3450
+
3451
+ context 'when the collection has a write concern' do
3452
+ min_server_fcv '3.2'
3453
+ require_topology :single
3454
+
3455
+ let(:collection) do
3456
+ authorized_collection.with(write: { w: 2 })
3457
+ end
3458
+
3459
+ it 'uses the write concern' do
3460
+ expect {
3461
+ collection.find_one_and_delete(selector,
3462
+ write_concern: { w: 2 })
3463
+ }.to raise_error(Mongo::Error::OperationFailure)
3464
+ end
3465
+ end
3466
+
3467
+ context 'when collation is specified' do
3468
+
3469
+ let(:selector) do
3470
+ { name: 'BANG' }
3471
+ end
3472
+
3473
+ let(:result) do
3474
+ authorized_collection.find_one_and_delete(selector, options)
3475
+ end
3476
+
3477
+ before do
3478
+ authorized_collection.insert_one(name: 'bang')
3479
+ end
3480
+
3481
+ let(:options) do
3482
+ { collation: { locale: 'en_US', strength: 2 } }
3483
+ end
3484
+
3485
+ context 'when the server selected supports collations' do
3486
+ min_server_fcv '3.4'
3487
+
3488
+ it 'applies the collation' do
3489
+ expect(result['name']).to eq('bang')
3490
+ expect(authorized_collection.find(name: 'bang').count).to eq(0)
3491
+ end
3492
+ end
3493
+
3494
+ context 'when the server selected does not support collations' do
3495
+ max_server_version '3.2'
3496
+
3497
+ it 'raises an exception' do
3498
+ expect {
3499
+ result
3500
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
3501
+ end
3502
+
3503
+ context 'when a String key is used' do
3504
+
3505
+ let(:options) do
3506
+ { 'collation' => { locale: 'en_US', strength: 2 } }
3507
+ end
3508
+
3509
+ it 'raises an exception' do
3510
+ expect {
3511
+ result
3512
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
3513
+ end
3514
+ end
3515
+ end
3516
+ end
3517
+
3518
+ context 'when collation is not specified' do
3519
+
3520
+ let(:selector) do
3521
+ { name: 'BANG' }
3522
+ end
3523
+
3524
+ let(:result) do
3525
+ authorized_collection.find_one_and_delete(selector)
3526
+ end
3527
+
3528
+ before do
3529
+ authorized_collection.insert_one(name: 'bang')
3530
+ end
3531
+
3532
+ it 'does not apply the collation' do
3533
+ expect(result).to be_nil
3534
+ end
3535
+ end
3536
+
3537
+ context 'when various options passed in' do
3538
+ # w: 2 requires a replica set
3539
+ require_topology :replica_set
3540
+
3541
+ # https://jira.mongodb.org/browse/RUBY-2306
3542
+ min_server_fcv '3.6'
3543
+
3544
+ before do
3545
+ authorized_collection.delete_many
3546
+ authorized_collection.insert_many([{ name: 'test1' }, { name: 'test2' }])
3547
+ end
3548
+
3549
+ let(:collection) do
3550
+ authorized_collection.with(write_concern: {w: 2})
3551
+ end
3552
+
3553
+ let(:session) do
3554
+ authorized_client.start_session
3555
+ end
3556
+
3557
+ let!(:command) do
3558
+ Utils.get_command_event(authorized_client, 'findAndModify') do |client|
3559
+ collection.find_one_and_delete(selector, session: session, write_concern: {w: 2},
3560
+ bypass_document_validation: true, max_time_ms: 300)
3561
+ end.command
3562
+ end
3563
+
3564
+ let(:events) do
3565
+ subscriber.command_started_events('findAndModify')
3566
+ end
3567
+
3568
+ it 'finds and deletes successfully with correct options sent to server' do
3569
+ expect(events.length).to eq(1)
3570
+ expect(command[:writeConcern]).to_not be_nil
3571
+ expect(command[:writeConcern][:w]).to eq(2)
3572
+ expect(command[:bypassDocumentValidation]).to eq(true)
3573
+ expect(command[:maxTimeMS]).to eq(300)
3574
+ end
3575
+ end
3576
+ end
3577
+
3578
+ describe '#find_one_and_update' do
3579
+
3580
+ let(:selector) do
3581
+ { field: 'test1' }
3582
+ end
3583
+
3584
+ before do
3585
+ authorized_collection.insert_many([{ field: 'test1' }])
3586
+ end
3587
+
3588
+ context 'when a matching document is found' do
3589
+
3590
+ context 'when no options are provided' do
3591
+
3592
+ let(:document) do
3593
+ authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }})
3594
+ end
3595
+
3596
+ it 'returns the original document' do
3597
+ expect(document['field']).to eq('test1')
3598
+ end
3599
+ end
3600
+
3601
+ context 'when a session is provided' do
3602
+
3603
+ let(:operation) do
3604
+ authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, session: session)
3605
+ end
3606
+
3607
+ let(:failed_operation) do
3608
+ authorized_collection.find_one_and_update({ '$._id' => 1 }, { '$set' => { field: 'testing' }}, session: session)
3609
+ end
3610
+
3611
+ let(:session) do
3612
+ authorized_client.start_session
3613
+ end
3614
+
3615
+ let(:client) do
3616
+ authorized_client
3617
+ end
3618
+
3619
+ it_behaves_like 'an operation using a session'
3620
+ it_behaves_like 'a failed operation using a session'
3621
+ end
3622
+
3623
+ context 'when no options are provided' do
3624
+
3625
+ let(:document) do
3626
+ authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }})
3627
+ end
3628
+
3629
+ it 'returns the original document' do
3630
+ expect(document['field']).to eq('test1')
3631
+ end
3632
+ end
3633
+
3634
+ context 'when return_document options are provided' do
3635
+
3636
+ context 'when return_document is :after' do
3637
+
3638
+ let(:document) do
3639
+ authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, :return_document => :after)
3640
+ end
3641
+
3642
+ it 'returns the new document' do
3643
+ expect(document['field']).to eq('testing')
3644
+ end
3645
+ end
3646
+
3647
+ context 'when return_document is :before' do
3648
+
3649
+ let(:document) do
3650
+ authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, :return_document => :before)
3651
+ end
3652
+
3653
+ it 'returns the original document' do
3654
+ expect(document['field']).to eq('test1')
3655
+ end
3656
+ end
3657
+ end
3658
+
3659
+ context 'when a projection is provided' do
3660
+
3661
+ let(:document) do
3662
+ authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, projection: { _id: 1 })
3663
+ end
3664
+
3665
+ it 'returns the document with limited fields' do
3666
+ expect(document['field']).to be_nil
3667
+ expect(document['_id']).to_not be_nil
3668
+ end
3669
+ end
3670
+
3671
+ context 'when a sort is provided' do
3672
+
3673
+ let(:document) do
3674
+ authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, sort: { field: 1 })
3675
+ end
3676
+
3677
+ it 'returns the original document' do
3678
+ expect(document['field']).to eq('test1')
3679
+ end
3680
+ end
3681
+ end
3682
+
3683
+ context 'when max_time_ms is provided' do
3684
+
3685
+ it 'includes the max_time_ms value in the command' do
3686
+ expect {
3687
+ authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, max_time_ms: 0.1)
3688
+ }.to raise_error(Mongo::Error::OperationFailure)
3689
+ end
3690
+ end
3691
+
3692
+ context 'when no matching document is found' do
3693
+
3694
+ let(:selector) do
3695
+ { field: 'test5' }
3696
+ end
3697
+
3698
+ let(:document) do
3699
+ authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }})
3700
+ end
3701
+
3702
+ it 'returns nil' do
3703
+ expect(document).to be_nil
3704
+ end
3705
+ end
3706
+
3707
+ context 'when no matching document is found' do
3708
+
3709
+ context 'when no upsert options are provided' do
3710
+
3711
+ let(:selector) do
3712
+ { field: 'test5' }
3713
+ end
3714
+
3715
+ let(:document) do
3716
+ authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }})
3717
+ end
3718
+
3719
+ it 'returns nil' do
3720
+ expect(document).to be_nil
3721
+ end
3722
+ end
3723
+
3724
+ context 'when upsert options are provided' do
3725
+
3726
+ let(:selector) do
3727
+ { field: 'test5' }
3728
+ end
3729
+
3730
+ let(:document) do
3731
+ authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, :upsert => true, :return_document => :after)
3732
+ end
3733
+
3734
+ it 'returns the new document' do
3735
+ expect(document['field']).to eq('testing')
3736
+ end
3737
+ end
3738
+ end
3739
+
3740
+ context 'when the operation fails' do
3741
+
3742
+ let(:result) do
3743
+ authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, max_time_ms: 0.1)
3744
+ end
3745
+
3746
+ it 'raises an OperationFailure' do
3747
+ expect {
3748
+ result
3749
+ }.to raise_exception(Mongo::Error::OperationFailure)
3750
+ end
3751
+ end
3752
+
3753
+ context 'when collection has a validator' do
3754
+ min_server_fcv '3.2'
3755
+
3756
+ around(:each) do |spec|
3757
+ authorized_client[:validating].drop
3758
+ authorized_client[:validating,
3759
+ :validator => { :a => { '$exists' => true } }].tap do |c|
3760
+ c.create
3761
+ end
3762
+ spec.run
3763
+ collection_with_validator.drop
3764
+ end
3765
+
3766
+ before do
3767
+ collection_with_validator.insert_one({ a: 1 })
3768
+ end
3769
+
3770
+ context 'when the document is valid' do
3771
+
3772
+ let(:result) do
3773
+ collection_with_validator.find_one_and_update(
3774
+ { a: 1 }, { '$inc' => { :a => 1 } }, :return_document => :after)
3775
+ end
3776
+
3777
+ it 'updates successfully' do
3778
+ expect(result['a']).to eq(2)
3779
+ end
3780
+ end
3781
+
3782
+ context 'when the document is invalid' do
3783
+
3784
+ context 'when bypass_document_validation is not set' do
3785
+
3786
+ let(:result2) do
3787
+ collection_with_validator.find_one_and_update(
3788
+ { a: 1 }, { '$unset' => { :a => '' } }, :return_document => :after)
3789
+ end
3790
+
3791
+ it 'raises OperationFailure' do
3792
+ expect {
3793
+ result2
3794
+ }.to raise_exception(Mongo::Error::OperationFailure)
3795
+ end
3796
+ end
3797
+
3798
+ context 'when bypass_document_validation is true' do
3799
+
3800
+ let(:result3) do
3801
+ collection_with_validator.find_one_and_update(
3802
+ { a: 1 }, { '$unset' => { :a => '' } },
3803
+ :bypass_document_validation => true,
3804
+ :return_document => :after)
3805
+ end
3806
+
3807
+ it 'updates successfully' do
3808
+ expect(result3['a']).to be_nil
3809
+ end
3810
+ end
3811
+ end
3812
+ end
3813
+
3814
+ context 'when write_concern is provided' do
3815
+ min_server_fcv '3.2'
3816
+ require_topology :single
3817
+
3818
+ it 'uses the write concern' do
3819
+ expect {
3820
+ authorized_collection.find_one_and_update(selector,
3821
+ { '$set' => { field: 'testing' }},
3822
+ write_concern: { w: 2 })
3823
+ }.to raise_error(Mongo::Error::OperationFailure)
3824
+ end
3825
+ end
3826
+
3827
+ context 'when the collection has a write concern' do
3828
+ min_server_fcv '3.2'
3829
+ require_topology :single
3830
+
3831
+ let(:collection) do
3832
+ authorized_collection.with(write: { w: 2 })
3833
+ end
3834
+
3835
+ it 'uses the write concern' do
3836
+ expect {
3837
+ collection.find_one_and_update(selector,
3838
+ { '$set' => { field: 'testing' }},
3839
+ write_concern: { w: 2 })
3840
+ }.to raise_error(Mongo::Error::OperationFailure)
3841
+ end
3842
+ end
3843
+
3844
+ context 'when a collation is specified' do
3845
+
3846
+ let(:selector) do
3847
+ { name: 'BANG' }
3848
+ end
3849
+
3850
+ let(:result) do
3851
+ authorized_collection.find_one_and_update(selector,
3852
+ { '$set' => { other: 'doink' } },
3853
+ options)
3854
+ end
3855
+
3856
+ before do
3857
+ authorized_collection.insert_one(name: 'bang')
3858
+ end
3859
+
3860
+ let(:options) do
3861
+ { collation: { locale: 'en_US', strength: 2 } }
3862
+ end
3863
+
3864
+ context 'when the server selected supports collations' do
3865
+ min_server_fcv '3.4'
3866
+
3867
+ it 'applies the collation' do
3868
+ expect(result['name']).to eq('bang')
3869
+ expect(authorized_collection.find({ name: 'bang' }, limit: -1).first['other']).to eq('doink')
3870
+ end
3871
+ end
3872
+
3873
+ context 'when the server selected does not support collations' do
3874
+ max_server_version '3.2'
3875
+
3876
+ it 'raises an exception' do
3877
+ expect {
3878
+ result
3879
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
3880
+ end
3881
+
3882
+ context 'when a String key is used' do
3883
+
3884
+ let(:options) do
3885
+ { 'collation' => { locale: 'en_US', strength: 2 } }
3886
+ end
3887
+
3888
+ it 'raises an exception' do
3889
+ expect {
3890
+ result
3891
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
3892
+ end
3893
+ end
3894
+ end
3895
+ end
3896
+
3897
+ context 'when there is no collation specified' do
3898
+
3899
+ let(:selector) do
3900
+ { name: 'BANG' }
3901
+ end
3902
+
3903
+ let(:result) do
3904
+ authorized_collection.find_one_and_update(selector, { '$set' => { other: 'doink' } })
3905
+ end
3906
+
3907
+ before do
3908
+ authorized_collection.insert_one(name: 'bang')
3909
+ end
3910
+
3911
+ it 'does not apply the collation' do
3912
+ expect(result).to be_nil
3913
+ end
3914
+ end
3915
+
3916
+ context 'when arrayFilters is provided' do
3917
+
3918
+ let(:selector) do
3919
+ { _id: 0 }
3920
+ end
3921
+
3922
+ context 'when the server supports arrayFilters' do
3923
+ min_server_fcv '3.6'
3924
+
3925
+ before do
3926
+ authorized_collection.insert_one(_id: 0, x: [{ y: 1 }, { y: 2 }, { y: 3 }])
3927
+ end
3928
+
3929
+ let(:result) do
3930
+ authorized_collection.find_one_and_update(selector,
3931
+ { '$set' => { 'x.$[i].y' => 5 } },
3932
+ options)
3933
+ end
3934
+
3935
+ context 'when a Symbol key is used' do
3936
+
3937
+ let(:options) do
3938
+ { array_filters: [{ 'i.y' => 3 }] }
3939
+ end
3940
+
3941
+
3942
+ it 'applies the arrayFilters' do
3943
+ expect(result['x']).to eq([{ 'y' => 1 }, { 'y' => 2 }, { 'y' => 3 }])
3944
+ expect(authorized_collection.find(selector).first['x'].last['y']).to eq(5)
3945
+ end
3946
+ end
3947
+
3948
+ context 'when a String key is used' do
3949
+
3950
+ let(:options) do
3951
+ { 'array_filters' => [{ 'i.y' => 3 }] }
3952
+ end
3953
+
3954
+ it 'applies the arrayFilters' do
3955
+ expect(result['x']).to eq([{ 'y' => 1 }, { 'y' => 2 }, { 'y' => 3 }])
3956
+ expect(authorized_collection.find(selector).first['x'].last['y']).to eq(5)
3957
+ end
3958
+ end
3959
+ end
3960
+
3961
+ context 'when the server selected does not support arrayFilters' do
3962
+ max_server_version '3.4'
3963
+
3964
+ let(:result) do
3965
+ authorized_collection.find_one_and_update(selector,
3966
+ { '$set' => { 'x.$[i].y' => 5 } },
3967
+ options)
3968
+ end
3969
+
3970
+ context 'when a Symbol key is used' do
3971
+
3972
+ let(:options) do
3973
+ { array_filters: [{ 'i.y' => 3 }] }
3974
+ end
3975
+
3976
+ it 'raises an exception' do
3977
+ expect {
3978
+ result
3979
+ }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
3980
+ end
3981
+ end
3982
+
3983
+ context 'when a String key is used' do
3984
+
3985
+ let(:options) do
3986
+ { 'array_filters' => [{ 'i.y' => 3 }] }
3987
+ end
3988
+
3989
+ it 'raises an exception' do
3990
+ expect {
3991
+ result
3992
+ }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
3993
+ end
3994
+ end
3995
+ end
3996
+ end
3997
+
3998
+ context 'when various options passed in' do
3999
+ # w: 2 requires a replica set
4000
+ require_topology :replica_set
4001
+
4002
+ # https://jira.mongodb.org/browse/RUBY-2306
4003
+ min_server_fcv '3.6'
4004
+
4005
+ let(:session) do
4006
+ authorized_client.start_session
4007
+ end
4008
+
4009
+ let(:events) do
4010
+ subscriber.command_started_events('findAndModify')
4011
+ end
4012
+
4013
+ let(:collection) do
4014
+ authorized_collection.with(write_concern: {w: 2})
4015
+ end
4016
+
4017
+ let(:selector) do
4018
+ {field: 'test1'}
4019
+ end
4020
+
4021
+ before do
4022
+ collection.insert_one({field: 'test1'}, session: session)
4023
+ end
4024
+
4025
+ let!(:command) do
4026
+ Utils.get_command_event(authorized_client, 'findAndModify') do |client|
4027
+ collection.find_one_and_update(selector, { '$set' => {field: 'testing'}},
4028
+ :return_document => :after, write_concern: {w: 1}, upsert: true,
4029
+ bypass_document_validation: true, max_time_ms: 100, session: session)
4030
+ end.command
4031
+ end
4032
+
4033
+ it 'find and updates successfully with correct options sent to server' do
4034
+ expect(events.length).to eq(1)
4035
+ expect(command[:writeConcern]).to_not be_nil
4036
+ expect(command[:writeConcern][:w]).to eq(1)
4037
+ expect(command[:upsert]).to eq(true)
4038
+ expect(command[:bypassDocumentValidation]).to be(true)
4039
+ expect(command[:maxTimeMS]).to eq(100)
4040
+ end
4041
+ end
4042
+ end
4043
+
4044
+ describe '#find_one_and_replace' do
4045
+
4046
+ before do
4047
+ authorized_collection.insert_many([{ field: 'test1', other: 'sth' }])
4048
+ end
4049
+
4050
+ let(:selector) do
4051
+ { field: 'test1' }
4052
+ end
4053
+
4054
+ context 'when a matching document is found' do
4055
+
4056
+ context 'when no options are provided' do
4057
+
4058
+ let(:document) do
4059
+ authorized_collection.find_one_and_replace(selector, { field: 'testing' })
4060
+ end
4061
+
4062
+ it 'returns the original document' do
4063
+ expect(document['field']).to eq('test1')
4064
+ end
4065
+ end
4066
+
4067
+ context 'when a session is provided' do
4068
+
4069
+ let(:operation) do
4070
+ authorized_collection.find_one_and_replace(selector, { field: 'testing' }, session: session)
4071
+ end
4072
+
4073
+ let(:failed_operation) do
4074
+ authorized_collection.find_one_and_replace({ '$._id' => 1}, { field: 'testing' }, session: session)
4075
+ end
4076
+
4077
+ let(:session) do
4078
+ authorized_client.start_session
4079
+ end
4080
+
4081
+ let(:client) do
4082
+ authorized_client
4083
+ end
4084
+
4085
+ it_behaves_like 'an operation using a session'
4086
+ it_behaves_like 'a failed operation using a session'
4087
+ end
4088
+
4089
+ context 'when return_document options are provided' do
4090
+
4091
+ context 'when return_document is :after' do
4092
+
4093
+ let(:document) do
4094
+ authorized_collection.find_one_and_replace(selector, { field: 'testing' }, :return_document => :after)
4095
+ end
4096
+
4097
+ it 'returns the new document' do
4098
+ expect(document['field']).to eq('testing')
4099
+ end
4100
+ end
4101
+
4102
+ context 'when return_document is :before' do
4103
+
4104
+ let(:document) do
4105
+ authorized_collection.find_one_and_replace(selector, { field: 'testing' }, :return_document => :before)
4106
+ end
4107
+
4108
+ it 'returns the original document' do
4109
+ expect(document['field']).to eq('test1')
4110
+ end
4111
+ end
4112
+ end
4113
+
4114
+ context 'when a projection is provided' do
4115
+
4116
+ let(:document) do
4117
+ authorized_collection.find_one_and_replace(selector, { field: 'testing' }, projection: { _id: 1 })
4118
+ end
4119
+
4120
+ it 'returns the document with limited fields' do
4121
+ expect(document['field']).to be_nil
4122
+ expect(document['_id']).to_not be_nil
4123
+ end
4124
+ end
4125
+
4126
+ context 'when a sort is provided' do
4127
+
4128
+ let(:document) do
4129
+ authorized_collection.find_one_and_replace(selector, { field: 'testing' }, :sort => { field: 1 })
4130
+ end
4131
+
4132
+ it 'returns the original document' do
4133
+ expect(document['field']).to eq('test1')
4134
+ end
4135
+ end
4136
+ end
4137
+
4138
+ context 'when no matching document is found' do
4139
+
4140
+ context 'when no upsert options are provided' do
4141
+
4142
+ let(:selector) do
4143
+ { field: 'test5' }
4144
+ end
4145
+
4146
+ let(:document) do
4147
+ authorized_collection.find_one_and_replace(selector, { field: 'testing' })
4148
+ end
4149
+
4150
+ it 'returns nil' do
4151
+ expect(document).to be_nil
4152
+ end
4153
+ end
4154
+
4155
+ context 'when upsert options are provided' do
4156
+
4157
+ let(:selector) do
4158
+ { field: 'test5' }
4159
+ end
4160
+
4161
+ let(:document) do
4162
+ authorized_collection.find_one_and_replace(selector, { field: 'testing' }, :upsert => true, :return_document => :after)
4163
+ end
4164
+
4165
+ it 'returns the new document' do
4166
+ expect(document['field']).to eq('testing')
4167
+ end
4168
+ end
4169
+ end
4170
+
4171
+ context 'when max_time_ms is provided' do
4172
+
4173
+ it 'includes the max_time_ms value in the command' do
4174
+ expect {
4175
+ authorized_collection.find_one_and_replace(selector, { field: 'testing' }, max_time_ms: 0.1)
4176
+ }.to raise_error(Mongo::Error::OperationFailure)
4177
+ end
4178
+ end
4179
+
4180
+ context 'when the operation fails' do
4181
+
4182
+ let(:result) do
4183
+ authorized_collection.find_one_and_replace(selector, { field: 'testing' }, max_time_ms: 0.1)
4184
+ end
4185
+
4186
+ it 'raises an OperationFailure' do
4187
+ expect {
4188
+ result
4189
+ }.to raise_exception(Mongo::Error::OperationFailure)
4190
+ end
4191
+ end
4192
+
4193
+ context 'when collection has a validator' do
4194
+ min_server_fcv '3.2'
4195
+
4196
+ around(:each) do |spec|
4197
+ authorized_client[:validating].drop
4198
+ authorized_client[:validating,
4199
+ :validator => { :a => { '$exists' => true } }].tap do |c|
4200
+ c.create
4201
+ end
4202
+ spec.run
4203
+ collection_with_validator.drop
4204
+ end
4205
+
4206
+ before do
4207
+ collection_with_validator.insert_one({ a: 1 })
4208
+ end
4209
+
4210
+ context 'when the document is valid' do
4211
+
4212
+ let(:result) do
4213
+ collection_with_validator.find_one_and_replace(
4214
+ { a: 1 }, { a: 5 }, :return_document => :after)
4215
+ end
4216
+
4217
+ it 'replaces successfully when document is valid' do
4218
+ expect(result[:a]).to eq(5)
4219
+ end
4220
+ end
4221
+
4222
+ context 'when the document is invalid' do
4223
+
4224
+ context 'when bypass_document_validation is not set' do
4225
+
4226
+ let(:result2) do
4227
+ collection_with_validator.find_one_and_replace(
4228
+ { a: 1 }, { x: 5 }, :return_document => :after)
4229
+ end
4230
+
4231
+ it 'raises OperationFailure' do
4232
+ expect {
4233
+ result2
4234
+ }.to raise_exception(Mongo::Error::OperationFailure)
4235
+ end
4236
+ end
4237
+
4238
+ context 'when bypass_document_validation is true' do
4239
+
4240
+ let(:result3) do
4241
+ collection_with_validator.find_one_and_replace(
4242
+ { a: 1 }, { x: 1 }, :bypass_document_validation => true,
4243
+ :return_document => :after)
4244
+ end
4245
+
4246
+ it 'replaces successfully' do
4247
+ expect(result3[:x]).to eq(1)
4248
+ expect(result3[:a]).to be_nil
4249
+ end
4250
+ end
4251
+ end
4252
+ end
4253
+
4254
+ context 'when write_concern is provided' do
4255
+ min_server_fcv '3.2'
4256
+ require_topology :single
4257
+
4258
+ it 'uses the write concern' do
4259
+ expect {
4260
+ authorized_collection.find_one_and_replace(selector,
4261
+ { field: 'testing' },
4262
+ write_concern: { w: 2 })
4263
+ }.to raise_error(Mongo::Error::OperationFailure)
4264
+ end
4265
+ end
4266
+
4267
+ context 'when the collection has a write concern' do
4268
+ min_server_fcv '3.2'
4269
+ require_topology :single
4270
+
4271
+ let(:collection) do
4272
+ authorized_collection.with(write: { w: 2 })
4273
+ end
4274
+
4275
+ it 'uses the write concern' do
4276
+ expect {
4277
+ collection.find_one_and_replace(selector,
4278
+ { field: 'testing' },
4279
+ write_concern: { w: 2 })
4280
+ }.to raise_error(Mongo::Error::OperationFailure)
4281
+ end
4282
+ end
4283
+
4284
+ context 'when collation is provided' do
4285
+
4286
+ let(:selector) do
4287
+ { name: 'BANG' }
4288
+ end
4289
+
4290
+ let(:result) do
4291
+ authorized_collection.find_one_and_replace(selector,
4292
+ { name: 'doink' },
4293
+ options)
4294
+ end
4295
+
4296
+ before do
4297
+ authorized_collection.insert_one(name: 'bang')
4298
+ end
4299
+
4300
+ let(:options) do
4301
+ { collation: { locale: 'en_US', strength: 2 } }
4302
+ end
4303
+
4304
+ context 'when the server selected supports collations' do
4305
+ min_server_fcv '3.4'
4306
+
4307
+ it 'applies the collation' do
4308
+ expect(result['name']).to eq('bang')
4309
+ expect(authorized_collection.find(name: 'doink').count).to eq(1)
4310
+ end
4311
+ end
4312
+
4313
+ context 'when the server selected does not support collations' do
4314
+ max_server_version '3.2'
4315
+
4316
+ it 'raises an exception' do
4317
+ expect {
4318
+ result
4319
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
4320
+ end
4321
+
4322
+ context 'when a String key is used' do
4323
+
4324
+ let(:options) do
4325
+ { 'collation' => { locale: 'en_US', strength: 2 } }
4326
+ end
4327
+
4328
+ it 'raises an exception' do
4329
+ expect {
4330
+ result
4331
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
4332
+ end
4333
+ end
4334
+ end
4335
+ end
4336
+
4337
+ context 'when collation is not specified' do
4338
+
4339
+ let(:selector) do
4340
+ { name: 'BANG' }
4341
+ end
4342
+
4343
+ let(:result) do
4344
+ authorized_collection.find_one_and_replace(selector, { name: 'doink' })
4345
+ end
4346
+
4347
+ before do
4348
+ authorized_collection.insert_one(name: 'bang')
4349
+ end
4350
+
4351
+ it 'does not apply the collation' do
4352
+ expect(result).to be_nil
4353
+ end
4354
+ end
4355
+
4356
+ context 'when various options passed in' do
4357
+ # https://jira.mongodb.org/browse/RUBY-2306
4358
+ min_server_fcv '3.6'
4359
+
4360
+ before do
4361
+ authorized_collection.insert_one({field: 'test1'})
4362
+ end
4363
+
4364
+ let(:session) do
4365
+ authorized_client.start_session
4366
+ end
4367
+
4368
+ let(:events) do
4369
+ subscriber.command_started_events('findAndModify')
4370
+ end
4371
+
4372
+ let(:collection) do
4373
+ authorized_collection.with(write_concern: { w: 2 })
4374
+ end
4375
+
4376
+ let!(:command) do
4377
+ Utils.get_command_event(authorized_client, 'findAndModify') do |client|
4378
+ collection.find_one_and_replace(selector, { '$set' => {field: 'test5'}},
4379
+ :return_document => :after, write_concern: {w: 1}, session: session,
4380
+ upsert: true, bypass_document_validation: false, max_time_ms: 200)
4381
+ end.command
4382
+ end
4383
+
4384
+ it 'find and replaces successfully with correct options sent to server' do
4385
+ expect(events.length).to eq(1)
4386
+ expect(command[:writeConcern]).to_not be_nil
4387
+ expect(command[:writeConcern][:w]).to eq(1)
4388
+ expect(command[:upsert]).to be(true)
4389
+ expect(command[:bypassDocumentValidation]).to be false
4390
+ expect(command[:maxTimeMS]).to eq(200)
4391
+ end
4392
+ end
4393
+ end
4394
+
4395
+ context 'when unacknowledged writes is used on find_one_and_update' do
4396
+
4397
+ let(:selector) do
4398
+ { name: 'BANG' }
4399
+ end
4400
+
4401
+ let(:collection_with_unacknowledged_write_concern) do
4402
+ authorized_collection.with(write: { w: 0 })
4403
+ end
4404
+
4405
+ let(:result) do
4406
+ collection_with_unacknowledged_write_concern.find_one_and_update(selector,
4407
+ { '$set' => { field: 'testing' }},
4408
+ write_concern: { w: 0 })
4409
+ end
4410
+
4411
+ it 'does not raise an exception' do
4412
+ expect(result).to be_nil
4413
+ end
4414
+ end
4415
+ end