mongo 2.13.0 → 2.15.0.alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (375) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +1 -4
  3. data.tar.gz.sig +0 -0
  4. data/README.md +4 -1
  5. data/Rakefile +46 -18
  6. data/lib/mongo.rb +32 -0
  7. data/lib/mongo/address.rb +1 -1
  8. data/lib/mongo/address/ipv4.rb +1 -1
  9. data/lib/mongo/address/ipv6.rb +1 -1
  10. data/lib/mongo/auth/aws/conversation.rb +1 -4
  11. data/lib/mongo/auth/base.rb +13 -7
  12. data/lib/mongo/auth/conversation_base.rb +32 -0
  13. data/lib/mongo/auth/cr/conversation.rb +6 -29
  14. data/lib/mongo/auth/gssapi/conversation.rb +4 -15
  15. data/lib/mongo/auth/ldap/conversation.rb +3 -14
  16. data/lib/mongo/auth/sasl_conversation_base.rb +1 -13
  17. data/lib/mongo/auth/scram_conversation_base.rb +7 -34
  18. data/lib/mongo/auth/user/view.rb +16 -9
  19. data/lib/mongo/auth/x509/conversation.rb +4 -25
  20. data/lib/mongo/background_thread.rb +11 -0
  21. data/lib/mongo/bulk_write.rb +38 -18
  22. data/lib/mongo/caching_cursor.rb +74 -0
  23. data/lib/mongo/client.rb +142 -16
  24. data/lib/mongo/cluster.rb +22 -31
  25. data/lib/mongo/cluster/reapers/cursor_reaper.rb +6 -2
  26. data/lib/mongo/cluster/sdam_flow.rb +14 -0
  27. data/lib/mongo/cluster/topology/single.rb +1 -1
  28. data/lib/mongo/collection.rb +58 -18
  29. data/lib/mongo/collection/view.rb +24 -20
  30. data/lib/mongo/collection/view/aggregation.rb +26 -5
  31. data/lib/mongo/collection/view/builder/find_command.rb +38 -18
  32. data/lib/mongo/collection/view/change_stream.rb +1 -1
  33. data/lib/mongo/collection/view/explainable.rb +27 -8
  34. data/lib/mongo/collection/view/iterable.rb +73 -13
  35. data/lib/mongo/collection/view/map_reduce.rb +2 -2
  36. data/lib/mongo/collection/view/readable.rb +57 -21
  37. data/lib/mongo/collection/view/writable.rb +29 -15
  38. data/lib/mongo/crypt/encryption_io.rb +6 -6
  39. data/lib/mongo/cursor.rb +18 -5
  40. data/lib/mongo/database.rb +28 -5
  41. data/lib/mongo/database/view.rb +2 -2
  42. data/lib/mongo/error.rb +11 -1
  43. data/lib/mongo/error/bulk_write_error.rb +17 -3
  44. data/lib/mongo/error/internal_driver_error.rb +22 -0
  45. data/lib/mongo/error/invalid_read_concern.rb +28 -0
  46. data/lib/mongo/error/operation_failure.rb +26 -7
  47. data/lib/mongo/error/parser.rb +65 -12
  48. data/lib/mongo/error/server_api_conflict.rb +23 -0
  49. data/lib/mongo/error/server_api_not_supported.rb +24 -0
  50. data/lib/mongo/error/server_certificate_revoked.rb +22 -0
  51. data/lib/mongo/error/unmet_dependency.rb +21 -0
  52. data/lib/mongo/error/unsupported_option.rb +14 -12
  53. data/lib/mongo/grid/fs_bucket.rb +37 -37
  54. data/lib/mongo/index/view.rb +21 -11
  55. data/lib/mongo/lint.rb +2 -1
  56. data/lib/mongo/logger.rb +3 -3
  57. data/lib/mongo/monitoring.rb +13 -4
  58. data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +27 -16
  59. data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +26 -15
  60. data/lib/mongo/operation.rb +4 -2
  61. data/lib/mongo/operation/aggregate/result.rb +9 -8
  62. data/lib/mongo/operation/collections_info.rb +18 -1
  63. data/lib/mongo/operation/collections_info/command.rb +5 -0
  64. data/lib/mongo/operation/collections_info/result.rb +18 -1
  65. data/lib/mongo/operation/context.rb +99 -0
  66. data/lib/mongo/operation/delete/bulk_result.rb +2 -0
  67. data/lib/mongo/operation/delete/result.rb +3 -0
  68. data/lib/mongo/operation/explain/command.rb +4 -0
  69. data/lib/mongo/operation/explain/legacy.rb +4 -0
  70. data/lib/mongo/operation/explain/op_msg.rb +6 -0
  71. data/lib/mongo/operation/explain/result.rb +3 -0
  72. data/lib/mongo/operation/find/legacy/result.rb +2 -0
  73. data/lib/mongo/operation/find/result.rb +13 -0
  74. data/lib/mongo/operation/get_more/result.rb +3 -0
  75. data/lib/mongo/operation/indexes.rb +15 -1
  76. data/lib/mongo/operation/indexes/result.rb +5 -0
  77. data/lib/mongo/operation/insert/bulk_result.rb +5 -0
  78. data/lib/mongo/operation/insert/command.rb +2 -2
  79. data/lib/mongo/operation/insert/legacy.rb +2 -2
  80. data/lib/mongo/operation/insert/op_msg.rb +2 -2
  81. data/lib/mongo/operation/insert/result.rb +5 -0
  82. data/lib/mongo/operation/list_collections/result.rb +9 -1
  83. data/lib/mongo/operation/map_reduce/result.rb +10 -0
  84. data/lib/mongo/operation/parallel_scan/result.rb +4 -0
  85. data/lib/mongo/operation/result.rb +37 -6
  86. data/lib/mongo/operation/shared/bypass_document_validation.rb +1 -0
  87. data/lib/mongo/operation/shared/causal_consistency_supported.rb +1 -0
  88. data/lib/mongo/operation/shared/executable.rb +25 -14
  89. data/lib/mongo/operation/shared/executable_no_validate.rb +2 -2
  90. data/lib/mongo/operation/shared/idable.rb +2 -1
  91. data/lib/mongo/operation/shared/limited.rb +1 -0
  92. data/lib/mongo/operation/shared/object_id_generator.rb +1 -0
  93. data/lib/mongo/operation/shared/op_msg_or_command.rb +1 -7
  94. data/lib/mongo/operation/shared/op_msg_or_find_command.rb +1 -7
  95. data/lib/mongo/operation/shared/polymorphic_operation.rb +39 -0
  96. data/lib/mongo/operation/shared/response_handling.rb +23 -23
  97. data/lib/mongo/operation/shared/result/aggregatable.rb +1 -0
  98. data/lib/mongo/operation/shared/sessions_supported.rb +14 -2
  99. data/lib/mongo/operation/shared/specifiable.rb +1 -0
  100. data/lib/mongo/operation/shared/write.rb +9 -18
  101. data/lib/mongo/operation/shared/write_concern_supported.rb +1 -0
  102. data/lib/mongo/operation/update/legacy/result.rb +7 -0
  103. data/lib/mongo/operation/update/result.rb +8 -0
  104. data/lib/mongo/operation/users_info/result.rb +3 -0
  105. data/lib/mongo/protocol/compressed.rb +51 -5
  106. data/lib/mongo/protocol/message.rb +31 -4
  107. data/lib/mongo/protocol/msg.rb +37 -12
  108. data/lib/mongo/protocol/query.rb +36 -0
  109. data/lib/mongo/query_cache.rb +272 -0
  110. data/lib/mongo/retryable.rb +9 -2
  111. data/lib/mongo/server.rb +12 -16
  112. data/lib/mongo/server/app_metadata.rb +52 -18
  113. data/lib/mongo/server/connection.rb +5 -0
  114. data/lib/mongo/server/connection_base.rb +16 -15
  115. data/lib/mongo/server/connection_common.rb +2 -2
  116. data/lib/mongo/server/connection_pool.rb +9 -4
  117. data/lib/mongo/server/description.rb +12 -1
  118. data/lib/mongo/server/description/features.rb +9 -8
  119. data/lib/mongo/server/monitor.rb +21 -2
  120. data/lib/mongo/server/monitor/app_metadata.rb +1 -1
  121. data/lib/mongo/server/monitor/connection.rb +12 -13
  122. data/lib/mongo/server/pending_connection.rb +26 -8
  123. data/lib/mongo/server/push_monitor.rb +12 -2
  124. data/lib/mongo/server_selector/base.rb +5 -1
  125. data/lib/mongo/session.rb +7 -3
  126. data/lib/mongo/session/session_pool.rb +4 -2
  127. data/lib/mongo/socket.rb +35 -8
  128. data/lib/mongo/socket/ocsp_cache.rb +97 -0
  129. data/lib/mongo/socket/ocsp_verifier.rb +368 -0
  130. data/lib/mongo/socket/ssl.rb +53 -24
  131. data/lib/mongo/srv/monitor.rb +7 -24
  132. data/lib/mongo/srv/resolver.rb +14 -10
  133. data/lib/mongo/timeout.rb +2 -0
  134. data/lib/mongo/uri.rb +21 -390
  135. data/lib/mongo/uri/options_mapper.rb +620 -0
  136. data/lib/mongo/uri/srv_protocol.rb +3 -2
  137. data/lib/mongo/utils.rb +27 -1
  138. data/lib/mongo/version.rb +1 -1
  139. data/spec/NOTES.aws-auth.md +12 -7
  140. data/spec/README.md +87 -2
  141. data/spec/integration/auth_spec.rb +25 -15
  142. data/spec/integration/bson_symbol_spec.rb +4 -2
  143. data/spec/integration/bulk_write_error_message_spec.rb +41 -0
  144. data/spec/integration/bulk_write_spec.rb +48 -0
  145. data/spec/integration/change_stream_spec.rb +5 -5
  146. data/spec/integration/client_authentication_options_spec.rb +92 -28
  147. data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +6 -2
  148. data/spec/integration/command_monitoring_spec.rb +2 -2
  149. data/spec/integration/connection_pool_populator_spec.rb +4 -2
  150. data/spec/integration/connection_spec.rb +2 -0
  151. data/spec/integration/cursor_reaping_spec.rb +54 -18
  152. data/spec/integration/docs_examples_spec.rb +8 -1
  153. data/spec/integration/fork_reconnect_spec.rb +60 -2
  154. data/spec/integration/ocsp_connectivity_spec.rb +26 -0
  155. data/spec/integration/ocsp_verifier_cache_spec.rb +188 -0
  156. data/spec/integration/ocsp_verifier_spec.rb +340 -0
  157. data/spec/integration/operation_failure_code_spec.rb +1 -1
  158. data/spec/integration/operation_failure_message_spec.rb +90 -0
  159. data/spec/integration/query_cache_spec.rb +1045 -0
  160. data/spec/integration/query_cache_transactions_spec.rb +190 -0
  161. data/spec/integration/reconnect_spec.rb +1 -1
  162. data/spec/integration/retryable_writes/retryable_writes_40_and_newer_spec.rb +1 -0
  163. data/spec/integration/retryable_writes/shared/performs_legacy_retries.rb +2 -0
  164. data/spec/integration/sdam_error_handling_spec.rb +86 -1
  165. data/spec/integration/sdam_events_spec.rb +8 -7
  166. data/spec/integration/server_selection_spec.rb +36 -0
  167. data/spec/integration/size_limit_spec.rb +20 -19
  168. data/spec/integration/snappy_compression_spec.rb +25 -0
  169. data/spec/integration/srv_monitoring_spec.rb +39 -4
  170. data/spec/integration/srv_spec.rb +56 -0
  171. data/spec/integration/transactions_examples_spec.rb +23 -7
  172. data/spec/integration/zlib_compression_spec.rb +1 -1
  173. data/spec/integration/zstd_compression_spec.rb +26 -0
  174. data/spec/lite_spec_helper.rb +15 -5
  175. data/spec/mongo/address_spec.rb +16 -12
  176. data/spec/mongo/auth/ldap/conversation_spec.rb +1 -1
  177. data/spec/mongo/auth/ldap_spec.rb +5 -1
  178. data/spec/mongo/auth/scram_negotiation_spec.rb +1 -1
  179. data/spec/mongo/auth/scram_spec.rb +1 -1
  180. data/spec/mongo/auth/user_spec.rb +1 -1
  181. data/spec/mongo/auth/x509/conversation_spec.rb +3 -3
  182. data/spec/mongo/bulk_write_spec.rb +2 -2
  183. data/spec/mongo/caching_cursor_spec.rb +70 -0
  184. data/spec/mongo/client_construction_spec.rb +273 -35
  185. data/spec/mongo/client_encryption_spec.rb +16 -10
  186. data/spec/mongo/client_spec.rb +64 -0
  187. data/spec/mongo/cluster/topology/replica_set_spec.rb +1 -1
  188. data/spec/mongo/cluster/topology/sharded_spec.rb +1 -1
  189. data/spec/mongo/cluster/topology/single_spec.rb +15 -6
  190. data/spec/mongo/cluster/topology/unknown_spec.rb +1 -1
  191. data/spec/mongo/cluster/topology_spec.rb +1 -1
  192. data/spec/mongo/cluster_spec.rb +6 -18
  193. data/spec/mongo/collection/view/change_stream_resume_spec.rb +1 -1
  194. data/spec/mongo/collection/view/explainable_spec.rb +87 -4
  195. data/spec/mongo/collection/view/map_reduce_spec.rb +2 -0
  196. data/spec/mongo/collection/view/readable_spec.rb +50 -0
  197. data/spec/mongo/collection_crud_spec.rb +4357 -0
  198. data/spec/mongo/collection_ddl_spec.rb +534 -0
  199. data/spec/mongo/collection_spec.rb +5 -4787
  200. data/spec/mongo/crypt/auto_decryption_context_spec.rb +1 -1
  201. data/spec/mongo/crypt/auto_encryption_context_spec.rb +1 -1
  202. data/spec/mongo/crypt/binary_spec.rb +1 -6
  203. data/spec/mongo/crypt/binding/binary_spec.rb +1 -6
  204. data/spec/mongo/crypt/binding/context_spec.rb +2 -7
  205. data/spec/mongo/crypt/binding/helpers_spec.rb +1 -6
  206. data/spec/mongo/crypt/binding/mongocrypt_spec.rb +2 -7
  207. data/spec/mongo/crypt/binding/status_spec.rb +1 -6
  208. data/spec/mongo/crypt/binding/version_spec.rb +1 -6
  209. data/spec/mongo/crypt/data_key_context_spec.rb +1 -1
  210. data/spec/mongo/crypt/explicit_decryption_context_spec.rb +1 -1
  211. data/spec/mongo/crypt/explicit_encryption_context_spec.rb +1 -1
  212. data/spec/mongo/crypt/status_spec.rb +1 -6
  213. data/spec/mongo/database_spec.rb +174 -4
  214. data/spec/mongo/error/bulk_write_error_spec.rb +3 -3
  215. data/spec/mongo/error/no_server_available_spec.rb +1 -1
  216. data/spec/mongo/error/parser_spec.rb +37 -6
  217. data/spec/mongo/index/view_spec.rb +8 -2
  218. data/spec/mongo/logger_spec.rb +13 -11
  219. data/spec/mongo/monitoring/event/server_closed_spec.rb +1 -1
  220. data/spec/mongo/monitoring/event/server_heartbeat_failed_spec.rb +1 -1
  221. data/spec/mongo/monitoring/event/server_heartbeat_succeeded_spec.rb +1 -1
  222. data/spec/mongo/monitoring/event/server_opening_spec.rb +1 -1
  223. data/spec/mongo/monitoring/event/topology_changed_spec.rb +1 -1
  224. data/spec/mongo/monitoring/event/topology_closed_spec.rb +1 -1
  225. data/spec/mongo/monitoring/event/topology_opening_spec.rb +1 -1
  226. data/spec/mongo/operation/aggregate_spec.rb +2 -1
  227. data/spec/mongo/operation/collections_info_spec.rb +4 -1
  228. data/spec/mongo/operation/command_spec.rb +6 -3
  229. data/spec/mongo/operation/create_index_spec.rb +6 -3
  230. data/spec/mongo/operation/create_user_spec.rb +6 -3
  231. data/spec/mongo/operation/delete/bulk_spec.rb +9 -6
  232. data/spec/mongo/operation/delete/op_msg_spec.rb +3 -3
  233. data/spec/mongo/operation/delete_spec.rb +11 -7
  234. data/spec/mongo/operation/drop_index_spec.rb +6 -2
  235. data/spec/mongo/operation/find/legacy_spec.rb +3 -1
  236. data/spec/mongo/operation/get_more_spec.rb +3 -1
  237. data/spec/mongo/operation/indexes_spec.rb +5 -1
  238. data/spec/mongo/operation/insert/bulk_spec.rb +10 -7
  239. data/spec/mongo/operation/insert/command_spec.rb +2 -2
  240. data/spec/mongo/operation/insert/op_msg_spec.rb +3 -3
  241. data/spec/mongo/operation/insert_spec.rb +15 -12
  242. data/spec/mongo/operation/map_reduce_spec.rb +5 -2
  243. data/spec/mongo/operation/read_preference_op_msg_spec.rb +1 -1
  244. data/spec/mongo/operation/remove_user_spec.rb +6 -3
  245. data/spec/mongo/operation/result_spec.rb +1 -1
  246. data/spec/mongo/operation/update/bulk_spec.rb +9 -6
  247. data/spec/mongo/operation/update/command_spec.rb +2 -2
  248. data/spec/mongo/operation/update/op_msg_spec.rb +3 -3
  249. data/spec/mongo/operation/update_spec.rb +10 -7
  250. data/spec/mongo/operation/update_user_spec.rb +4 -1
  251. data/spec/mongo/protocol/compressed_spec.rb +26 -12
  252. data/spec/mongo/query_cache_middleware_spec.rb +55 -0
  253. data/spec/mongo/query_cache_spec.rb +280 -0
  254. data/spec/mongo/retryable_spec.rb +3 -2
  255. data/spec/mongo/server/app_metadata_shared.rb +2 -2
  256. data/spec/mongo/server/app_metadata_spec.rb +2 -0
  257. data/spec/mongo/server/connection_pool/populator_spec.rb +3 -1
  258. data/spec/mongo/server/connection_pool_spec.rb +8 -4
  259. data/spec/mongo/server/connection_spec.rb +39 -25
  260. data/spec/mongo/server/description_spec.rb +18 -0
  261. data/spec/mongo/server/monitor/connection_spec.rb +17 -7
  262. data/spec/mongo/server/monitor_spec.rb +9 -1
  263. data/spec/mongo/server_selector_spec.rb +2 -2
  264. data/spec/mongo/server_spec.rb +15 -2
  265. data/spec/mongo/socket/ssl_spec.rb +44 -4
  266. data/spec/mongo/socket_spec.rb +2 -2
  267. data/spec/mongo/tls_context_hooks_spec.rb +37 -0
  268. data/spec/mongo/uri/srv_protocol_spec.rb +64 -33
  269. data/spec/mongo/uri_option_parsing_spec.rb +11 -11
  270. data/spec/mongo/uri_spec.rb +68 -41
  271. data/spec/mongo/utils_spec.rb +39 -0
  272. data/spec/runners/auth.rb +3 -0
  273. data/spec/runners/change_streams/test.rb +1 -1
  274. data/spec/runners/connection_string.rb +31 -124
  275. data/spec/runners/crud/requirement.rb +40 -3
  276. data/spec/runners/crud/test_base.rb +0 -19
  277. data/spec/runners/crud/verifier.rb +8 -0
  278. data/spec/runners/server_selection.rb +1 -1
  279. data/spec/runners/transactions/operation.rb +13 -2
  280. data/spec/runners/transactions/test.rb +3 -2
  281. data/spec/runners/unified.rb +96 -0
  282. data/spec/runners/unified/assertions.rb +249 -0
  283. data/spec/runners/unified/change_stream_operations.rb +26 -0
  284. data/spec/runners/unified/crud_operations.rb +199 -0
  285. data/spec/runners/unified/ddl_operations.rb +96 -0
  286. data/spec/runners/unified/entity_map.rb +39 -0
  287. data/spec/runners/unified/error.rb +25 -0
  288. data/spec/runners/unified/event_subscriber.rb +91 -0
  289. data/spec/runners/unified/exceptions.rb +21 -0
  290. data/spec/runners/unified/grid_fs_operations.rb +55 -0
  291. data/spec/runners/unified/support_operations.rb +250 -0
  292. data/spec/runners/unified/test.rb +393 -0
  293. data/spec/runners/unified/test_group.rb +28 -0
  294. data/spec/runners/unified/using_hash.rb +31 -0
  295. data/spec/shared/LICENSE +20 -0
  296. data/spec/shared/bin/get-mongodb-download-url +17 -0
  297. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  298. data/spec/shared/lib/mrss/cluster_config.rb +218 -0
  299. data/spec/shared/lib/mrss/constraints.rb +346 -0
  300. data/spec/shared/lib/mrss/docker_runner.rb +262 -0
  301. data/spec/shared/lib/mrss/lite_constraints.rb +175 -0
  302. data/spec/shared/lib/mrss/server_version_registry.rb +112 -0
  303. data/spec/shared/lib/mrss/spec_organizer.rb +149 -0
  304. data/spec/shared/lib/mrss/utils.rb +15 -0
  305. data/spec/shared/share/Dockerfile.erb +231 -0
  306. data/spec/shared/shlib/distro.sh +73 -0
  307. data/spec/shared/shlib/server.sh +290 -0
  308. data/spec/shared/shlib/set_env.sh +128 -0
  309. data/spec/solo/clean_exit_spec.rb +21 -0
  310. data/spec/spec_helper.rb +7 -2
  311. data/spec/spec_tests/cmap_spec.rb +7 -3
  312. data/spec/spec_tests/crud_unified_spec.rb +10 -0
  313. data/spec/spec_tests/data/change_streams/change-streams-errors.yml +0 -1
  314. data/spec/spec_tests/data/change_streams/change-streams.yml +0 -2
  315. data/spec/spec_tests/data/cmap/pool-checkout-connection.yml +6 -2
  316. data/spec/spec_tests/data/cmap/pool-create-min-size.yml +3 -0
  317. data/spec/spec_tests/data/connection_string/valid-warnings.yml +24 -0
  318. data/spec/spec_tests/data/crud_unified/estimatedDocumentCount.yml +267 -0
  319. data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-4.9.yml +60 -0
  320. data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount.yml → estimatedDocumentCount-pre4.9.yml} +2 -0
  321. data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-serverErrors-4.9.yml +146 -0
  322. data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount-serverErrors.yml → estimatedDocumentCount-serverErrors-pre4.9.yml} +2 -0
  323. data/spec/spec_tests/data/retryable_reads/listIndexNames.yml +1 -1
  324. data/spec/spec_tests/data/sdam_monitoring/discovered_standalone.yml +1 -3
  325. data/spec/spec_tests/data/sdam_monitoring/standalone.yml +2 -2
  326. data/spec/spec_tests/data/sdam_monitoring/standalone_repeated.yml +2 -2
  327. data/spec/spec_tests/data/sdam_monitoring/standalone_suppress_equal_description_changes.yml +2 -2
  328. data/spec/spec_tests/data/sdam_monitoring/standalone_to_rs_with_me_mismatch.yml +2 -2
  329. data/spec/spec_tests/data/unified/valid-fail/operation-failure.yml +31 -0
  330. data/spec/spec_tests/data/unified/valid-pass/poc-change-streams.yml +220 -0
  331. data/spec/spec_tests/data/unified/valid-pass/poc-command-monitoring.yml +102 -0
  332. data/spec/spec_tests/data/unified/valid-pass/poc-crud.yml +184 -0
  333. data/spec/spec_tests/data/unified/valid-pass/poc-gridfs.yml +155 -0
  334. data/spec/spec_tests/data/unified/valid-pass/poc-retryable-reads.yml +193 -0
  335. data/spec/spec_tests/data/unified/valid-pass/poc-retryable-writes.yml +210 -0
  336. data/spec/spec_tests/data/unified/valid-pass/poc-sessions.yml +215 -0
  337. data/spec/spec_tests/data/unified/valid-pass/poc-transactions-convenient-api.yml +235 -0
  338. data/spec/spec_tests/data/unified/valid-pass/poc-transactions-mongos-pin-auto.yml +169 -0
  339. data/spec/spec_tests/data/unified/valid-pass/poc-transactions.yml +170 -0
  340. data/spec/spec_tests/data/uri_options/auth-options.yml +25 -0
  341. data/spec/spec_tests/data/uri_options/compression-options.yml +7 -4
  342. data/spec/spec_tests/data/uri_options/read-preference-options.yml +24 -0
  343. data/spec/spec_tests/data/uri_options/ruby-connection-options.yml +1 -0
  344. data/spec/spec_tests/data/uri_options/tls-options.yml +160 -4
  345. data/spec/spec_tests/data/versioned_api/crud-api-version-1-strict.yml +416 -0
  346. data/spec/spec_tests/data/versioned_api/crud-api-version-1.yml +409 -0
  347. data/spec/spec_tests/data/versioned_api/runcommand-helper-no-api-version-declared.yml +67 -0
  348. data/spec/spec_tests/data/versioned_api/test-commands-deprecation-errors.yml +47 -0
  349. data/spec/spec_tests/data/versioned_api/test-commands-strict-mode.yml +44 -0
  350. data/spec/spec_tests/data/versioned_api/transaction-handling.yml +180 -0
  351. data/spec/spec_tests/dns_seedlist_discovery_spec.rb +9 -1
  352. data/spec/spec_tests/unified_spec.rb +15 -0
  353. data/spec/spec_tests/uri_options_spec.rb +47 -33
  354. data/spec/spec_tests/versioned_api_spec.rb +10 -0
  355. data/spec/stress/fork_reconnect_stress_spec.rb +1 -1
  356. data/spec/support/certificates/atlas-ocsp-ca.crt +28 -0
  357. data/spec/support/certificates/atlas-ocsp.crt +41 -0
  358. data/spec/support/client_registry_macros.rb +11 -2
  359. data/spec/support/common_shortcuts.rb +59 -0
  360. data/spec/support/constraints.rb +6 -253
  361. data/spec/support/matchers.rb +16 -0
  362. data/spec/support/ocsp +1 -0
  363. data/spec/support/session_registry.rb +52 -0
  364. data/spec/support/shared/session.rb +2 -2
  365. data/spec/support/spec_config.rb +68 -3
  366. data/spec/support/spec_setup.rb +48 -38
  367. data/spec/support/utils.rb +102 -4
  368. metadata +1087 -936
  369. metadata.gz.sig +0 -0
  370. data/lib/mongo/operation/shared/collections_info_or_list_collections.rb +0 -56
  371. data/lib/mongo/operation/shared/op_msg_or_list_indexes_command.rb +0 -47
  372. data/spec/support/child_process_helper.rb +0 -78
  373. data/spec/support/cluster_config.rb +0 -207
  374. data/spec/support/lite_constraints.rb +0 -141
  375. data/spec/support/spec_organizer.rb +0 -129
@@ -16,14 +16,6 @@ describe Mongo::Collection do
16
16
  authorized_client['collection_spec'].drop
17
17
  end
18
18
 
19
- let(:collection_invalid_write_concern) do
20
- authorized_collection.client.with(write: INVALID_WRITE_CONCERN)[authorized_collection.name]
21
- end
22
-
23
- let(:collection_with_validator) do
24
- authorized_client[:validating]
25
- end
26
-
27
19
  describe '#==' do
28
20
 
29
21
  let(:database) do
@@ -682,4788 +674,14 @@ describe Mongo::Collection do
682
674
  end
683
675
  end
684
676
 
685
- describe '#create' do
686
- before do
687
- authorized_client[:specs].drop
688
- end
689
-
690
- let(:database) do
691
- authorized_client.database
692
- end
693
-
694
- context 'when the collection has no options' do
695
-
696
- let(:collection) do
697
- described_class.new(database, :specs)
698
- end
699
-
700
- let!(:response) do
701
- collection.create
702
- end
703
-
704
- it 'executes the command' do
705
- expect(response).to be_successful
706
- end
707
-
708
- it 'creates the collection in the database' do
709
- expect(database.collection_names).to include('specs')
710
- end
711
- end
712
-
713
- context 'when the collection has options' do
714
-
715
- context 'when the collection is capped' do
716
-
717
- shared_examples 'a capped collection command' do
718
-
719
- let!(:response) do
720
- collection.create
721
- end
722
-
723
- let(:options) do
724
- { :capped => true, :size => 1024 }
725
- end
726
-
727
- it 'executes the command' do
728
- expect(response).to be_successful
729
- end
730
-
731
- it 'sets the collection as capped' do
732
- expect(collection).to be_capped
733
- end
734
-
735
- it 'creates the collection in the database' do
736
- expect(database.collection_names).to include('specs')
737
- end
738
- end
739
-
740
- shared_examples 'a validated collection command' do
741
-
742
- let!(:response) do
743
- collection.create
744
- end
745
-
746
- let(:options) do
747
- { :validator => { fieldName: { '$gte' => 1024 } },
748
- :validationLevel => 'strict' }
749
- end
750
-
751
- let(:collection_info) do
752
- database.list_collections.find { |i| i['name'] == 'specs' }
753
- end
754
-
755
- it 'executes the command' do
756
- expect(response).to be_successful
757
- end
758
-
759
- it 'sets the collection with validators' do
760
- expect(collection_info['options']['validator']).to eq({ 'fieldName' => { '$gte' => 1024 } })
761
- end
762
-
763
- it 'creates the collection in the database' do
764
- expect(database.collection_names).to include('specs')
765
- end
766
- end
767
-
768
- context 'when instantiating a collection directly' do
769
-
770
- let(:collection) do
771
- described_class.new(database, :specs, options)
772
- end
773
-
774
- it_behaves_like 'a capped collection command'
775
-
776
- context 'when validators can be set' do
777
- min_server_fcv '3.2'
778
- it_behaves_like 'a validated collection command'
779
- end
780
- end
781
-
782
- context 'when instantiating a collection through the database' do
783
-
784
- let(:collection) do
785
- authorized_client[:specs, options]
786
- end
787
-
788
- it_behaves_like 'a capped collection command'
789
-
790
- context 'when validators can be set' do
791
- min_server_fcv '3.2'
792
- it_behaves_like 'a validated collection command'
793
- end
794
- end
795
- end
796
-
797
- context 'when the collection has a write concern' do
798
-
799
- before do
800
- database[:specs].drop
801
- end
802
-
803
- let(:options) do
804
- {
805
- write: INVALID_WRITE_CONCERN
806
- }
807
- end
808
-
809
- let(:collection) do
810
- described_class.new(database, :specs, options)
811
- end
812
-
813
- context 'when the server supports write concern on the create command' do
814
- min_server_fcv '3.4'
815
- require_topology :replica_set
816
-
817
- it 'applies the write concern' do
818
- expect{
819
- collection.create
820
- }.to raise_exception(Mongo::Error::OperationFailure)
821
- end
822
- end
823
-
824
- context 'when the server does not support write concern on the create command' do
825
- max_server_version '3.2'
826
-
827
- it 'does not apply the write concern' do
828
- expect(collection.create).to be_successful
829
- end
830
- end
831
- end
832
-
833
- context 'when the collection has a collation' do
834
-
835
- shared_examples 'a collection command with a collation option' do
836
-
837
- let(:response) do
838
- collection.create
839
- end
840
-
841
- let(:options) do
842
- { :collation => { locale: 'fr' } }
843
- end
844
-
845
- let(:collection_info) do
846
- database.list_collections.find { |i| i['name'] == 'specs' }
847
- end
848
-
849
- before do
850
- collection.drop
851
- end
852
-
853
- context 'when the server supports collations' do
854
- min_server_fcv '3.4'
855
-
856
- it 'executes the command' do
857
- expect(response).to be_successful
858
- end
859
-
860
- it 'sets the collection with a collation' do
861
- response
862
- expect(collection_info['options']['collation']['locale']).to eq('fr')
863
- end
864
-
865
- it 'creates the collection in the database' do
866
- response
867
- expect(database.collection_names).to include('specs')
868
- end
869
- end
870
-
871
- context 'when the server does not support collations' do
872
- max_server_version '3.2'
873
-
874
- it 'raises an error' do
875
- expect {
876
- response
877
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
878
- end
879
-
880
- context 'when a String key is used' do
881
-
882
- let(:options) do
883
- { 'collation' => { locale: 'fr' } }
884
- end
885
-
886
- it 'raises an exception' do
887
- expect {
888
- response
889
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
890
- end
891
- end
892
- end
893
- end
894
-
895
- context 'when instantiating a collection directly' do
896
-
897
- let(:collection) do
898
- described_class.new(database, :specs, options)
899
- end
900
-
901
- it_behaves_like 'a collection command with a collation option'
902
- end
903
-
904
- context 'when instantiating a collection through the database' do
905
-
906
- let(:collection) do
907
- authorized_client[:specs, options]
908
- end
909
-
910
- it_behaves_like 'a collection command with a collation option'
911
- end
912
- end
913
-
914
- context 'when a session is provided' do
915
-
916
- let(:collection) do
917
- authorized_client[:specs]
918
- end
919
-
920
- let(:operation) do
921
- collection.create(session: session)
922
- end
923
-
924
- let(:session) do
925
- authorized_client.start_session
926
- end
927
-
928
- let(:client) do
929
- authorized_client
930
- end
931
-
932
- let(:failed_operation) do
933
- authorized_client[:specs, invalid: true].create(session: session)
934
- end
935
-
936
- before do
937
- collection.drop
938
- end
939
-
940
- it_behaves_like 'an operation using a session'
941
- it_behaves_like 'a failed operation using a session'
942
- end
943
- end
944
-
945
- context 'when collation has a strength' do
946
- min_server_fcv '3.4'
947
-
948
- let(:band_collection) do
949
- described_class.new(database, :bands)
950
- end
951
-
952
- before do
953
- band_collection.delete_many
954
- band_collection.insert_many([{ name: "Depeche Mode" }, { name: "New Order" }])
955
- end
956
-
957
- let(:options) do
958
- { collation: { locale: 'en_US', strength: 2 } }
959
- end
960
- let(:band_result) do
961
- band_collection.find({ name: 'DEPECHE MODE' }, options)
962
- end
963
-
964
- it 'finds Capitalize from UPPER CASE' do
965
- expect(band_result.count_documents).to eq(1)
966
- end
967
- end
968
- end
969
-
970
- describe '#drop' do
971
-
972
- let(:database) do
973
- authorized_client.database
974
- end
975
-
976
- let(:collection) do
977
- described_class.new(database, :specs)
978
- end
979
-
980
- context 'when the collection exists' do
981
-
982
- before do
983
- authorized_client[:specs].drop
984
- collection.create
985
- # wait for the collection to be created
986
- sleep 0.4
987
- end
988
-
989
- context 'when a session is provided' do
990
-
991
- let(:operation) do
992
- collection.drop(session: session)
993
- end
994
-
995
- let(:failed_operation) do
996
- collection.with(write: INVALID_WRITE_CONCERN).drop(session: session)
997
- end
998
-
999
- let(:session) do
1000
- authorized_client.start_session
1001
- end
1002
-
1003
- let(:client) do
1004
- authorized_client
1005
- end
1006
-
1007
- it_behaves_like 'an operation using a session'
1008
-
1009
- context 'can set write concern' do
1010
- require_set_write_concern
1011
-
1012
- it_behaves_like 'a failed operation using a session'
1013
- end
1014
- end
1015
-
1016
- context 'when the collection does not have a write concern set' do
1017
-
1018
- let!(:response) do
1019
- collection.drop
1020
- end
1021
-
1022
- it 'executes the command' do
1023
- expect(response).to be_successful
1024
- end
1025
-
1026
- it 'drops the collection from the database' do
1027
- expect(database.collection_names).to_not include('specs')
1028
- end
1029
-
1030
- context 'when the collection does not exist' do
1031
- require_set_write_concern
1032
-
1033
- it 'does not raise an error' do
1034
- expect(database['non-existent-coll'].drop).to be(false)
1035
- end
1036
- end
1037
- end
1038
-
1039
- context 'when the collection has a write concern' do
1040
-
1041
- let(:write_options) do
1042
- {
1043
- write: INVALID_WRITE_CONCERN
1044
- }
1045
- end
1046
-
1047
- let(:collection_with_write_options) do
1048
- collection.with(write_options)
1049
- end
1050
-
1051
- context 'when the server supports write concern on the drop command' do
1052
- min_server_fcv '3.4'
1053
- require_set_write_concern
1054
-
1055
- it 'applies the write concern' do
1056
- expect{
1057
- collection_with_write_options.drop
1058
- }.to raise_exception(Mongo::Error::OperationFailure)
1059
- end
1060
- end
1061
-
1062
- context 'when the server does not support write concern on the drop command' do
1063
- max_server_version '3.2'
1064
-
1065
- it 'does not apply the write concern' do
1066
- expect(collection_with_write_options.drop).to be_successful
1067
- end
1068
- end
1069
- end
1070
- end
1071
-
1072
- context 'when the collection does not exist' do
1073
- require_set_write_concern
1074
-
1075
- before do
1076
- begin
1077
- collection.drop
1078
- rescue Mongo::Error::OperationFailure
1079
- end
1080
- end
1081
-
1082
- it 'returns false' do
1083
- expect(collection.drop).to be(false)
1084
- end
1085
- end
1086
- end
1087
-
1088
- describe '#find' do
1089
-
1090
- describe 'updating cluster time' do
1091
-
1092
- let(:operation) do
1093
- client[TEST_COLL].find.first
1094
- end
1095
-
1096
- let(:operation_with_session) do
1097
- client[TEST_COLL].find({}, session: session).first
1098
- end
1099
-
1100
- let(:second_operation) do
1101
- client[TEST_COLL].find({}, session: session).first
1102
- end
1103
-
1104
- it_behaves_like 'an operation updating cluster time'
1105
- end
1106
-
1107
- context 'when provided a filter' do
1108
-
1109
- let(:view) do
1110
- authorized_collection.find(name: 1)
1111
- end
1112
-
1113
- it 'returns a authorized_collection view for the filter' do
1114
- expect(view.filter).to eq('name' => 1)
1115
- end
1116
- end
1117
-
1118
- context 'when provided no filter' do
1119
-
1120
- let(:view) do
1121
- authorized_collection.find
1122
- end
677
+ describe '#inspect' do
1123
678
 
1124
- it 'returns a authorized_collection view with an empty filter' do
1125
- expect(view.filter).to be_empty
1126
- end
679
+ it 'includes the object id' do
680
+ expect(authorized_collection.inspect).to include(authorized_collection.object_id.to_s)
1127
681
  end
1128
682
 
1129
- context 'when providing a bad filter' do
1130
-
1131
- let(:view) do
1132
- authorized_collection.find('$or' => [])
1133
- end
1134
-
1135
- it 'raises an exception when iterating' do
1136
- expect {
1137
- view.to_a
1138
- }.to raise_exception(Mongo::Error::OperationFailure)
1139
- end
1140
- end
1141
-
1142
- context 'when iterating the authorized_collection view' do
1143
-
1144
- before do
1145
- authorized_collection.insert_many([{ field: 'test1' }, { field: 'test2' }])
1146
- end
1147
-
1148
- let(:view) do
1149
- authorized_collection.find
1150
- end
1151
-
1152
- it 'iterates over the documents' do
1153
- view.each do |document|
1154
- expect(document).to_not be_nil
1155
- end
1156
- end
1157
- end
1158
-
1159
- context 'when the user is not authorized' do
1160
- require_auth
1161
-
1162
- let(:view) do
1163
- unauthorized_collection.find
1164
- end
1165
-
1166
- it 'iterates over the documents' do
1167
- expect {
1168
- view.each{ |document| document }
1169
- }.to raise_error(Mongo::Error::OperationFailure)
1170
- end
1171
- end
1172
-
1173
- context 'when documents contain potential error message fields' do
1174
-
1175
- [ Mongo::Error::ERRMSG, Mongo::Error::ERROR, Mongo::Operation::Result::OK ].each do |field|
1176
-
1177
- context "when the document contains a '#{field}' field" do
1178
-
1179
- let(:value) do
1180
- 'testing'
1181
- end
1182
-
1183
- let(:view) do
1184
- authorized_collection.find
1185
- end
1186
-
1187
- before do
1188
- authorized_collection.insert_one({ field => value })
1189
- end
1190
-
1191
- it 'iterates over the documents' do
1192
- view.each do |document|
1193
- expect(document[field]).to eq(value)
1194
- end
1195
- end
1196
- end
1197
- end
1198
- end
1199
-
1200
- context 'when provided options' do
1201
-
1202
- context 'when a session is provided' do
1203
- require_wired_tiger
1204
-
1205
- let(:operation) do
1206
- authorized_collection.find({}, session: session).to_a
1207
- end
1208
-
1209
- let(:session) do
1210
- authorized_client.start_session
1211
- end
1212
-
1213
- let(:failed_operation) do
1214
- client[authorized_collection.name].find({ '$._id' => 1 }, session: session).to_a
1215
- end
1216
-
1217
- let(:client) do
1218
- authorized_client
1219
- end
1220
-
1221
- it_behaves_like 'an operation using a session'
1222
- it_behaves_like 'a failed operation using a session'
1223
- end
1224
-
1225
- context 'session id' do
1226
- min_server_fcv '3.6'
1227
- require_topology :replica_set, :sharded
1228
- require_wired_tiger
1229
-
1230
- let(:options) do
1231
- { session: session }
1232
- end
1233
-
1234
- let(:session) do
1235
- client.start_session
1236
- end
1237
-
1238
- let(:view) do
1239
- Mongo::Collection::View.new(client[TEST_COLL], selector, view_options)
1240
- end
1241
-
1242
- let(:command) do
1243
- client[TEST_COLL].find({}, session: session).explain
1244
- subscriber.started_events.find { |c| c.command_name == 'explain' }.command
1245
- end
1246
-
1247
- it 'sends the session id' do
1248
- expect(command['lsid']).to eq(session.session_id)
1249
- end
1250
- end
1251
-
1252
- context 'when a session supporting causal consistency is used' do
1253
- require_wired_tiger
1254
-
1255
- let(:operation) do
1256
- collection.find({}, session: session).to_a
1257
- end
1258
-
1259
- let(:command) do
1260
- operation
1261
- subscriber.started_events.find { |cmd| cmd.command_name == 'find' }.command
1262
- end
1263
-
1264
- it_behaves_like 'an operation supporting causally consistent reads'
1265
- end
1266
-
1267
- let(:view) do
1268
- authorized_collection.find({}, options)
1269
- end
1270
-
1271
- context 'when provided :allow_partial_results' do
1272
-
1273
- let(:options) do
1274
- { allow_partial_results: true }
1275
- end
1276
-
1277
- it 'returns a view with :allow_partial_results set' do
1278
- expect(view.options[:allow_partial_results]).to be(options[:allow_partial_results])
1279
- end
1280
- end
1281
-
1282
- context 'when provided :batch_size' do
1283
-
1284
- let(:options) do
1285
- { batch_size: 100 }
1286
- end
1287
-
1288
- it 'returns a view with :batch_size set' do
1289
- expect(view.options[:batch_size]).to eq(options[:batch_size])
1290
- end
1291
- end
1292
-
1293
- context 'when provided :comment' do
1294
-
1295
- let(:options) do
1296
- { comment: 'slow query' }
1297
- end
1298
-
1299
- it 'returns a view with :comment set' do
1300
- expect(view.modifiers[:$comment]).to eq(options[:comment])
1301
- end
1302
- end
1303
-
1304
- context 'when provided :cursor_type' do
1305
-
1306
- let(:options) do
1307
- { cursor_type: :tailable }
1308
- end
1309
-
1310
- it 'returns a view with :cursor_type set' do
1311
- expect(view.options[:cursor_type]).to eq(options[:cursor_type])
1312
- end
1313
- end
1314
-
1315
- context 'when provided :max_time_ms' do
1316
-
1317
- let(:options) do
1318
- { max_time_ms: 500 }
1319
- end
1320
-
1321
- it 'returns a view with :max_time_ms set' do
1322
- expect(view.modifiers[:$maxTimeMS]).to eq(options[:max_time_ms])
1323
- end
1324
- end
1325
-
1326
- context 'when provided :modifiers' do
1327
-
1328
- let(:options) do
1329
- { modifiers: { '$orderby' => Mongo::Index::ASCENDING } }
1330
- end
1331
-
1332
- it 'returns a view with modifiers set' do
1333
- expect(view.modifiers).to eq(options[:modifiers])
1334
- end
1335
-
1336
- it 'dups the modifiers hash' do
1337
- expect(view.modifiers).not_to be(options[:modifiers])
1338
- end
1339
- end
1340
-
1341
- context 'when provided :no_cursor_timeout' do
1342
-
1343
- let(:options) do
1344
- { no_cursor_timeout: true }
1345
- end
1346
-
1347
- it 'returns a view with :no_cursor_timeout set' do
1348
- expect(view.options[:no_cursor_timeout]).to eq(options[:no_cursor_timeout])
1349
- end
1350
- end
1351
-
1352
- context 'when provided :oplog_replay' do
1353
-
1354
- let(:options) do
1355
- { oplog_replay: false }
1356
- end
1357
-
1358
- it 'returns a view with :oplog_replay set' do
1359
- expect(view.options[:oplog_replay]).to eq(options[:oplog_replay])
1360
- end
1361
- end
1362
-
1363
- context 'when provided :projection' do
1364
-
1365
- let(:options) do
1366
- { projection: { 'x' => 1 } }
1367
- end
1368
-
1369
- it 'returns a view with :projection set' do
1370
- expect(view.options[:projection]).to eq(options[:projection])
1371
- end
1372
- end
1373
-
1374
- context 'when provided :skip' do
1375
-
1376
- let(:options) do
1377
- { skip: 5 }
1378
- end
1379
-
1380
- it 'returns a view with :skip set' do
1381
- expect(view.options[:skip]).to eq(options[:skip])
1382
- end
1383
- end
1384
-
1385
- context 'when provided :sort' do
1386
-
1387
- let(:options) do
1388
- { sort: { 'x' => Mongo::Index::ASCENDING } }
1389
- end
1390
-
1391
- it 'returns a view with :sort set' do
1392
- expect(view.modifiers[:$orderby]).to eq(options[:sort])
1393
- end
1394
- end
1395
-
1396
- context 'when provided :collation' do
1397
-
1398
- let(:options) do
1399
- { collation: { 'locale' => 'en_US' } }
1400
- end
1401
-
1402
- it 'returns a view with :collation set' do
1403
- expect(view.options[:collation]).to eq(options[:collation])
1404
- end
1405
- end
1406
- end
1407
- end
1408
-
1409
- describe '#insert_many' do
1410
-
1411
- let(:result) do
1412
- authorized_collection.insert_many([{ name: 'test1' }, { name: 'test2' }])
1413
- end
1414
-
1415
- it 'inserts the documents into the collection' do
1416
- expect(result.inserted_count).to eq(2)
1417
- end
1418
-
1419
- it 'contains the ids in the result' do
1420
- expect(result.inserted_ids.size).to eq(2)
1421
- end
1422
-
1423
- context 'when a session is provided' do
1424
-
1425
- let(:session) do
1426
- authorized_client.start_session
1427
- end
1428
-
1429
- let(:operation) do
1430
- authorized_collection.insert_many([{ name: 'test1' }, { name: 'test2' }], session: session)
1431
- end
1432
-
1433
- let(:failed_operation) do
1434
- authorized_collection.insert_many([{ _id: 'test1' }, { _id: 'test1' }], session: session)
1435
- end
1436
-
1437
- let(:client) do
1438
- authorized_client
1439
- end
1440
-
1441
- it_behaves_like 'an operation using a session'
1442
- it_behaves_like 'a failed operation using a session'
1443
- end
1444
-
1445
- context 'when unacknowledged writes is used with an explicit session' do
1446
-
1447
- let(:collection_with_unacknowledged_write_concern) do
1448
- authorized_collection.with(write: { w: 0 })
1449
- end
1450
-
1451
- let(:operation) do
1452
- collection_with_unacknowledged_write_concern.insert_many([{ name: 'test1' }, { name: 'test2' }], session: session)
1453
- end
1454
-
1455
- it_behaves_like 'an explicit session with an unacknowledged write'
1456
- end
1457
-
1458
- context 'when unacknowledged writes is used with an implicit session' do
1459
-
1460
- let(:collection_with_unacknowledged_write_concern) do
1461
- client.with(write: { w: 0 })[TEST_COLL]
1462
- end
1463
-
1464
- let(:operation) do
1465
- collection_with_unacknowledged_write_concern.insert_many([{ name: 'test1' }, { name: 'test2' }])
1466
- end
1467
-
1468
- it_behaves_like 'an implicit session with an unacknowledged write'
1469
- end
1470
-
1471
- context 'when a document contains invalid keys' do
1472
-
1473
- let(:docs) do
1474
- [ { 'first.name' => 'test1' }, { name: 'test2' } ]
1475
- end
1476
-
1477
- it 'raises a BSON::String::IllegalKey exception' do
1478
- expect {
1479
- authorized_collection.insert_many(docs)
1480
- }.to raise_exception(BSON::String::IllegalKey)
1481
- end
1482
- end
1483
-
1484
- context 'when the client has a custom id generator' do
1485
-
1486
- let(:generator) do
1487
- Class.new do
1488
- def generate
1489
- 1
1490
- end
1491
- end.new
1492
- end
1493
-
1494
- let(:custom_client) do
1495
- authorized_client.with(id_generator: generator)
1496
- end
1497
-
1498
- let(:custom_collection) do
1499
- custom_client['custom_id_generator_test_collection']
1500
- end
1501
-
1502
- before do
1503
- custom_collection.delete_many
1504
- custom_collection.insert_many([{ name: 'testing' }])
1505
- expect(custom_collection.count).to eq(1)
1506
- end
1507
-
1508
- it 'inserts with the custom id' do
1509
- expect(custom_collection.count).to eq(1)
1510
- expect(custom_collection.find.first[:_id]).to eq(1)
1511
- end
1512
- end
1513
-
1514
- context 'when the inserts fail' do
1515
-
1516
- let(:result) do
1517
- authorized_collection.insert_many([{ _id: 1 }, { _id: 1 }])
1518
- end
1519
-
1520
- it 'raises an BulkWriteError' do
1521
- expect {
1522
- result
1523
- }.to raise_exception(Mongo::Error::BulkWriteError)
1524
- end
1525
- end
1526
-
1527
- context "when the documents exceed the max bson size" do
1528
-
1529
- let(:documents) do
1530
- [{ '_id' => 1, 'name' => '1'*17000000 }]
1531
- end
1532
-
1533
- it 'raises a MaxBSONSize error' do
1534
- expect {
1535
- authorized_collection.insert_many(documents)
1536
- }.to raise_error(Mongo::Error::MaxBSONSize)
1537
- end
1538
- end
1539
-
1540
- context 'when the documents are sent with OP_MSG' do
1541
- min_server_fcv '3.6'
1542
-
1543
- let(:documents) do
1544
- [{ '_id' => 1, 'name' => '1'*16777191 }, { '_id' => 'y' }]
1545
- end
1546
-
1547
- before do
1548
- authorized_collection.insert_many(documents)
1549
- end
1550
-
1551
- let(:insert_events) do
1552
- subscriber.started_events.select { |e| e.command_name == 'insert' }
1553
- end
1554
-
1555
- it 'sends the documents in one OP_MSG' do
1556
- expect(insert_events.size).to eq(1)
1557
- expect(insert_events[0].command['documents']).to eq(documents)
1558
- end
1559
- end
1560
-
1561
- context 'when collection has a validator' do
1562
- min_server_fcv '3.2'
1563
-
1564
- around(:each) do |spec|
1565
- authorized_client[:validating].drop
1566
- authorized_client[:validating,
1567
- :validator => { :a => { '$exists' => true } }].tap do |c|
1568
- c.create
1569
- end
1570
- spec.run
1571
- collection_with_validator.drop
1572
- end
1573
-
1574
- context 'when the document is valid' do
1575
-
1576
- let(:result) do
1577
- collection_with_validator.insert_many([{ a: 1 }, { a: 2 }])
1578
- end
1579
-
1580
- it 'inserts successfully' do
1581
- expect(result.inserted_count).to eq(2)
1582
- end
1583
- end
1584
-
1585
- context 'when the document is invalid' do
1586
-
1587
- context 'when bypass_document_validation is not set' do
1588
-
1589
- let(:result2) do
1590
- collection_with_validator.insert_many([{ x: 1 }, { x: 2 }])
1591
- end
1592
-
1593
- it 'raises a BulkWriteError' do
1594
- expect {
1595
- result2
1596
- }.to raise_exception(Mongo::Error::BulkWriteError)
1597
- end
1598
- end
1599
-
1600
- context 'when bypass_document_validation is true' do
1601
-
1602
- let(:result3) do
1603
- collection_with_validator.insert_many(
1604
- [{ x: 1 }, { x: 2 }], :bypass_document_validation => true)
1605
- end
1606
-
1607
- it 'inserts successfully' do
1608
- expect(result3.inserted_count).to eq(2)
1609
- end
1610
- end
1611
- end
1612
- end
1613
-
1614
- context 'when unacknowledged writes is used' do
1615
-
1616
- let(:collection_with_unacknowledged_write_concern) do
1617
- authorized_collection.with(write: { w: 0 })
1618
- end
1619
-
1620
- let(:result) do
1621
- collection_with_unacknowledged_write_concern.insert_many([{ _id: 1 }, { _id: 1 }])
1622
- end
1623
-
1624
- it 'does not raise an exception' do
1625
- expect(result.inserted_count).to be(0)
1626
- end
1627
- end
1628
-
1629
- context 'when various options passed in' do
1630
- # w: 2 requires a replica set
1631
- require_topology :replica_set
1632
-
1633
- # https://jira.mongodb.org/browse/RUBY-2306
1634
- min_server_fcv '3.6'
1635
-
1636
- let(:session) do
1637
- authorized_client.start_session
1638
- end
1639
-
1640
- let(:events) do
1641
- subscriber.command_started_events('insert')
1642
- end
1643
-
1644
- let(:collection) do
1645
- authorized_collection.with(write_concern: {w: 2})
1646
- end
1647
-
1648
- let!(:command) do
1649
- Utils.get_command_event(authorized_client, 'insert') do |client|
1650
- collection.insert_many([{ name: 'test1' }, { name: 'test2' }], session: session,
1651
- write_concern: {w: 1}, bypass_document_validation: true)
1652
- end.command
1653
- end
1654
-
1655
- it 'inserts many successfully with correct options sent to server' do
1656
- expect(events.length).to eq(1)
1657
- expect(command[:writeConcern]).to_not be_nil
1658
- expect(command[:writeConcern][:w]).to eq(1)
1659
- expect(command[:bypassDocumentValidation]).to be(true)
1660
- end
1661
- end
1662
- end
1663
-
1664
- describe '#insert_one' do
1665
-
1666
- describe 'updating cluster time' do
1667
-
1668
- let(:operation) do
1669
- client[TEST_COLL].insert_one({ name: 'testing' })
1670
- end
1671
-
1672
- let(:operation_with_session) do
1673
- client[TEST_COLL].insert_one({ name: 'testing' }, session: session)
1674
- end
1675
-
1676
- let(:second_operation) do
1677
- client[TEST_COLL].insert_one({ name: 'testing' }, session: session)
1678
- end
1679
-
1680
- it_behaves_like 'an operation updating cluster time'
1681
- end
1682
-
1683
- let(:result) do
1684
- authorized_collection.insert_one({ name: 'testing' })
1685
- end
1686
-
1687
- it 'inserts the document into the collection'do
1688
- expect(result.written_count).to eq(1)
1689
- end
1690
-
1691
- it 'contains the id in the result' do
1692
- expect(result.inserted_id).to_not be_nil
1693
- end
1694
-
1695
- context 'when a session is provided' do
1696
-
1697
- let(:session) do
1698
- authorized_client.start_session
1699
- end
1700
-
1701
- let(:operation) do
1702
- authorized_collection.insert_one({ name: 'testing' }, session: session)
1703
- end
1704
-
1705
- let(:failed_operation) do
1706
- authorized_collection.insert_one({ _id: 'testing' })
1707
- authorized_collection.insert_one({ _id: 'testing' }, session: session)
1708
- end
1709
-
1710
- let(:client) do
1711
- authorized_client
1712
- end
1713
-
1714
- it_behaves_like 'an operation using a session'
1715
- it_behaves_like 'a failed operation using a session'
1716
- end
1717
-
1718
- context 'when unacknowledged writes is used with an explicit session' do
1719
-
1720
- let(:collection_with_unacknowledged_write_concern) do
1721
- authorized_collection.with(write: { w: 0 })
1722
- end
1723
-
1724
- let(:operation) do
1725
- collection_with_unacknowledged_write_concern.insert_one({ name: 'testing' }, session: session)
1726
- end
1727
-
1728
- it_behaves_like 'an explicit session with an unacknowledged write'
1729
- end
1730
-
1731
- context 'when unacknowledged writes is used with an implicit session' do
1732
-
1733
- let(:collection_with_unacknowledged_write_concern) do
1734
- client.with(write: { w: 0 })[TEST_COLL]
1735
- end
1736
-
1737
- let(:operation) do
1738
- collection_with_unacknowledged_write_concern.insert_one({ name: 'testing' })
1739
- end
1740
-
1741
- it_behaves_like 'an implicit session with an unacknowledged write'
1742
- end
1743
-
1744
- context 'when various options passed in' do
1745
- # https://jira.mongodb.org/browse/RUBY-2306
1746
- min_server_fcv '3.6'
1747
-
1748
- let(:session) do
1749
- authorized_client.start_session
1750
- end
1751
-
1752
- let(:events) do
1753
- subscriber.command_started_events('insert')
1754
- end
1755
-
1756
- let(:collection) do
1757
- authorized_collection.with(write_concern: {w: 3})
1758
- end
1759
-
1760
- let!(:command) do
1761
- Utils.get_command_event(authorized_client, 'insert') do |client|
1762
- collection.insert_one({name: 'test1'}, session: session, write_concern: {w: 1},
1763
- bypass_document_validation: true)
1764
- end.command
1765
- end
1766
-
1767
- it 'inserts one successfully with correct options sent to server' do
1768
- expect(events.length).to eq(1)
1769
- expect(command[:writeConcern]).to_not be_nil
1770
- expect(command[:writeConcern][:w]).to eq(1)
1771
- expect(command[:bypassDocumentValidation]).to be(true)
1772
- end
1773
- end
1774
-
1775
- context 'when the document contains invalid keys' do
1776
-
1777
- let(:doc) do
1778
- { 'testing.test' => 'value' }
1779
- end
1780
-
1781
- it 'raises a BSON::String::IllegalKey exception' do
1782
- expect {
1783
- authorized_collection.insert_one(doc)
1784
- }.to raise_exception(BSON::String::IllegalKey)
1785
- end
1786
- end
1787
-
1788
- context 'when the insert fails' do
1789
-
1790
- let(:result) do
1791
- authorized_collection.insert_one(_id: 1)
1792
- authorized_collection.insert_one(_id: 1)
1793
- end
1794
-
1795
- it 'raises an OperationFailure' do
1796
- expect {
1797
- result
1798
- }.to raise_exception(Mongo::Error::OperationFailure)
1799
- end
1800
- end
1801
-
1802
- context 'when the client has a custom id generator' do
1803
-
1804
- let(:generator) do
1805
- Class.new do
1806
- def generate
1807
- 1
1808
- end
1809
- end.new
1810
- end
1811
-
1812
- let(:custom_client) do
1813
- authorized_client.with(id_generator: generator)
1814
- end
1815
-
1816
- let(:custom_collection) do
1817
- custom_client[TEST_COLL]
1818
- end
1819
-
1820
- before do
1821
- custom_collection.delete_many
1822
- custom_collection.insert_one({ name: 'testing' })
1823
- end
1824
-
1825
- it 'inserts with the custom id' do
1826
- expect(custom_collection.find.first[:_id]).to eq(1)
1827
- end
1828
- end
1829
-
1830
- context 'when collection has a validator' do
1831
- min_server_fcv '3.2'
1832
-
1833
- around(:each) do |spec|
1834
- authorized_client[:validating,
1835
- :validator => { :a => { '$exists' => true } }].tap do |c|
1836
- c.create
1837
- end
1838
- spec.run
1839
- collection_with_validator.drop
1840
- end
1841
-
1842
- context 'when the document is valid' do
1843
-
1844
- let(:result) do
1845
- collection_with_validator.insert_one({ a: 1 })
1846
- end
1847
-
1848
- it 'inserts successfully' do
1849
- expect(result.written_count).to eq(1)
1850
- end
1851
- end
1852
-
1853
- context 'when the document is invalid' do
1854
-
1855
- context 'when bypass_document_validation is not set' do
1856
-
1857
- let(:result2) do
1858
- collection_with_validator.insert_one({ x: 1 })
1859
- end
1860
-
1861
- it 'raises a OperationFailure' do
1862
- expect {
1863
- result2
1864
- }.to raise_exception(Mongo::Error::OperationFailure)
1865
- end
1866
- end
1867
-
1868
- context 'when bypass_document_validation is true' do
1869
-
1870
- let(:result3) do
1871
- collection_with_validator.insert_one(
1872
- { x: 1 }, :bypass_document_validation => true)
1873
- end
1874
-
1875
- it 'inserts successfully' do
1876
- expect(result3.written_count).to eq(1)
1877
- end
1878
- end
1879
- end
1880
- end
1881
- end
1882
-
1883
- describe '#bulk_write' do
1884
-
1885
- context 'when various options passed in' do
1886
- min_server_fcv '3.2'
1887
- require_topology :replica_set
1888
-
1889
- # https://jira.mongodb.org/browse/RUBY-2306
1890
- min_server_fcv '3.6'
1891
-
1892
- let(:requests) do
1893
- [
1894
- { insert_one: { name: "anne" }},
1895
- { insert_one: { name: "bob" }},
1896
- { insert_one: { name: "charlie" }}
1897
- ]
1898
- end
1899
-
1900
- let(:session) do
1901
- authorized_client.start_session
1902
- end
1903
-
1904
- let!(:command) do
1905
- Utils.get_command_event(authorized_client, 'insert') do |client|
1906
- collection.bulk_write(requests, session: session, write_concern: {w: 1},
1907
- bypass_document_validation: true)
1908
- end.command
1909
- end
1910
-
1911
- let(:events) do
1912
- subscriber.command_started_events('insert')
1913
- end
1914
-
1915
- let(:collection) do
1916
- authorized_collection.with(write_concern: {w: 2})
1917
- end
1918
-
1919
- it 'inserts successfully with correct options sent to server' do
1920
- expect(collection.count).to eq(3)
1921
- expect(events.length).to eq(1)
1922
- expect(command[:writeConcern]).to_not be_nil
1923
- expect(command[:writeConcern][:w]).to eq(1)
1924
- expect(command[:bypassDocumentValidation]).to eq(true)
1925
- end
1926
- end
1927
- end
1928
-
1929
- describe '#inspect' do
1930
-
1931
- it 'includes the object id' do
1932
- expect(authorized_collection.inspect).to include(authorized_collection.object_id.to_s)
1933
- end
1934
-
1935
- it 'includes the namespace' do
1936
- expect(authorized_collection.inspect).to include(authorized_collection.namespace)
1937
- end
1938
- end
1939
-
1940
- describe '#indexes' do
1941
-
1942
- let(:index_spec) do
1943
- { name: 1 }
1944
- end
1945
-
1946
- let(:batch_size) { nil }
1947
-
1948
- let(:index_names) do
1949
- authorized_collection.indexes(batch_size: batch_size).collect { |i| i['name'] }
1950
- end
1951
-
1952
- before do
1953
- authorized_collection.indexes.create_one(index_spec, unique: true)
1954
- end
1955
-
1956
- it 'returns a list of indexes' do
1957
- expect(index_names).to include(*'name_1', '_id_')
1958
- end
1959
-
1960
- context 'when a session is provided' do
1961
- require_wired_tiger
1962
-
1963
- let(:session) do
1964
- authorized_client.start_session
1965
- end
1966
-
1967
- let(:operation) do
1968
- authorized_collection.indexes(batch_size: batch_size, session: session).collect { |i| i['name'] }
1969
- end
1970
-
1971
- let(:failed_operation) do
1972
- authorized_collection.indexes(batch_size: -100, session: session).collect { |i| i['name'] }
1973
- end
1974
-
1975
- let(:client) do
1976
- authorized_client
1977
- end
1978
-
1979
- it_behaves_like 'an operation using a session'
1980
- it_behaves_like 'a failed operation using a session'
1981
- end
1982
-
1983
- context 'when batch size is specified' do
1984
-
1985
- let(:batch_size) { 1 }
1986
-
1987
- it 'returns a list of indexes' do
1988
- expect(index_names).to include(*'name_1', '_id_')
1989
- end
1990
- end
1991
- end
1992
-
1993
- describe '#aggregate' do
1994
-
1995
- describe 'updating cluster time' do
1996
-
1997
- let(:operation) do
1998
- client[TEST_COLL].aggregate([]).first
1999
- end
2000
-
2001
- let(:operation_with_session) do
2002
- client[TEST_COLL].aggregate([], session: session).first
2003
- end
2004
-
2005
- let(:second_operation) do
2006
- client[TEST_COLL].aggregate([], session: session).first
2007
- end
2008
-
2009
- it_behaves_like 'an operation updating cluster time'
2010
- end
2011
-
2012
- context 'when a session supporting causal consistency is used' do
2013
- require_wired_tiger
2014
-
2015
- let(:operation) do
2016
- collection.aggregate([], session: session).first
2017
- end
2018
-
2019
- let(:command) do
2020
- operation
2021
- subscriber.started_events.find { |cmd| cmd.command_name == 'aggregate' }.command
2022
- end
2023
-
2024
- it_behaves_like 'an operation supporting causally consistent reads'
2025
- end
2026
-
2027
- it 'returns an Aggregation object' do
2028
- expect(authorized_collection.aggregate([])).to be_a(Mongo::Collection::View::Aggregation)
2029
- end
2030
-
2031
- context 'when options are provided' do
2032
-
2033
- let(:options) do
2034
- { :allow_disk_use => true, :bypass_document_validation => true }
2035
- end
2036
-
2037
- it 'sets the options on the Aggregation object' do
2038
- expect(authorized_collection.aggregate([], options).options).to eq(BSON::Document.new(options))
2039
- end
2040
-
2041
- context 'when the :comment option is provided' do
2042
-
2043
- let(:options) do
2044
- { :comment => 'testing' }
2045
- end
2046
-
2047
- it 'sets the options on the Aggregation object' do
2048
- expect(authorized_collection.aggregate([], options).options).to eq(BSON::Document.new(options))
2049
- end
2050
- end
2051
-
2052
- context 'when a session is provided' do
2053
-
2054
- let(:session) do
2055
- authorized_client.start_session
2056
- end
2057
-
2058
- let(:operation) do
2059
- authorized_collection.aggregate([], session: session).to_a
2060
- end
2061
-
2062
- let(:failed_operation) do
2063
- authorized_collection.aggregate([ { '$invalid' => 1 }], session: session).to_a
2064
- end
2065
-
2066
- let(:client) do
2067
- authorized_client
2068
- end
2069
-
2070
- it_behaves_like 'an operation using a session'
2071
- it_behaves_like 'a failed operation using a session'
2072
- end
2073
-
2074
- context 'when a hint is provided' do
2075
-
2076
- let(:options) do
2077
- { 'hint' => { 'y' => 1 } }
2078
- end
2079
-
2080
- it 'sets the options on the Aggregation object' do
2081
- expect(authorized_collection.aggregate([], options).options).to eq(options)
2082
- end
2083
- end
2084
-
2085
- context 'when collation is provided' do
2086
-
2087
- before do
2088
- authorized_collection.insert_many([ { name: 'bang' }, { name: 'bang' }])
2089
- end
2090
-
2091
- let(:pipeline) do
2092
- [{ "$match" => { "name" => "BANG" } }]
2093
- end
2094
-
2095
- let(:options) do
2096
- { collation: { locale: 'en_US', strength: 2 } }
2097
- end
2098
-
2099
- let(:result) do
2100
- authorized_collection.aggregate(pipeline, options).collect { |doc| doc['name']}
2101
- end
2102
-
2103
- context 'when the server selected supports collations' do
2104
- min_server_fcv '3.4'
2105
-
2106
- it 'applies the collation' do
2107
- expect(result).to eq(['bang', 'bang'])
2108
- end
2109
- end
2110
-
2111
- context 'when the server selected does not support collations' do
2112
- max_server_version '3.2'
2113
-
2114
- it 'raises an exception' do
2115
- expect {
2116
- result
2117
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2118
- end
2119
-
2120
- context 'when a String key is used' do
2121
-
2122
- let(:options) do
2123
- { 'collation' => { locale: 'en_US', strength: 2 } }
2124
- end
2125
-
2126
- it 'raises an exception' do
2127
- expect {
2128
- result
2129
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2130
- end
2131
- end
2132
- end
2133
- end
2134
- end
2135
- end
2136
-
2137
- describe '#count_documents' do
2138
-
2139
- before do
2140
- authorized_collection.delete_many
2141
- end
2142
-
2143
- context 'no argument provided' do
2144
-
2145
- context 'when collection is empty' do
2146
- it 'returns 0 matching documents' do
2147
- expect(authorized_collection.count_documents).to eq(0)
2148
- end
2149
- end
2150
-
2151
- context 'when collection is not empty' do
2152
-
2153
- let(:documents) do
2154
- documents = []
2155
- 1.upto(10) do |index|
2156
- documents << { key: 'a', _id: "in#{index}" }
2157
- end
2158
- documents
2159
- end
2160
-
2161
- before do
2162
- authorized_collection.insert_many(documents)
2163
- end
2164
-
2165
- it 'returns 10 matching documents' do
2166
- expect(authorized_collection.count_documents).to eq(10)
2167
- end
2168
- end
2169
- end
2170
-
2171
- context 'when transactions are enabled' do
2172
- require_wired_tiger
2173
- require_transaction_support
2174
-
2175
- before do
2176
- # Ensure that the collection is created
2177
- authorized_collection.insert_one(x: 1)
2178
- authorized_collection.delete_many({})
2179
- end
2180
-
2181
- let(:session) do
2182
- authorized_client.start_session
2183
- end
2184
-
2185
- it 'successfully starts a transaction and executes a transaction' do
2186
- session.start_transaction
2187
- expect(
2188
- session.instance_variable_get(:@state)
2189
- ).to eq(Mongo::Session::STARTING_TRANSACTION_STATE)
2190
-
2191
- expect(authorized_collection.count_documents({}, { session: session })).to eq(0)
2192
- expect(
2193
- session.instance_variable_get(:@state)
2194
- ).to eq(Mongo::Session::TRANSACTION_IN_PROGRESS_STATE)
2195
-
2196
- authorized_collection.insert_one({ x: 1 }, { session: session })
2197
- expect(authorized_collection.count_documents({}, { session: session })).to eq(1)
2198
-
2199
- session.commit_transaction
2200
- expect(
2201
- session.instance_variable_get(:@state)
2202
- ).to eq(Mongo::Session::TRANSACTION_COMMITTED_STATE)
2203
- end
2204
- end
2205
- end
2206
-
2207
- describe '#count' do
2208
-
2209
- let(:documents) do
2210
- (1..10).map{ |i| { field: "test#{i}" }}
2211
- end
2212
-
2213
- before do
2214
- authorized_collection.insert_many(documents)
2215
- end
2216
-
2217
- it 'returns an integer count' do
2218
- expect(authorized_collection.count).to eq(10)
2219
- end
2220
-
2221
- context 'when options are provided' do
2222
-
2223
- it 'passes the options to the count' do
2224
- expect(authorized_collection.count({}, limit: 5)).to eq(5)
2225
- end
2226
-
2227
- context 'when a session is provided' do
2228
- require_wired_tiger
2229
-
2230
- let(:session) do
2231
- authorized_client.start_session
2232
- end
2233
-
2234
- let(:operation) do
2235
- authorized_collection.count({}, session: session)
2236
- end
2237
-
2238
- let(:failed_operation) do
2239
- authorized_collection.count({ '$._id' => 1 }, session: session)
2240
- end
2241
-
2242
- let(:client) do
2243
- authorized_client
2244
- end
2245
-
2246
- it_behaves_like 'an operation using a session'
2247
- it_behaves_like 'a failed operation using a session'
2248
- end
2249
-
2250
- context 'when a session supporting causal consistency is used' do
2251
- require_wired_tiger
2252
-
2253
- let(:operation) do
2254
- collection.count({}, session: session)
2255
- end
2256
-
2257
- let(:command) do
2258
- operation
2259
- subscriber.started_events.find { |cmd| cmd.command_name == 'count' }.command
2260
- end
2261
-
2262
- it_behaves_like 'an operation supporting causally consistent reads'
2263
- end
2264
-
2265
- context 'when a collation is specified' do
2266
-
2267
- let(:selector) do
2268
- { name: 'BANG' }
2269
- end
2270
-
2271
- let(:result) do
2272
- authorized_collection.count(selector, options)
2273
- end
2274
-
2275
- before do
2276
- authorized_collection.insert_one(name: 'bang')
2277
- end
2278
-
2279
- let(:options) do
2280
- { collation: { locale: 'en_US', strength: 2 } }
2281
- end
2282
-
2283
- context 'when the server selected supports collations' do
2284
- min_server_fcv '3.4'
2285
-
2286
- it 'applies the collation to the count' do
2287
- expect(result).to eq(1)
2288
- end
2289
- end
2290
-
2291
- context 'when the server selected does not support collations' do
2292
- max_server_version '3.2'
2293
-
2294
- it 'raises an exception' do
2295
- expect {
2296
- result
2297
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2298
- end
2299
-
2300
- context 'when a String key is used' do
2301
-
2302
- let(:options) do
2303
- { 'collation' => { locale: 'en_US', strength: 2 } }
2304
- end
2305
-
2306
- it 'raises an exception' do
2307
- expect {
2308
- result
2309
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2310
- end
2311
- end
2312
- end
2313
- end
2314
- end
2315
- end
2316
-
2317
- describe '#distinct' do
2318
-
2319
- let(:documents) do
2320
- (1..3).map{ |i| { field: "test#{i}" }}
2321
- end
2322
-
2323
- before do
2324
- authorized_collection.insert_many(documents)
2325
- end
2326
-
2327
- it 'returns the distinct values' do
2328
- expect(authorized_collection.distinct(:field).sort).to eq([ 'test1', 'test2', 'test3' ])
2329
- end
2330
-
2331
- context 'when a selector is provided' do
2332
-
2333
- it 'returns the distinct values' do
2334
- expect(authorized_collection.distinct(:field, field: 'test1')).to eq([ 'test1' ])
2335
- end
2336
- end
2337
-
2338
- context 'when options are provided' do
2339
-
2340
- it 'passes the options to the distinct command' do
2341
- expect(authorized_collection.distinct(:field, {}, max_time_ms: 100).sort).to eq([ 'test1', 'test2', 'test3' ])
2342
- end
2343
-
2344
- context 'when a session is provided' do
2345
- require_wired_tiger
2346
-
2347
- let(:session) do
2348
- authorized_client.start_session
2349
- end
2350
-
2351
- let(:operation) do
2352
- authorized_collection.distinct(:field, {}, session: session)
2353
- end
2354
-
2355
- let(:failed_operation) do
2356
- authorized_collection.distinct(:field, { '$._id' => 1 }, session: session)
2357
- end
2358
-
2359
- let(:client) do
2360
- authorized_client
2361
- end
2362
-
2363
- it_behaves_like 'an operation using a session'
2364
- it_behaves_like 'a failed operation using a session'
2365
- end
2366
- end
2367
-
2368
- context 'when a session supporting causal consistency is used' do
2369
- require_wired_tiger
2370
-
2371
- let(:operation) do
2372
- collection.distinct(:field, {}, session: session)
2373
- end
2374
-
2375
- let(:command) do
2376
- operation
2377
- subscriber.started_events.find { |cmd| cmd.command_name == 'distinct' }.command
2378
- end
2379
-
2380
- it_behaves_like 'an operation supporting causally consistent reads'
2381
- end
2382
-
2383
- context 'when a collation is specified' do
2384
-
2385
- let(:result) do
2386
- authorized_collection.distinct(:name, {}, options)
2387
- end
2388
-
2389
- before do
2390
- authorized_collection.insert_one(name: 'bang')
2391
- authorized_collection.insert_one(name: 'BANG')
2392
- end
2393
-
2394
- let(:options) do
2395
- { collation: { locale: 'en_US', strength: 2 } }
2396
- end
2397
-
2398
- context 'when the server selected supports collations' do
2399
- min_server_fcv '3.4'
2400
-
2401
- it 'applies the collation to the distinct' do
2402
- expect(result).to eq(['bang'])
2403
- end
2404
- end
2405
-
2406
- context 'when the server selected does not support collations' do
2407
- max_server_version '3.2'
2408
-
2409
- it 'raises an exception' do
2410
- expect {
2411
- result
2412
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2413
- end
2414
-
2415
- context 'when a String key is used' do
2416
-
2417
- let(:options) do
2418
- { 'collation' => { locale: 'en_US', strength: 2 } }
2419
- end
2420
-
2421
- it 'raises an exception' do
2422
- expect {
2423
- result
2424
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2425
- end
2426
- end
2427
- end
2428
- end
2429
-
2430
- context 'when a collation is not specified' do
2431
-
2432
- let(:result) do
2433
- authorized_collection.distinct(:name)
2434
- end
2435
-
2436
- before do
2437
- authorized_collection.insert_one(name: 'bang')
2438
- authorized_collection.insert_one(name: 'BANG')
2439
- end
2440
-
2441
- it 'does not apply the collation to the distinct' do
2442
- expect(result).to match_array(['bang', 'BANG'])
2443
- end
2444
- end
2445
- end
2446
-
2447
- describe '#delete_one' do
2448
-
2449
- context 'when a selector was provided' do
2450
-
2451
- let(:selector) do
2452
- { field: 'test1' }
2453
- end
2454
-
2455
- before do
2456
- authorized_collection.insert_many([
2457
- { field: 'test1' },
2458
- { field: 'test1' },
2459
- { field: 'test1' }
2460
- ])
2461
- end
2462
-
2463
- let(:response) do
2464
- authorized_collection.delete_one(selector)
2465
- end
2466
-
2467
- it 'deletes the first matching document in the collection' do
2468
- expect(response.deleted_count).to eq(1)
2469
- end
2470
- end
2471
-
2472
- context 'when no selector was provided' do
2473
-
2474
- before do
2475
- authorized_collection.insert_many([{ field: 'test1' }, { field: 'test2' }])
2476
- end
2477
-
2478
- let(:response) do
2479
- authorized_collection.delete_one
2480
- end
2481
-
2482
- it 'deletes the first document in the collection' do
2483
- expect(response.deleted_count).to eq(1)
2484
- end
2485
- end
2486
-
2487
- context 'when the delete fails' do
2488
- require_topology :single
2489
-
2490
- let(:result) do
2491
- collection_invalid_write_concern.delete_one
2492
- end
2493
-
2494
- it 'raises an OperationFailure' do
2495
- expect {
2496
- result
2497
- }.to raise_exception(Mongo::Error::OperationFailure)
2498
- end
2499
- end
2500
-
2501
- context 'when a session is provided' do
2502
-
2503
- let(:session) do
2504
- authorized_client.start_session
2505
- end
2506
-
2507
- let(:operation) do
2508
- authorized_collection.delete_one({}, session: session)
2509
- end
2510
-
2511
- let(:failed_operation) do
2512
- authorized_collection.delete_one({ '$._id' => 1}, session: session)
2513
- end
2514
-
2515
- let(:client) do
2516
- authorized_client
2517
- end
2518
-
2519
- it_behaves_like 'an operation using a session'
2520
- it_behaves_like 'a failed operation using a session'
2521
- end
2522
-
2523
- context 'when unacknowledged writes is used' do
2524
-
2525
- let(:collection_with_unacknowledged_write_concern) do
2526
- authorized_collection.with(write: { w: 0 })
2527
- end
2528
-
2529
- let(:operation) do
2530
- collection_with_unacknowledged_write_concern.delete_one({}, session: session)
2531
- end
2532
-
2533
- it_behaves_like 'an explicit session with an unacknowledged write'
2534
- end
2535
-
2536
- context 'when unacknowledged writes is used with an implicit session' do
2537
-
2538
- let(:collection_with_unacknowledged_write_concern) do
2539
- client.with(write: { w: 0 })[TEST_COLL]
2540
- end
2541
-
2542
- let(:operation) do
2543
- collection_with_unacknowledged_write_concern.delete_one
2544
- end
2545
-
2546
- it_behaves_like 'an implicit session with an unacknowledged write'
2547
- end
2548
-
2549
- context 'when a collation is provided' do
2550
-
2551
- let(:selector) do
2552
- { name: 'BANG' }
2553
- end
2554
-
2555
- let(:result) do
2556
- authorized_collection.delete_one(selector, options)
2557
- end
2558
-
2559
- before do
2560
- authorized_collection.insert_one(name: 'bang')
2561
- end
2562
-
2563
- let(:options) do
2564
- { collation: { locale: 'en_US', strength: 2 } }
2565
- end
2566
-
2567
- context 'when the server selected supports collations' do
2568
- min_server_fcv '3.4'
2569
-
2570
- it 'applies the collation' do
2571
- expect(result.written_count).to eq(1)
2572
- expect(authorized_collection.find(name: 'bang').count).to eq(0)
2573
- end
2574
-
2575
- context 'when unacknowledged writes is used' do
2576
-
2577
- let(:collection_with_unacknowledged_write_concern) do
2578
- authorized_collection.with(write: { w: 0 })
2579
- end
2580
-
2581
- let(:result) do
2582
- collection_with_unacknowledged_write_concern.delete_one(selector, options)
2583
- end
2584
-
2585
- it 'raises an exception' do
2586
- expect {
2587
- result
2588
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2589
- end
2590
-
2591
- context 'when a String key is used' do
2592
-
2593
- let(:options) do
2594
- { 'collation' => { locale: 'en_US', strength: 2 } }
2595
- end
2596
-
2597
- it 'raises an exception' do
2598
- expect {
2599
- result
2600
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2601
- end
2602
- end
2603
- end
2604
- end
2605
-
2606
- context 'when the server selected does not support collations' do
2607
- max_server_version '3.2'
2608
-
2609
- it 'raises an exception' do
2610
- expect {
2611
- result
2612
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2613
- end
2614
-
2615
- context 'when a String key is used' do
2616
-
2617
- let(:options) do
2618
- { 'collation' => { locale: 'en_US', strength: 2 } }
2619
- end
2620
-
2621
- it 'raises an exception' do
2622
- expect {
2623
- result
2624
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2625
- end
2626
- end
2627
- end
2628
- end
2629
-
2630
- context 'when collation is not specified' do
2631
-
2632
- let(:selector) do
2633
- { name: 'BANG' }
2634
- end
2635
-
2636
- let(:result) do
2637
- authorized_collection.delete_one(selector)
2638
- end
2639
-
2640
- before do
2641
- authorized_collection.insert_one(name: 'bang')
2642
- end
2643
-
2644
- it 'does not apply the collation' do
2645
- expect(result.written_count).to eq(0)
2646
- expect(authorized_collection.find(name: 'bang').count).to eq(1)
2647
- end
2648
- end
2649
-
2650
- context 'when various options passed in' do
2651
- # w: 2 requires a replica set
2652
- require_topology :replica_set
2653
-
2654
- # https://jira.mongodb.org/browse/RUBY-2306
2655
- min_server_fcv '3.6'
2656
-
2657
- before do
2658
- authorized_collection.insert_many([{ name: 'test1' }, { name: 'test2' }])
2659
- end
2660
-
2661
- let(:selector) do
2662
- {name: 'test2'}
2663
- end
2664
-
2665
- let(:session) do
2666
- authorized_client.start_session
2667
- end
2668
-
2669
- let(:events) do
2670
- subscriber.command_started_events('delete')
2671
- end
2672
-
2673
- let(:collection) do
2674
- authorized_collection.with(write_concern: {w: 2})
2675
- end
2676
-
2677
- let!(:command) do
2678
- Utils.get_command_event(authorized_client, 'delete') do |client|
2679
- collection.delete_one(selector, session: session, write_concern: {w: 1},
2680
- bypass_document_validation: true)
2681
- end.command
2682
- end
2683
-
2684
- it 'deletes one successfully with correct options sent to server' do
2685
- expect(events.length).to eq(1)
2686
- expect(command[:writeConcern]).to_not be_nil
2687
- expect(command[:writeConcern][:w]).to eq(1)
2688
- expect(command[:bypassDocumentValidation]).to eq(true)
2689
- end
2690
- end
2691
- end
2692
-
2693
- describe '#delete_many' do
2694
-
2695
- before do
2696
- authorized_collection.insert_many([{ field: 'test1' }, { field: 'test2' }])
2697
- end
2698
-
2699
- context 'when a selector was provided' do
2700
-
2701
- let(:selector) do
2702
- { field: 'test1' }
2703
- end
2704
-
2705
- it 'deletes the matching documents in the collection' do
2706
- expect(authorized_collection.delete_many(selector).deleted_count).to eq(1)
2707
- end
2708
- end
2709
-
2710
- context 'when no selector was provided' do
2711
-
2712
- it 'deletes all the documents in the collection' do
2713
- expect(authorized_collection.delete_many.deleted_count).to eq(2)
2714
- end
2715
- end
2716
-
2717
- context 'when the deletes fail' do
2718
- require_topology :single
2719
-
2720
- let(:result) do
2721
- collection_invalid_write_concern.delete_many
2722
- end
2723
-
2724
- it 'raises an OperationFailure' do
2725
- expect {
2726
- result
2727
- }.to raise_exception(Mongo::Error::OperationFailure)
2728
- end
2729
- end
2730
-
2731
- context 'when a session is provided' do
2732
-
2733
- let(:session) do
2734
- authorized_client.start_session
2735
- end
2736
-
2737
- let(:operation) do
2738
- authorized_collection.delete_many({}, session: session)
2739
- end
2740
-
2741
- let(:failed_operation) do
2742
- authorized_collection.delete_many({ '$._id' => 1}, session: session)
2743
- end
2744
-
2745
- let(:client) do
2746
- authorized_client
2747
- end
2748
-
2749
- it_behaves_like 'an operation using a session'
2750
- it_behaves_like 'a failed operation using a session'
2751
- end
2752
-
2753
- context 'when unacknowledged writes are used with an explicit session' do
2754
-
2755
- let(:collection_with_unacknowledged_write_concern) do
2756
- authorized_collection.with(write: { w: 0 })
2757
- end
2758
-
2759
- let(:operation) do
2760
- collection_with_unacknowledged_write_concern.delete_many({ '$._id' => 1}, session: session)
2761
- end
2762
-
2763
- it_behaves_like 'an explicit session with an unacknowledged write'
2764
- end
2765
-
2766
- context 'when unacknowledged writes are used with an implicit session' do
2767
-
2768
- let(:collection_with_unacknowledged_write_concern) do
2769
- client.with(write: { w: 0 })[TEST_COLL]
2770
- end
2771
-
2772
- let(:operation) do
2773
- collection_with_unacknowledged_write_concern.delete_many({ '$._id' => 1 })
2774
- end
2775
-
2776
- it_behaves_like 'an implicit session with an unacknowledged write'
2777
- end
2778
-
2779
- context 'when a collation is specified' do
2780
-
2781
- let(:selector) do
2782
- { name: 'BANG' }
2783
- end
2784
-
2785
- let(:result) do
2786
- authorized_collection.delete_many(selector, options)
2787
- end
2788
-
2789
- before do
2790
- authorized_collection.insert_one(name: 'bang')
2791
- authorized_collection.insert_one(name: 'bang')
2792
- end
2793
-
2794
- let(:options) do
2795
- { collation: { locale: 'en_US', strength: 2 } }
2796
- end
2797
-
2798
- context 'when the server selected supports collations' do
2799
- min_server_fcv '3.4'
2800
-
2801
- it 'applies the collation' do
2802
- expect(result.written_count).to eq(2)
2803
- expect(authorized_collection.find(name: 'bang').count).to eq(0)
2804
- end
2805
-
2806
- context 'when unacknowledged writes is used' do
2807
-
2808
- let(:collection_with_unacknowledged_write_concern) do
2809
- authorized_collection.with(write: { w: 0 })
2810
- end
2811
-
2812
- let(:result) do
2813
- collection_with_unacknowledged_write_concern.delete_many(selector, options)
2814
- end
2815
-
2816
- it 'raises an exception' do
2817
- expect {
2818
- result
2819
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2820
- end
2821
-
2822
- context 'when a String key is used' do
2823
-
2824
- let(:options) do
2825
- { 'collation' => { locale: 'en_US', strength: 2 } }
2826
- end
2827
-
2828
- it 'raises an exception' do
2829
- expect {
2830
- result
2831
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2832
- end
2833
- end
2834
- end
2835
- end
2836
-
2837
- context 'when the server selected does not support collations' do
2838
- max_server_version '3.2'
2839
-
2840
- it 'raises an exception' do
2841
- expect {
2842
- result
2843
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2844
- end
2845
-
2846
- context 'when a String key is used' do
2847
-
2848
- let(:options) do
2849
- { 'collation' => { locale: 'en_US', strength: 2 } }
2850
- end
2851
-
2852
- it 'raises an exception' do
2853
- expect {
2854
- result
2855
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2856
- end
2857
- end
2858
- end
2859
- end
2860
-
2861
- context 'when a collation is not specified' do
2862
-
2863
- let(:selector) do
2864
- { name: 'BANG' }
2865
- end
2866
-
2867
- let(:result) do
2868
- authorized_collection.delete_many(selector)
2869
- end
2870
-
2871
- before do
2872
- authorized_collection.insert_one(name: 'bang')
2873
- authorized_collection.insert_one(name: 'bang')
2874
- end
2875
-
2876
- it 'does not apply the collation' do
2877
- expect(result.written_count).to eq(0)
2878
- expect(authorized_collection.find(name: 'bang').count).to eq(2)
2879
- end
2880
- end
2881
-
2882
- context 'when various options passed in' do
2883
- # w: 2 requires a replica set
2884
- require_topology :replica_set
2885
-
2886
- # https://jira.mongodb.org/browse/RUBY-2306
2887
- min_server_fcv '3.6'
2888
-
2889
- before do
2890
- collection.insert_many([{ name: 'test1' }, { name: 'test2' }, { name: 'test3'}])
2891
- end
2892
-
2893
- let(:selector) do
2894
- {name: 'test1'}
2895
- end
2896
-
2897
- let(:session) do
2898
- authorized_client.start_session
2899
- end
2900
-
2901
- let(:events) do
2902
- subscriber.command_started_events('delete')
2903
- end
2904
-
2905
- let(:collection) do
2906
- authorized_collection.with(write_concern: {w: 1})
2907
- end
2908
-
2909
- let!(:command) do
2910
- Utils.get_command_event(authorized_client, 'delete') do |client|
2911
- collection.delete_many(selector, session: session, write_concern: {w: 2},
2912
- bypass_document_validation: true)
2913
- end.command
2914
- end
2915
-
2916
- it 'deletes many successfully with correct options sent to server' do
2917
- expect(events.length).to eq(1)
2918
- expect(command[:writeConcern]).to_not be_nil
2919
- expect(command[:writeConcern][:w]).to eq(2)
2920
- expect(command[:bypassDocumentValidation]).to be(true)
2921
- end
2922
- end
2923
- end
2924
-
2925
- describe '#parallel_scan' do
2926
- max_server_version '4.0'
2927
- require_topology :single, :replica_set
2928
-
2929
- let(:documents) do
2930
- (1..200).map do |i|
2931
- { name: "testing-scan-#{i}" }
2932
- end
2933
- end
2934
-
2935
- before do
2936
- authorized_collection.insert_many(documents)
2937
- end
2938
-
2939
- let(:cursors) do
2940
- authorized_collection.parallel_scan(2)
2941
- end
2942
-
2943
- it 'returns an array of cursors' do
2944
- cursors.each do |cursor|
2945
- expect(cursor.class).to be(Mongo::Cursor)
2946
- end
2947
- end
2948
-
2949
- it 'returns the correct number of documents' do
2950
- expect(
2951
- cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
2952
- ).to eq(200)
2953
- end
2954
-
2955
- context 'when a session is provided' do
2956
- require_wired_tiger
2957
-
2958
- let(:cursors) do
2959
- authorized_collection.parallel_scan(2, session: session)
2960
- end
2961
-
2962
- let(:operation) do
2963
- cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
2964
- end
2965
-
2966
- let(:failed_operation) do
2967
- authorized_collection.parallel_scan(-2, session: session)
2968
- end
2969
-
2970
- let(:client) do
2971
- authorized_client
2972
- end
2973
-
2974
- it_behaves_like 'an operation using a session'
2975
- it_behaves_like 'a failed operation using a session'
2976
- end
2977
-
2978
- context 'when a session is not provided' do
2979
- let(:collection) { client['test'] }
2980
-
2981
- let(:cursors) do
2982
- collection.parallel_scan(2)
2983
- end
2984
-
2985
- let(:operation) do
2986
- cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
2987
- end
2988
-
2989
- let(:failed_operation) do
2990
- collection.parallel_scan(-2)
2991
- end
2992
-
2993
- let(:command) do
2994
- operation
2995
- event = subscriber.started_events.find { |cmd| cmd.command_name == 'parallelCollectionScan' }
2996
- expect(event).not_to be_nil
2997
- event.command
2998
- end
2999
-
3000
- it_behaves_like 'an operation not using a session'
3001
- it_behaves_like 'a failed operation not using a session'
3002
- end
3003
-
3004
- context 'when a session supporting causal consistency is used' do
3005
- require_wired_tiger
3006
-
3007
- let(:cursors) do
3008
- collection.parallel_scan(2, session: session)
3009
- end
3010
-
3011
- let(:operation) do
3012
- cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
3013
- end
3014
-
3015
- let(:command) do
3016
- operation
3017
- event = subscriber.started_events.find { |cmd| cmd.command_name == 'parallelCollectionScan' }
3018
- expect(event).not_to be_nil
3019
- event.command
3020
- end
3021
-
3022
- it_behaves_like 'an operation supporting causally consistent reads'
3023
- end
3024
-
3025
- context 'when a read concern is provided' do
3026
- require_wired_tiger
3027
- min_server_fcv '3.2'
3028
-
3029
- let(:result) do
3030
- authorized_collection.with(options).parallel_scan(2)
3031
- end
3032
-
3033
- context 'when the read concern is valid' do
3034
-
3035
- let(:options) do
3036
- { read_concern: { level: 'local' }}
3037
- end
3038
-
3039
- it 'sends the read concern' do
3040
- expect { result }.to_not raise_error
3041
- end
3042
- end
3043
-
3044
- context 'when the read concern is not valid' do
3045
-
3046
- let(:options) do
3047
- { read_concern: { level: 'idontknow' }}
3048
- end
3049
-
3050
- it 'raises an exception' do
3051
- expect {
3052
- result
3053
- }.to raise_error(Mongo::Error::OperationFailure)
3054
- end
3055
- end
3056
- end
3057
-
3058
- context 'when the collection has a read preference' do
3059
- require_topology :single, :replica_set
3060
-
3061
- before do
3062
- allow(collection.client.cluster).to receive(:single?).and_return(false)
3063
- end
3064
-
3065
- let(:client) do
3066
- authorized_client.with(server_selection_timeout: 0.2)
3067
- end
3068
-
3069
- let(:collection) do
3070
- client[authorized_collection.name,
3071
- read: { :mode => :secondary, :tag_sets => [{ 'non' => 'existent' }] }]
3072
- end
3073
-
3074
- let(:result) do
3075
- collection.parallel_scan(2)
3076
- end
3077
-
3078
- it 'uses that read preference' do
3079
- expect {
3080
- result
3081
- }.to raise_exception(Mongo::Error::NoServerAvailable)
3082
- end
3083
- end
3084
-
3085
- context 'when a max time ms value is provided' do
3086
- require_topology :single, :replica_set
3087
-
3088
- let(:result) do
3089
- authorized_collection.parallel_scan(2, options)
3090
- end
3091
-
3092
- context 'when the read concern is valid' do
3093
-
3094
- let(:options) do
3095
- { max_time_ms: 5 }
3096
- end
3097
-
3098
- it 'sends the max time ms value' do
3099
- expect { result }.to_not raise_error
3100
- end
3101
- end
3102
-
3103
- context 'when the max time ms is not valid' do
3104
-
3105
- let(:options) do
3106
- { max_time_ms: 0.1 }
3107
- end
3108
-
3109
- it 'raises an exception' do
3110
- expect {
3111
- result
3112
- }.to raise_error(Mongo::Error::OperationFailure)
3113
- end
3114
- end
3115
- end
3116
- end
3117
-
3118
- describe '#replace_one' do
3119
-
3120
- let(:selector) do
3121
- { field: 'test1' }
3122
- end
3123
-
3124
- context 'when a selector was provided' do
3125
-
3126
- before do
3127
- authorized_collection.insert_many([{ field: 'test1' }, { field: 'test1' }])
3128
- end
3129
-
3130
- let!(:response) do
3131
- authorized_collection.replace_one(selector, { field: 'testing' })
3132
- end
3133
-
3134
- let(:updated) do
3135
- authorized_collection.find(field: 'testing').first
3136
- end
3137
-
3138
- it 'updates the first matching document in the collection' do
3139
- expect(response.modified_count).to eq(1)
3140
- end
3141
-
3142
- it 'updates the documents in the collection' do
3143
- expect(updated[:field]).to eq('testing')
3144
- end
3145
- end
3146
-
3147
- context 'when upsert is false' do
3148
-
3149
- let!(:response) do
3150
- authorized_collection.replace_one(selector, { field: 'test1' }, upsert: false)
3151
- end
3152
-
3153
- let(:updated) do
3154
- authorized_collection.find(field: 'test1').to_a
3155
- end
3156
-
3157
- it 'reports that no documents were written' do
3158
- expect(response.modified_count).to eq(0)
3159
- end
3160
-
3161
- it 'does not insert the document' do
3162
- expect(updated).to be_empty
3163
- end
3164
- end
3165
-
3166
- context 'when upsert is true' do
3167
-
3168
- let!(:response) do
3169
- authorized_collection.replace_one(selector, { field: 'test1' }, upsert: true)
3170
- end
3171
-
3172
- let(:updated) do
3173
- authorized_collection.find(field: 'test1').first
3174
- end
3175
-
3176
- it 'reports that a document was written' do
3177
- expect(response.written_count).to eq(1)
3178
- end
3179
-
3180
- it 'inserts the document' do
3181
- expect(updated[:field]).to eq('test1')
3182
- end
3183
- end
3184
-
3185
- context 'when upsert is not specified' do
3186
-
3187
- let!(:response) do
3188
- authorized_collection.replace_one(selector, { field: 'test1' })
3189
- end
3190
-
3191
- let(:updated) do
3192
- authorized_collection.find(field: 'test1').to_a
3193
- end
3194
-
3195
- it 'reports that no documents were written' do
3196
- expect(response.modified_count).to eq(0)
3197
- end
3198
-
3199
- it 'does not insert the document' do
3200
- expect(updated).to be_empty
3201
- end
3202
- end
3203
-
3204
- context 'when the replace fails' do
3205
-
3206
- let(:result) do
3207
- authorized_collection.replace_one(selector, { '$s' => 'test1' })
3208
- end
3209
-
3210
- it 'raises an OperationFailure' do
3211
- expect {
3212
- result
3213
- }.to raise_exception(Mongo::Error::OperationFailure)
3214
- end
3215
- end
3216
-
3217
- context 'when collection has a validator' do
3218
- min_server_fcv '3.2'
3219
-
3220
- around(:each) do |spec|
3221
- authorized_client[:validating,
3222
- :validator => { :a => { '$exists' => true } }].tap do |c|
3223
- c.create
3224
- end
3225
- spec.run
3226
- collection_with_validator.drop
3227
- end
3228
-
3229
- before do
3230
- collection_with_validator.insert_one({ a: 1 })
3231
- end
3232
-
3233
- context 'when the document is valid' do
3234
-
3235
- let(:result) do
3236
- collection_with_validator.replace_one({ a: 1 }, { a: 5 })
3237
- end
3238
-
3239
- it 'replaces successfully' do
3240
- expect(result.modified_count).to eq(1)
3241
- end
3242
- end
3243
-
3244
- context 'when the document is invalid' do
3245
-
3246
- context 'when bypass_document_validation is not set' do
3247
-
3248
- let(:result2) do
3249
- collection_with_validator.replace_one({ a: 1 }, { x: 5 })
3250
- end
3251
-
3252
- it 'raises OperationFailure' do
3253
- expect {
3254
- result2
3255
- }.to raise_exception(Mongo::Error::OperationFailure)
3256
- end
3257
- end
3258
-
3259
- context 'when bypass_document_validation is true' do
3260
-
3261
- let(:result3) do
3262
- collection_with_validator.replace_one(
3263
- { a: 1 }, { x: 1 }, :bypass_document_validation => true)
3264
- end
3265
-
3266
- it 'replaces successfully' do
3267
- expect(result3.written_count).to eq(1)
3268
- end
3269
- end
3270
- end
3271
- end
3272
-
3273
- context 'when a collation is specified' do
3274
-
3275
- let(:selector) do
3276
- { name: 'BANG' }
3277
- end
3278
-
3279
- let(:result) do
3280
- authorized_collection.replace_one(selector, { name: 'doink' }, options)
3281
- end
3282
-
3283
- before do
3284
- authorized_collection.insert_one(name: 'bang')
3285
- end
3286
-
3287
- let(:options) do
3288
- { collation: { locale: 'en_US', strength: 2 } }
3289
- end
3290
-
3291
- context 'when the server selected supports collations' do
3292
- min_server_fcv '3.4'
3293
-
3294
- it 'applies the collation' do
3295
- expect(result.written_count).to eq(1)
3296
- expect(authorized_collection.find(name: 'doink').count).to eq(1)
3297
- end
3298
-
3299
- context 'when unacknowledged writes is used' do
3300
-
3301
- let(:collection_with_unacknowledged_write_concern) do
3302
- authorized_collection.with(write: { w: 0 })
3303
- end
3304
-
3305
- let(:result) do
3306
- collection_with_unacknowledged_write_concern.replace_one(selector, { name: 'doink' }, options)
3307
- end
3308
-
3309
- it 'raises an exception' do
3310
- expect {
3311
- result
3312
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
3313
- end
3314
-
3315
- context 'when a String key is used' do
3316
-
3317
- let(:options) do
3318
- { 'collation' => { locale: 'en_US', strength: 2 } }
3319
- end
3320
-
3321
- it 'raises an exception' do
3322
- expect {
3323
- result
3324
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
3325
- end
3326
- end
3327
- end
3328
- end
3329
-
3330
- context 'when the server selected does not support collations' do
3331
- max_server_version '3.2'
3332
-
3333
- it 'raises an exception' do
3334
- expect {
3335
- result
3336
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
3337
- end
3338
-
3339
- context 'when a String key is used' do
3340
-
3341
- let(:options) do
3342
- { 'collation' => { locale: 'en_US', strength: 2 } }
3343
- end
3344
-
3345
- it 'raises an exception' do
3346
- expect {
3347
- result
3348
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
3349
- end
3350
- end
3351
- end
3352
- end
3353
-
3354
- context 'when a collation is not specified' do
3355
-
3356
- let(:selector) do
3357
- { name: 'BANG' }
3358
- end
3359
-
3360
- let(:result) do
3361
- authorized_collection.replace_one(selector, { name: 'doink' })
3362
- end
3363
-
3364
- before do
3365
- authorized_collection.insert_one(name: 'bang')
3366
- end
3367
-
3368
- it 'does not apply the collation' do
3369
- expect(result.written_count).to eq(0)
3370
- expect(authorized_collection.find(name: 'bang').count).to eq(1)
3371
- end
3372
- end
3373
-
3374
- context 'when a session is provided' do
3375
-
3376
- let(:selector) do
3377
- { name: 'BANG' }
3378
- end
3379
-
3380
- before do
3381
- authorized_collection.insert_one(name: 'bang')
3382
- end
3383
-
3384
- let(:session) do
3385
- authorized_client.start_session
3386
- end
3387
-
3388
- let(:operation) do
3389
- authorized_collection.replace_one(selector, { name: 'doink' }, session: session)
3390
- end
3391
-
3392
- let(:failed_operation) do
3393
- authorized_collection.replace_one({ '$._id' => 1 }, { name: 'doink' }, session: session)
3394
- end
3395
-
3396
- let(:client) do
3397
- authorized_client
3398
- end
3399
-
3400
- it_behaves_like 'an operation using a session'
3401
- it_behaves_like 'a failed operation using a session'
3402
- end
3403
-
3404
- context 'when unacknowledged writes is used with an explicit session' do
3405
-
3406
- let(:collection_with_unacknowledged_write_concern) do
3407
- authorized_collection.with(write: { w: 0 })
3408
- end
3409
-
3410
- let(:operation) do
3411
- collection_with_unacknowledged_write_concern.replace_one({ a: 1 }, { x: 5 }, session: session)
3412
- end
3413
-
3414
- it_behaves_like 'an explicit session with an unacknowledged write'
3415
- end
3416
-
3417
- context 'when unacknowledged writes is used with an implicit session' do
3418
-
3419
- let(:collection_with_unacknowledged_write_concern) do
3420
- client.with(write: { w: 0 })[TEST_COLL]
3421
- end
3422
-
3423
- let(:operation) do
3424
- collection_with_unacknowledged_write_concern.replace_one({ a: 1 }, { x: 5 })
3425
- end
3426
-
3427
- it_behaves_like 'an implicit session with an unacknowledged write'
3428
- end
3429
-
3430
- context 'when various options passed in' do
3431
- # w: 2 requires a replica set
3432
- require_topology :replica_set
3433
-
3434
- # https://jira.mongodb.org/browse/RUBY-2306
3435
- min_server_fcv '3.6'
3436
-
3437
- before do
3438
- authorized_collection.insert_one({field: 'test1'})
3439
- end
3440
-
3441
- let(:session) do
3442
- authorized_client.start_session
3443
- end
3444
-
3445
- let(:events) do
3446
- subscriber.command_started_events('update')
3447
- end
3448
-
3449
- let(:collection) do
3450
- authorized_collection.with(write_concern: {w: 3})
3451
- end
3452
-
3453
- let(:updated) do
3454
- collection.find(field: 'test4').first
3455
- end
3456
-
3457
- let!(:command) do
3458
- Utils.get_command_event(authorized_client, 'update') do |client|
3459
- collection.replace_one(selector, { field: 'test4'},
3460
- session: session, :return_document => :after, write_concern: {w: 2},
3461
- upsert: true, bypass_document_validation: true)
3462
- end.command
3463
- end
3464
-
3465
- it 'replaced one successfully with correct options sent to server' do
3466
- expect(updated[:field]).to eq('test4')
3467
- expect(events.length).to eq(1)
3468
- expect(command[:writeConcern]).to_not be_nil
3469
- expect(command[:writeConcern][:w]).to eq(2)
3470
- expect(command[:bypassDocumentValidation]).to be(true)
3471
- expect(command[:updates][0][:upsert]).to be(true)
3472
- end
3473
- end
3474
- end
3475
-
3476
- describe '#update_many' do
3477
-
3478
- let(:selector) do
3479
- { field: 'test' }
3480
- end
3481
-
3482
- context 'when a selector was provided' do
3483
-
3484
- before do
3485
- authorized_collection.insert_many([{ field: 'test' }, { field: 'test' }])
3486
- end
3487
-
3488
- let!(:response) do
3489
- authorized_collection.update_many(selector, '$set'=> { field: 'testing' })
3490
- end
3491
-
3492
- let(:updated) do
3493
- authorized_collection.find(field: 'testing').to_a.last
3494
- end
3495
-
3496
- it 'returns the number updated' do
3497
- expect(response.modified_count).to eq(2)
3498
- end
3499
-
3500
- it 'updates the documents in the collection' do
3501
- expect(updated[:field]).to eq('testing')
3502
- end
3503
- end
3504
-
3505
- context 'when upsert is false' do
3506
-
3507
- let(:response) do
3508
- authorized_collection.update_many(selector, { '$set'=> { field: 'testing' } },
3509
- upsert: false)
3510
- end
3511
-
3512
- let(:updated) do
3513
- authorized_collection.find.to_a
3514
- end
3515
-
3516
- it 'reports that no documents were updated' do
3517
- expect(response.modified_count).to eq(0)
3518
- end
3519
-
3520
- it 'updates no documents in the collection' do
3521
- expect(updated).to be_empty
3522
- end
3523
- end
3524
-
3525
- context 'when upsert is true' do
3526
-
3527
- let!(:response) do
3528
- authorized_collection.update_many(selector, { '$set'=> { field: 'testing' } },
3529
- upsert: true)
3530
- end
3531
-
3532
- let(:updated) do
3533
- authorized_collection.find.to_a.last
3534
- end
3535
-
3536
- it 'reports that a document was written' do
3537
- expect(response.written_count).to eq(1)
3538
- end
3539
-
3540
- it 'inserts a document into the collection' do
3541
- expect(updated[:field]).to eq('testing')
3542
- end
3543
- end
3544
-
3545
- context 'when upsert is not specified' do
3546
-
3547
- let(:response) do
3548
- authorized_collection.update_many(selector, { '$set'=> { field: 'testing' } })
3549
- end
3550
-
3551
- let(:updated) do
3552
- authorized_collection.find.to_a
3553
- end
3554
-
3555
- it 'reports that no documents were updated' do
3556
- expect(response.modified_count).to eq(0)
3557
- end
3558
-
3559
- it 'updates no documents in the collection' do
3560
- expect(updated).to be_empty
3561
- end
3562
- end
3563
-
3564
- context 'when arrayFilters is provided' do
3565
-
3566
- let(:selector) do
3567
- { '$or' => [{ _id: 0 }, { _id: 1 }]}
3568
- end
3569
-
3570
- context 'when the server supports arrayFilters' do
3571
- min_server_fcv '3.6'
3572
-
3573
- before do
3574
- authorized_collection.insert_many([{
3575
- _id: 0, x: [
3576
- { y: 1 },
3577
- { y: 2 },
3578
- { y: 3 }
3579
- ]
3580
- },
3581
- {
3582
- _id: 1,
3583
- x: [
3584
- { y: 3 },
3585
- { y: 2 },
3586
- { y: 1 }
3587
- ]
3588
- }])
3589
- end
3590
-
3591
- let(:result) do
3592
- authorized_collection.update_many(selector,
3593
- { '$set' => { 'x.$[i].y' => 5 } },
3594
- options)
3595
- end
3596
-
3597
- context 'when a Symbol key is used' do
3598
-
3599
- let(:options) do
3600
- { array_filters: [{ 'i.y' => 3 }] }
3601
- end
3602
-
3603
- it 'applies the arrayFilters' do
3604
- expect(result.matched_count).to eq(2)
3605
- expect(result.modified_count).to eq(2)
3606
-
3607
- docs = authorized_collection.find(selector, sort: { _id: 1 }).to_a
3608
- expect(docs[0]['x']).to eq ([{ 'y' => 1 }, { 'y' => 2 }, { 'y' => 5 }])
3609
- expect(docs[1]['x']).to eq ([{ 'y' => 5 }, { 'y' => 2 }, { 'y' => 1 }])
3610
- end
3611
- end
3612
-
3613
- context 'when a String key is used' do
3614
- let(:options) do
3615
- { 'array_filters' => [{ 'i.y' => 3 }] }
3616
- end
3617
-
3618
- it 'applies the arrayFilters' do
3619
- expect(result.matched_count).to eq(2)
3620
- expect(result.modified_count).to eq(2)
3621
-
3622
- docs = authorized_collection.find({}, sort: { _id: 1 }).to_a
3623
- expect(docs[0]['x']).to eq ([{ 'y' => 1 }, { 'y' => 2 }, { 'y' => 5 }])
3624
- expect(docs[1]['x']).to eq ([{ 'y' => 5 }, { 'y' => 2 }, { 'y' => 1 }])
3625
- end
3626
- end
3627
- end
3628
-
3629
- context 'when the server does not support arrayFilters' do
3630
- max_server_version '3.4'
3631
-
3632
- let(:result) do
3633
- authorized_collection.update_many(selector,
3634
- { '$set' => { 'x.$[i].y' => 5 } },
3635
- options)
3636
- end
3637
-
3638
- context 'when a Symbol key is used' do
3639
-
3640
- let(:options) do
3641
- { array_filters: [{ 'i.y' => 3 }] }
3642
- end
3643
-
3644
- it 'raises an exception' do
3645
- expect {
3646
- result
3647
- }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
3648
- end
3649
- end
3650
-
3651
- context 'when a String key is used' do
3652
-
3653
- let(:options) do
3654
- { 'array_filters' => [{ 'i.y' => 3 }] }
3655
- end
3656
-
3657
- it 'raises an exception' do
3658
- expect {
3659
- result
3660
- }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
3661
- end
3662
- end
3663
- end
3664
- end
3665
-
3666
- context 'when the updates fail' do
3667
-
3668
- let(:result) do
3669
- authorized_collection.update_many(selector, { '$s'=> { field: 'testing' } })
3670
- end
3671
-
3672
- it 'raises an OperationFailure' do
3673
- expect {
3674
- result
3675
- }.to raise_exception(Mongo::Error::OperationFailure)
3676
- end
3677
- end
3678
-
3679
- context 'when collection has a validator' do
3680
- min_server_fcv '3.2'
3681
-
3682
- around(:each) do |spec|
3683
- authorized_client[:validating,
3684
- :validator => { :a => { '$exists' => true } }].tap do |c|
3685
- c.create
3686
- end
3687
- spec.run
3688
- collection_with_validator.drop
3689
- end
3690
-
3691
- before do
3692
- collection_with_validator.insert_many([{ a: 1 }, { a: 2 }])
3693
- end
3694
-
3695
- context 'when the document is valid' do
3696
-
3697
- let(:result) do
3698
- collection_with_validator.update_many(
3699
- { :a => { '$gt' => 0 } }, '$inc' => { :a => 1 } )
3700
- end
3701
-
3702
- it 'updates successfully' do
3703
- expect(result.modified_count).to eq(2)
3704
- end
3705
- end
3706
-
3707
- context 'when the document is invalid' do
3708
-
3709
- context 'when bypass_document_validation is not set' do
3710
-
3711
- let(:result2) do
3712
- collection_with_validator.update_many(
3713
- { :a => { '$gt' => 0 } }, '$unset' => { :a => '' })
3714
- end
3715
-
3716
- it 'raises OperationFailure' do
3717
- expect {
3718
- result2
3719
- }.to raise_exception(Mongo::Error::OperationFailure)
3720
- end
3721
- end
3722
-
3723
- context 'when bypass_document_validation is true' do
3724
-
3725
- let(:result3) do
3726
- collection_with_validator.update_many(
3727
- { :a => { '$gt' => 0 } }, { '$unset' => { :a => '' } },
3728
- :bypass_document_validation => true)
3729
- end
3730
-
3731
- it 'updates successfully' do
3732
- expect(result3.written_count).to eq(2)
3733
- end
3734
- end
3735
- end
3736
- end
3737
-
3738
- context 'when a collation is specified' do
3739
-
3740
- let(:selector) do
3741
- { name: 'BANG' }
3742
- end
3743
-
3744
- let(:result) do
3745
- authorized_collection.update_many(selector, { '$set' => { other: 'doink' } }, options)
3746
- end
3747
-
3748
- before do
3749
- authorized_collection.insert_one(name: 'bang')
3750
- authorized_collection.insert_one(name: 'baNG')
3751
- end
3752
-
3753
- let(:options) do
3754
- { collation: { locale: 'en_US', strength: 2 } }
3755
- end
3756
-
3757
- context 'when the server selected supports collations' do
3758
- min_server_fcv '3.4'
3759
-
3760
- it 'applies the collation' do
3761
- expect(result.written_count).to eq(2)
3762
- expect(authorized_collection.find(other: 'doink').count).to eq(2)
3763
- end
3764
-
3765
- context 'when unacknowledged writes is used' do
3766
-
3767
- let(:collection_with_unacknowledged_write_concern) do
3768
- authorized_collection.with(write: { w: 0 })
3769
- end
3770
-
3771
- let(:result) do
3772
- collection_with_unacknowledged_write_concern.update_many(selector, { '$set' => { other: 'doink' } }, options)
3773
- end
3774
-
3775
- it 'raises an exception' do
3776
- expect {
3777
- result
3778
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
3779
- end
3780
-
3781
- context 'when a String key is used' do
3782
-
3783
- let(:options) do
3784
- { 'collation' => { locale: 'en_US', strength: 2 } }
3785
- end
3786
-
3787
- it 'raises an exception' do
3788
- expect {
3789
- result
3790
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
3791
- end
3792
- end
3793
- end
3794
- end
3795
-
3796
- context 'when the server selected does not support collations' do
3797
- max_server_version '3.2'
3798
-
3799
- it 'raises an exception' do
3800
- expect {
3801
- result
3802
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
3803
- end
3804
-
3805
- context 'when a String key is used' do
3806
-
3807
- let(:options) do
3808
- { 'collation' => { locale: 'en_US', strength: 2 } }
3809
- end
3810
-
3811
- it 'raises an exception' do
3812
- expect {
3813
- result
3814
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
3815
- end
3816
- end
3817
- end
3818
- end
3819
-
3820
- context 'when collation is not specified' do
3821
-
3822
- let(:selector) do
3823
- {name: 'BANG'}
3824
- end
3825
-
3826
- let(:result) do
3827
- authorized_collection.update_many(selector, { '$set' => {other: 'doink'} })
3828
- end
3829
-
3830
- before do
3831
- authorized_collection.insert_one(name: 'bang')
3832
- authorized_collection.insert_one(name: 'baNG')
3833
- end
3834
-
3835
- it 'does not apply the collation' do
3836
- expect(result.written_count).to eq(0)
3837
- end
3838
- end
3839
-
3840
- context 'when a session is provided' do
3841
-
3842
- let(:selector) do
3843
- { name: 'BANG' }
3844
- end
3845
-
3846
- let(:operation) do
3847
- authorized_collection.update_many(selector, { '$set' => {other: 'doink'} }, session: session)
3848
- end
3849
-
3850
- before do
3851
- authorized_collection.insert_one(name: 'bang')
3852
- authorized_collection.insert_one(name: 'baNG')
3853
- end
3854
-
3855
- let(:session) do
3856
- authorized_client.start_session
3857
- end
3858
-
3859
- let(:failed_operation) do
3860
- authorized_collection.update_many({ '$._id' => 1 }, { '$set' => {other: 'doink'} }, session: session)
3861
- end
3862
-
3863
- let(:client) do
3864
- authorized_client
3865
- end
3866
-
3867
- it_behaves_like 'an operation using a session'
3868
- it_behaves_like 'a failed operation using a session'
3869
- end
3870
-
3871
- context 'when unacknowledged writes is used with an explicit session' do
3872
-
3873
- let(:collection_with_unacknowledged_write_concern) do
3874
- authorized_collection.with(write: { w: 0 })
3875
- end
3876
-
3877
- let(:operation) do
3878
- collection_with_unacknowledged_write_concern.update_many({a: 1}, { '$set' => {x: 1} }, session: session)
3879
- end
3880
-
3881
- it_behaves_like 'an explicit session with an unacknowledged write'
3882
- end
3883
-
3884
- context 'when unacknowledged writes is used with an implicit session' do
3885
-
3886
- let(:collection_with_unacknowledged_write_concern) do
3887
- client.with(write: { w: 0 })[TEST_COLL]
3888
- end
3889
-
3890
- let(:operation) do
3891
- collection_with_unacknowledged_write_concern.update_many({a: 1}, {'$set' => {x: 1}})
3892
- end
3893
-
3894
- it_behaves_like 'an implicit session with an unacknowledged write'
3895
- end
3896
-
3897
- context 'when various options passed in' do
3898
- # w: 2 requires a replica set
3899
- require_topology :replica_set
3900
-
3901
- # https://jira.mongodb.org/browse/RUBY-2306
3902
- min_server_fcv '3.6'
3903
-
3904
- before do
3905
- collection.insert_many([{ field: 'test' }, { field: 'test2' }], session: session)
3906
- end
3907
-
3908
- let(:session) do
3909
- authorized_client.start_session
3910
- end
3911
-
3912
- let(:collection) do
3913
- authorized_collection.with(write_concern: {w: 1})
3914
- end
3915
-
3916
- let(:events) do
3917
- subscriber.command_started_events('update')
3918
- end
3919
-
3920
- let!(:command) do
3921
- Utils.get_command_event(authorized_client, 'update') do |client|
3922
- collection.update_many(selector, {'$set'=> { field: 'testing' }}, session: session,
3923
- write_concern: {w: 2}, bypass_document_validation: true, upsert: true)
3924
- end.command
3925
- end
3926
-
3927
- it 'updates many successfully with correct options sent to server' do
3928
- expect(events.length).to eq(1)
3929
- expect(collection.options[:write_concern]).to eq(w: 1)
3930
- expect(command[:writeConcern][:w]).to eq(2)
3931
- expect(command[:bypassDocumentValidation]).to be(true)
3932
- expect(command[:updates][0][:upsert]).to be(true)
3933
- end
3934
- end
3935
- end
3936
-
3937
- describe '#update_one' do
3938
-
3939
- let(:selector) do
3940
- { field: 'test1' }
3941
- end
3942
-
3943
- context 'when a selector was provided' do
3944
-
3945
- before do
3946
- authorized_collection.insert_many([{ field: 'test1' }, { field: 'test1' }])
3947
- end
3948
-
3949
- let!(:response) do
3950
- authorized_collection.update_one(selector, '$set'=> { field: 'testing' })
3951
- end
3952
-
3953
- let(:updated) do
3954
- authorized_collection.find(field: 'testing').first
3955
- end
3956
-
3957
- it 'updates the first matching document in the collection' do
3958
- expect(response.modified_count).to eq(1)
3959
- end
3960
-
3961
- it 'updates the documents in the collection' do
3962
- expect(updated[:field]).to eq('testing')
3963
- end
3964
- end
3965
-
3966
- context 'when upsert is false' do
3967
-
3968
- let(:response) do
3969
- authorized_collection.update_one(selector, { '$set'=> { field: 'testing' } },
3970
- upsert: false)
3971
- end
3972
-
3973
- let(:updated) do
3974
- authorized_collection.find.to_a
3975
- end
3976
-
3977
- it 'reports that no documents were updated' do
3978
- expect(response.modified_count).to eq(0)
3979
- end
3980
-
3981
- it 'updates no documents in the collection' do
3982
- expect(updated).to be_empty
3983
- end
3984
- end
3985
-
3986
- context 'when upsert is true' do
3987
-
3988
- let!(:response) do
3989
- authorized_collection.update_one(selector, { '$set'=> { field: 'testing' } },
3990
- upsert: true)
3991
- end
3992
-
3993
- let(:updated) do
3994
- authorized_collection.find.first
3995
- end
3996
-
3997
- it 'reports that a document was written' do
3998
- expect(response.written_count).to eq(1)
3999
- end
4000
-
4001
- it 'inserts a document into the collection' do
4002
- expect(updated[:field]).to eq('testing')
4003
- end
4004
- end
4005
-
4006
- context 'when upsert is not specified' do
4007
-
4008
- let(:response) do
4009
- authorized_collection.update_one(selector, { '$set'=> { field: 'testing' } })
4010
- end
4011
-
4012
- let(:updated) do
4013
- authorized_collection.find.to_a
4014
- end
4015
-
4016
- it 'reports that no documents were updated' do
4017
- expect(response.modified_count).to eq(0)
4018
- end
4019
-
4020
- it 'updates no documents in the collection' do
4021
- expect(updated).to be_empty
4022
- end
4023
- end
4024
-
4025
- context 'when the update fails' do
4026
-
4027
- let(:result) do
4028
- authorized_collection.update_one(selector, { '$s'=> { field: 'testing' } })
4029
- end
4030
-
4031
- it 'raises an OperationFailure' do
4032
- expect {
4033
- result
4034
- }.to raise_exception(Mongo::Error::OperationFailure)
4035
- end
4036
- end
4037
-
4038
- context 'when collection has a validator' do
4039
- min_server_fcv '3.2'
4040
-
4041
- around(:each) do |spec|
4042
- authorized_client[:validating,
4043
- :validator => { :a => { '$exists' => true } }].tap do |c|
4044
- c.create
4045
- end
4046
- spec.run
4047
- collection_with_validator.drop
4048
- end
4049
-
4050
- before do
4051
- collection_with_validator.insert_one({ a: 1 })
4052
- end
4053
-
4054
- context 'when the document is valid' do
4055
-
4056
- let(:result) do
4057
- collection_with_validator.update_one(
4058
- { :a => { '$gt' => 0 } }, '$inc' => { :a => 1 } )
4059
- end
4060
-
4061
- it 'updates successfully' do
4062
- expect(result.modified_count).to eq(1)
4063
- end
4064
- end
4065
-
4066
- context 'when the document is invalid' do
4067
-
4068
- context 'when bypass_document_validation is not set' do
4069
-
4070
- let(:result2) do
4071
- collection_with_validator.update_one(
4072
- { :a => { '$gt' => 0 } }, '$unset' => { :a => '' })
4073
- end
4074
-
4075
- it 'raises OperationFailure' do
4076
- expect {
4077
- result2
4078
- }.to raise_exception(Mongo::Error::OperationFailure)
4079
- end
4080
- end
4081
-
4082
- context 'when bypass_document_validation is true' do
4083
-
4084
- let(:result3) do
4085
- collection_with_validator.update_one(
4086
- { :a => { '$gt' => 0 } }, { '$unset' => { :a => '' } },
4087
- :bypass_document_validation => true)
4088
- end
4089
-
4090
- it 'updates successfully' do
4091
- expect(result3.written_count).to eq(1)
4092
- end
4093
- end
4094
- end
4095
- end
4096
-
4097
- context 'when there is a collation specified' do
4098
-
4099
- let(:selector) do
4100
- { name: 'BANG' }
4101
- end
4102
-
4103
- let(:result) do
4104
- authorized_collection.update_one(selector, { '$set' => { other: 'doink' } }, options)
4105
- end
4106
-
4107
- before do
4108
- authorized_collection.insert_one(name: 'bang')
4109
- end
4110
-
4111
- let(:options) do
4112
- { collation: { locale: 'en_US', strength: 2 } }
4113
- end
4114
-
4115
- context 'when the server selected supports collations' do
4116
- min_server_fcv '3.4'
4117
-
4118
- it 'applies the collation' do
4119
- expect(result.written_count).to eq(1)
4120
- expect(authorized_collection.find(other: 'doink').count).to eq(1)
4121
- end
4122
-
4123
- context 'when unacknowledged writes is used' do
4124
-
4125
- let(:collection_with_unacknowledged_write_concern) do
4126
- authorized_collection.with(write: { w: 0 })
4127
- end
4128
-
4129
- let(:result) do
4130
- collection_with_unacknowledged_write_concern.update_one(selector, { '$set' => { other: 'doink' } }, options)
4131
- end
4132
-
4133
- it 'raises an exception' do
4134
- expect {
4135
- result
4136
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
4137
- end
4138
-
4139
- context 'when a String key is used' do
4140
-
4141
- let(:options) do
4142
- { 'collation' => { locale: 'en_US', strength: 2 } }
4143
- end
4144
-
4145
- it 'raises an exception' do
4146
- expect {
4147
- result
4148
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
4149
- end
4150
- end
4151
- end
4152
- end
4153
-
4154
- context 'when the server selected does not support collations' do
4155
- max_server_version '3.2'
4156
-
4157
- it 'raises an exception' do
4158
- expect {
4159
- result
4160
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
4161
- end
4162
-
4163
- context 'when a String key is used' do
4164
-
4165
- let(:options) do
4166
- { 'collation' => { locale: 'en_US', strength: 2 } }
4167
- end
4168
-
4169
- it 'raises an exception' do
4170
- expect {
4171
- result
4172
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
4173
- end
4174
- end
4175
- end
4176
- end
4177
-
4178
- context 'when a collation is not specified' do
4179
-
4180
- let(:selector) do
4181
- { name: 'BANG' }
4182
- end
4183
-
4184
- let(:result) do
4185
- authorized_collection.update_one(selector, { '$set' => { other: 'doink' } })
4186
- end
4187
-
4188
- before do
4189
- authorized_collection.insert_one(name: 'bang')
4190
- end
4191
-
4192
- it 'does not apply the collation' do
4193
- expect(result.written_count).to eq(0)
4194
- end
4195
- end
4196
-
4197
-
4198
- context 'when arrayFilters is provided' do
4199
-
4200
- let(:selector) do
4201
- { _id: 0}
4202
- end
4203
-
4204
- context 'when the server supports arrayFilters' do
4205
- min_server_fcv '3.6'
4206
-
4207
- before do
4208
- authorized_collection.insert_one(_id: 0, x: [{ y: 1 }, { y: 2 }, {y: 3 }])
4209
- end
4210
-
4211
- let(:result) do
4212
- authorized_collection.update_one(selector,
4213
- { '$set' => { 'x.$[i].y' => 5 } },
4214
- options)
4215
- end
4216
-
4217
- context 'when a Symbol key is used' do
4218
-
4219
- let(:options) do
4220
- { array_filters: [{ 'i.y' => 3 }] }
4221
- end
4222
-
4223
- it 'applies the arrayFilters' do
4224
- expect(result.matched_count).to eq(1)
4225
- expect(result.modified_count).to eq(1)
4226
- expect(authorized_collection.find(selector).first['x'].last['y']).to eq(5)
4227
- end
4228
- end
4229
-
4230
- context 'when a String key is used' do
4231
-
4232
- let(:options) do
4233
- { 'array_filters' => [{ 'i.y' => 3 }] }
4234
- end
4235
-
4236
- it 'applies the arrayFilters' do
4237
- expect(result.matched_count).to eq(1)
4238
- expect(result.modified_count).to eq(1)
4239
- expect(authorized_collection.find(selector).first['x'].last['y']).to eq(5)
4240
- end
4241
- end
4242
- end
4243
-
4244
- context 'when the server does not support arrayFilters' do
4245
- max_server_version '3.4'
4246
-
4247
- let(:result) do
4248
- authorized_collection.update_one(selector,
4249
- { '$set' => { 'x.$[i].y' => 5 } },
4250
- options)
4251
- end
4252
-
4253
- context 'when a Symbol key is used' do
4254
-
4255
- let(:options) do
4256
- { array_filters: [{ 'i.y' => 3 }] }
4257
- end
4258
-
4259
- it 'raises an exception' do
4260
- expect {
4261
- result
4262
- }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
4263
- end
4264
- end
4265
-
4266
- context 'when a String key is used' do
4267
-
4268
- let(:options) do
4269
- { 'array_filters' => [{ 'i.y' => 3 }] }
4270
- end
4271
-
4272
- it 'raises an exception' do
4273
- expect {
4274
- result
4275
- }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
4276
- end
4277
- end
4278
- end
4279
- end
4280
-
4281
- context 'when the documents are sent with OP_MSG' do
4282
- min_server_fcv '3.6'
4283
-
4284
- let(:documents) do
4285
- [{ '_id' => 1, 'name' => '1'*16777191 }, { '_id' => 'y' }]
4286
- end
4287
-
4288
- before do
4289
- authorized_collection.insert_many([{ field: 'test1' }, { field: 'test1' }])
4290
- client[TEST_COLL].update_one({ a: 1 }, {'$set' => { 'name' => '1'*16777149 }})
4291
- end
4292
-
4293
- let(:update_events) do
4294
- subscriber.started_events.select { |e| e.command_name == 'update' }
4295
- end
4296
-
4297
- it 'sends the documents in one OP_MSG' do
4298
- expect(update_events.size).to eq(1)
4299
- end
4300
- end
4301
-
4302
- context 'when a session is provided' do
4303
-
4304
- before do
4305
- authorized_collection.insert_many([{ field: 'test1' }, { field: 'test1' }])
4306
- end
4307
-
4308
- let(:session) do
4309
- authorized_client.start_session
4310
- end
4311
-
4312
- let(:operation) do
4313
- authorized_collection.update_one({ field: 'test' }, { '$set'=> { field: 'testing' } }, session: session)
4314
- end
4315
-
4316
- let(:failed_operation) do
4317
- authorized_collection.update_one({ '$._id' => 1 }, { '$set'=> { field: 'testing' } }, session: session)
4318
- end
4319
-
4320
- let(:client) do
4321
- authorized_client
4322
- end
4323
-
4324
- it_behaves_like 'an operation using a session'
4325
- it_behaves_like 'a failed operation using a session'
4326
- end
4327
-
4328
- context 'when unacknowledged writes is used with an explicit session' do
4329
-
4330
- let(:collection_with_unacknowledged_write_concern) do
4331
- authorized_collection.with(write: { w: 0 })
4332
- end
4333
-
4334
- let(:operation) do
4335
- collection_with_unacknowledged_write_concern.update_one({ a: 1 }, { '$set' => { x: 1 } }, session: session)
4336
- end
4337
-
4338
- it_behaves_like 'an explicit session with an unacknowledged write'
4339
- end
4340
-
4341
- context 'when unacknowledged writes is used with an implicit session' do
4342
-
4343
- let(:collection_with_unacknowledged_write_concern) do
4344
- client.with(write: { w: 0 })[TEST_COLL]
4345
- end
4346
-
4347
- let(:operation) do
4348
- collection_with_unacknowledged_write_concern.update_one({ a: 1 }, { '$set' => { x: 1 }})
4349
- end
4350
-
4351
- it_behaves_like 'an implicit session with an unacknowledged write'
4352
- end
4353
-
4354
- context 'when various options passed in' do
4355
- # w: 2 requires a replica set
4356
- require_topology :replica_set
4357
-
4358
- # https://jira.mongodb.org/browse/RUBY-2306
4359
- min_server_fcv '3.6'
4360
-
4361
- before do
4362
- collection.insert_many([{ field: 'test1' }, { field: 'test2' }], session: session)
4363
- end
4364
-
4365
- let(:session) do
4366
- authorized_client.start_session
4367
- end
4368
-
4369
- let(:collection) do
4370
- authorized_collection.with(write_concern: {w: 1})
4371
- end
4372
-
4373
- let(:events) do
4374
- subscriber.command_started_events('update')
4375
- end
4376
-
4377
- let!(:command) do
4378
- Utils.get_command_event(authorized_client, 'update') do |client|
4379
- collection.update_one(selector, { '$set'=> { field: 'testing' } }, session: session,
4380
- write_concern: {w: 2}, bypass_document_validation: true, :return_document => :after,
4381
- upsert: true)
4382
- end.command
4383
- end
4384
-
4385
- it 'updates one successfully with correct options sent to server' do
4386
- expect(events.length).to eq(1)
4387
- expect(command[:writeConcern]).to_not be_nil
4388
- expect(command[:writeConcern][:w]).to eq(2)
4389
- expect(collection.options[:write_concern]).to eq(w:1)
4390
- expect(command[:bypassDocumentValidation]).to be(true)
4391
- expect(command[:updates][0][:upsert]).to be(true)
4392
- end
4393
- end
4394
- end
4395
-
4396
- describe '#find_one_and_delete' do
4397
-
4398
- before do
4399
- authorized_collection.insert_many([{ field: 'test1' }])
4400
- end
4401
-
4402
- let(:selector) do
4403
- { field: 'test1' }
4404
- end
4405
-
4406
- context 'when a matching document is found' do
4407
-
4408
- context 'when a session is provided' do
4409
-
4410
- let(:operation) do
4411
- authorized_collection.find_one_and_delete(selector, session: session)
4412
- end
4413
-
4414
- let(:failed_operation) do
4415
- authorized_collection.find_one_and_delete({ '$._id' => 1 }, session: session)
4416
- end
4417
-
4418
- let(:session) do
4419
- authorized_client.start_session
4420
- end
4421
-
4422
- let(:client) do
4423
- authorized_client
4424
- end
4425
-
4426
- it_behaves_like 'an operation using a session'
4427
- it_behaves_like 'a failed operation using a session'
4428
- end
4429
-
4430
- context 'when no options are provided' do
4431
-
4432
- let!(:document) do
4433
- authorized_collection.find_one_and_delete(selector)
4434
- end
4435
-
4436
- it 'deletes the document from the database' do
4437
- expect(authorized_collection.find.to_a).to be_empty
4438
- end
4439
-
4440
- it 'returns the document' do
4441
- expect(document['field']).to eq('test1')
4442
- end
4443
- end
4444
-
4445
- context 'when a projection is provided' do
4446
-
4447
- let!(:document) do
4448
- authorized_collection.find_one_and_delete(selector, projection: { _id: 1 })
4449
- end
4450
-
4451
- it 'deletes the document from the database' do
4452
- expect(authorized_collection.find.to_a).to be_empty
4453
- end
4454
-
4455
- it 'returns the document with limited fields' do
4456
- expect(document['field']).to be_nil
4457
- expect(document['_id']).to_not be_nil
4458
- end
4459
- end
4460
-
4461
- context 'when a sort is provided' do
4462
-
4463
- let!(:document) do
4464
- authorized_collection.find_one_and_delete(selector, sort: { field: 1 })
4465
- end
4466
-
4467
- it 'deletes the document from the database' do
4468
- expect(authorized_collection.find.to_a).to be_empty
4469
- end
4470
-
4471
- it 'returns the document with limited fields' do
4472
- expect(document['field']).to eq('test1')
4473
- end
4474
- end
4475
-
4476
- context 'when max_time_ms is provided' do
4477
-
4478
- it 'includes the max_time_ms value in the command' do
4479
- expect {
4480
- authorized_collection.find_one_and_delete(selector, max_time_ms: 0.1)
4481
- }.to raise_error(Mongo::Error::OperationFailure)
4482
- end
4483
- end
4484
- end
4485
-
4486
- context 'when no matching document is found' do
4487
-
4488
- let(:selector) do
4489
- { field: 'test5' }
4490
- end
4491
-
4492
- let!(:document) do
4493
- authorized_collection.find_one_and_delete(selector)
4494
- end
4495
-
4496
- it 'returns nil' do
4497
- expect(document).to be_nil
4498
- end
4499
- end
4500
-
4501
- context 'when the operation fails' do
4502
-
4503
- let(:result) do
4504
- authorized_collection.find_one_and_delete(selector, max_time_ms: 0.1)
4505
- end
4506
-
4507
- it 'raises an OperationFailure' do
4508
- expect {
4509
- result
4510
- }.to raise_exception(Mongo::Error::OperationFailure)
4511
- end
4512
- end
4513
-
4514
- context 'when write_concern is provided' do
4515
- min_server_fcv '3.2'
4516
- require_topology :single
4517
-
4518
- it 'uses the write concern' do
4519
- expect {
4520
- authorized_collection.find_one_and_delete(selector,
4521
- write_concern: { w: 2 })
4522
- }.to raise_error(Mongo::Error::OperationFailure)
4523
- end
4524
- end
4525
-
4526
- context 'when the collection has a write concern' do
4527
- min_server_fcv '3.2'
4528
- require_topology :single
4529
-
4530
- let(:collection) do
4531
- authorized_collection.with(write: { w: 2 })
4532
- end
4533
-
4534
- it 'uses the write concern' do
4535
- expect {
4536
- collection.find_one_and_delete(selector,
4537
- write_concern: { w: 2 })
4538
- }.to raise_error(Mongo::Error::OperationFailure)
4539
- end
4540
- end
4541
-
4542
- context 'when collation is specified' do
4543
-
4544
- let(:selector) do
4545
- { name: 'BANG' }
4546
- end
4547
-
4548
- let(:result) do
4549
- authorized_collection.find_one_and_delete(selector, options)
4550
- end
4551
-
4552
- before do
4553
- authorized_collection.insert_one(name: 'bang')
4554
- end
4555
-
4556
- let(:options) do
4557
- { collation: { locale: 'en_US', strength: 2 } }
4558
- end
4559
-
4560
- context 'when the server selected supports collations' do
4561
- min_server_fcv '3.4'
4562
-
4563
- it 'applies the collation' do
4564
- expect(result['name']).to eq('bang')
4565
- expect(authorized_collection.find(name: 'bang').count).to eq(0)
4566
- end
4567
- end
4568
-
4569
- context 'when the server selected does not support collations' do
4570
- max_server_version '3.2'
4571
-
4572
- it 'raises an exception' do
4573
- expect {
4574
- result
4575
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
4576
- end
4577
-
4578
- context 'when a String key is used' do
4579
-
4580
- let(:options) do
4581
- { 'collation' => { locale: 'en_US', strength: 2 } }
4582
- end
4583
-
4584
- it 'raises an exception' do
4585
- expect {
4586
- result
4587
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
4588
- end
4589
- end
4590
- end
4591
- end
4592
-
4593
- context 'when collation is not specified' do
4594
-
4595
- let(:selector) do
4596
- { name: 'BANG' }
4597
- end
4598
-
4599
- let(:result) do
4600
- authorized_collection.find_one_and_delete(selector)
4601
- end
4602
-
4603
- before do
4604
- authorized_collection.insert_one(name: 'bang')
4605
- end
4606
-
4607
- it 'does not apply the collation' do
4608
- expect(result).to be_nil
4609
- end
4610
- end
4611
-
4612
- context 'when various options passed in' do
4613
- # w: 2 requires a replica set
4614
- require_topology :replica_set
4615
-
4616
- # https://jira.mongodb.org/browse/RUBY-2306
4617
- min_server_fcv '3.6'
4618
-
4619
- before do
4620
- authorized_collection.delete_many
4621
- authorized_collection.insert_many([{ name: 'test1' }, { name: 'test2' }])
4622
- end
4623
-
4624
- let(:collection) do
4625
- authorized_collection.with(write_concern: {w: 2})
4626
- end
4627
-
4628
- let(:session) do
4629
- authorized_client.start_session
4630
- end
4631
-
4632
- let!(:command) do
4633
- Utils.get_command_event(authorized_client, 'findAndModify') do |client|
4634
- collection.find_one_and_delete(selector, session: session, write_concern: {w: 2},
4635
- bypass_document_validation: true, max_time_ms: 300)
4636
- end.command
4637
- end
4638
-
4639
- let(:events) do
4640
- subscriber.command_started_events('findAndModify')
4641
- end
4642
-
4643
- it 'finds and deletes successfully with correct options sent to server' do
4644
- expect(events.length).to eq(1)
4645
- expect(command[:writeConcern]).to_not be_nil
4646
- expect(command[:writeConcern][:w]).to eq(2)
4647
- expect(command[:bypassDocumentValidation]).to eq(true)
4648
- expect(command[:maxTimeMS]).to eq(300)
4649
- end
4650
- end
4651
- end
4652
-
4653
- describe '#find_one_and_update' do
4654
-
4655
- let(:selector) do
4656
- { field: 'test1' }
4657
- end
4658
-
4659
- before do
4660
- authorized_collection.insert_many([{ field: 'test1' }])
4661
- end
4662
-
4663
- context 'when a matching document is found' do
4664
-
4665
- context 'when no options are provided' do
4666
-
4667
- let(:document) do
4668
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }})
4669
- end
4670
-
4671
- it 'returns the original document' do
4672
- expect(document['field']).to eq('test1')
4673
- end
4674
- end
4675
-
4676
- context 'when a session is provided' do
4677
-
4678
- let(:operation) do
4679
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, session: session)
4680
- end
4681
-
4682
- let(:failed_operation) do
4683
- authorized_collection.find_one_and_update({ '$._id' => 1 }, { '$set' => { field: 'testing' }}, session: session)
4684
- end
4685
-
4686
- let(:session) do
4687
- authorized_client.start_session
4688
- end
4689
-
4690
- let(:client) do
4691
- authorized_client
4692
- end
4693
-
4694
- it_behaves_like 'an operation using a session'
4695
- it_behaves_like 'a failed operation using a session'
4696
- end
4697
-
4698
- context 'when no options are provided' do
4699
-
4700
- let(:document) do
4701
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }})
4702
- end
4703
-
4704
- it 'returns the original document' do
4705
- expect(document['field']).to eq('test1')
4706
- end
4707
- end
4708
-
4709
- context 'when return_document options are provided' do
4710
-
4711
- context 'when return_document is :after' do
4712
-
4713
- let(:document) do
4714
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, :return_document => :after)
4715
- end
4716
-
4717
- it 'returns the new document' do
4718
- expect(document['field']).to eq('testing')
4719
- end
4720
- end
4721
-
4722
- context 'when return_document is :before' do
4723
-
4724
- let(:document) do
4725
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, :return_document => :before)
4726
- end
4727
-
4728
- it 'returns the original document' do
4729
- expect(document['field']).to eq('test1')
4730
- end
4731
- end
4732
- end
4733
-
4734
- context 'when a projection is provided' do
4735
-
4736
- let(:document) do
4737
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, projection: { _id: 1 })
4738
- end
4739
-
4740
- it 'returns the document with limited fields' do
4741
- expect(document['field']).to be_nil
4742
- expect(document['_id']).to_not be_nil
4743
- end
4744
- end
4745
-
4746
- context 'when a sort is provided' do
4747
-
4748
- let(:document) do
4749
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, sort: { field: 1 })
4750
- end
4751
-
4752
- it 'returns the original document' do
4753
- expect(document['field']).to eq('test1')
4754
- end
4755
- end
4756
- end
4757
-
4758
- context 'when max_time_ms is provided' do
4759
-
4760
- it 'includes the max_time_ms value in the command' do
4761
- expect {
4762
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, max_time_ms: 0.1)
4763
- }.to raise_error(Mongo::Error::OperationFailure)
4764
- end
4765
- end
4766
-
4767
- context 'when no matching document is found' do
4768
-
4769
- let(:selector) do
4770
- { field: 'test5' }
4771
- end
4772
-
4773
- let(:document) do
4774
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }})
4775
- end
4776
-
4777
- it 'returns nil' do
4778
- expect(document).to be_nil
4779
- end
4780
- end
4781
-
4782
- context 'when no matching document is found' do
4783
-
4784
- context 'when no upsert options are provided' do
4785
-
4786
- let(:selector) do
4787
- { field: 'test5' }
4788
- end
4789
-
4790
- let(:document) do
4791
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }})
4792
- end
4793
-
4794
- it 'returns nil' do
4795
- expect(document).to be_nil
4796
- end
4797
- end
4798
-
4799
- context 'when upsert options are provided' do
4800
-
4801
- let(:selector) do
4802
- { field: 'test5' }
4803
- end
4804
-
4805
- let(:document) do
4806
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, :upsert => true, :return_document => :after)
4807
- end
4808
-
4809
- it 'returns the new document' do
4810
- expect(document['field']).to eq('testing')
4811
- end
4812
- end
4813
- end
4814
-
4815
- context 'when the operation fails' do
4816
-
4817
- let(:result) do
4818
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, max_time_ms: 0.1)
4819
- end
4820
-
4821
- it 'raises an OperationFailure' do
4822
- expect {
4823
- result
4824
- }.to raise_exception(Mongo::Error::OperationFailure)
4825
- end
4826
- end
4827
-
4828
- context 'when collection has a validator' do
4829
- min_server_fcv '3.2'
4830
-
4831
- around(:each) do |spec|
4832
- authorized_client[:validating].drop
4833
- authorized_client[:validating,
4834
- :validator => { :a => { '$exists' => true } }].tap do |c|
4835
- c.create
4836
- end
4837
- spec.run
4838
- collection_with_validator.drop
4839
- end
4840
-
4841
- before do
4842
- collection_with_validator.insert_one({ a: 1 })
4843
- end
4844
-
4845
- context 'when the document is valid' do
4846
-
4847
- let(:result) do
4848
- collection_with_validator.find_one_and_update(
4849
- { a: 1 }, { '$inc' => { :a => 1 } }, :return_document => :after)
4850
- end
4851
-
4852
- it 'updates successfully' do
4853
- expect(result['a']).to eq(2)
4854
- end
4855
- end
4856
-
4857
- context 'when the document is invalid' do
4858
-
4859
- context 'when bypass_document_validation is not set' do
4860
-
4861
- let(:result2) do
4862
- collection_with_validator.find_one_and_update(
4863
- { a: 1 }, { '$unset' => { :a => '' } }, :return_document => :after)
4864
- end
4865
-
4866
- it 'raises OperationFailure' do
4867
- expect {
4868
- result2
4869
- }.to raise_exception(Mongo::Error::OperationFailure)
4870
- end
4871
- end
4872
-
4873
- context 'when bypass_document_validation is true' do
4874
-
4875
- let(:result3) do
4876
- collection_with_validator.find_one_and_update(
4877
- { a: 1 }, { '$unset' => { :a => '' } },
4878
- :bypass_document_validation => true,
4879
- :return_document => :after)
4880
- end
4881
-
4882
- it 'updates successfully' do
4883
- expect(result3['a']).to be_nil
4884
- end
4885
- end
4886
- end
4887
- end
4888
-
4889
- context 'when write_concern is provided' do
4890
- min_server_fcv '3.2'
4891
- require_topology :single
4892
-
4893
- it 'uses the write concern' do
4894
- expect {
4895
- authorized_collection.find_one_and_update(selector,
4896
- { '$set' => { field: 'testing' }},
4897
- write_concern: { w: 2 })
4898
- }.to raise_error(Mongo::Error::OperationFailure)
4899
- end
4900
- end
4901
-
4902
- context 'when the collection has a write concern' do
4903
- min_server_fcv '3.2'
4904
- require_topology :single
4905
-
4906
- let(:collection) do
4907
- authorized_collection.with(write: { w: 2 })
4908
- end
4909
-
4910
- it 'uses the write concern' do
4911
- expect {
4912
- collection.find_one_and_update(selector,
4913
- { '$set' => { field: 'testing' }},
4914
- write_concern: { w: 2 })
4915
- }.to raise_error(Mongo::Error::OperationFailure)
4916
- end
4917
- end
4918
-
4919
- context 'when a collation is specified' do
4920
-
4921
- let(:selector) do
4922
- { name: 'BANG' }
4923
- end
4924
-
4925
- let(:result) do
4926
- authorized_collection.find_one_and_update(selector,
4927
- { '$set' => { other: 'doink' } },
4928
- options)
4929
- end
4930
-
4931
- before do
4932
- authorized_collection.insert_one(name: 'bang')
4933
- end
4934
-
4935
- let(:options) do
4936
- { collation: { locale: 'en_US', strength: 2 } }
4937
- end
4938
-
4939
- context 'when the server selected supports collations' do
4940
- min_server_fcv '3.4'
4941
-
4942
- it 'applies the collation' do
4943
- expect(result['name']).to eq('bang')
4944
- expect(authorized_collection.find({ name: 'bang' }, limit: -1).first['other']).to eq('doink')
4945
- end
4946
- end
4947
-
4948
- context 'when the server selected does not support collations' do
4949
- max_server_version '3.2'
4950
-
4951
- it 'raises an exception' do
4952
- expect {
4953
- result
4954
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
4955
- end
4956
-
4957
- context 'when a String key is used' do
4958
-
4959
- let(:options) do
4960
- { 'collation' => { locale: 'en_US', strength: 2 } }
4961
- end
4962
-
4963
- it 'raises an exception' do
4964
- expect {
4965
- result
4966
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
4967
- end
4968
- end
4969
- end
4970
- end
4971
-
4972
- context 'when there is no collation specified' do
4973
-
4974
- let(:selector) do
4975
- { name: 'BANG' }
4976
- end
4977
-
4978
- let(:result) do
4979
- authorized_collection.find_one_and_update(selector, { '$set' => { other: 'doink' } })
4980
- end
4981
-
4982
- before do
4983
- authorized_collection.insert_one(name: 'bang')
4984
- end
4985
-
4986
- it 'does not apply the collation' do
4987
- expect(result).to be_nil
4988
- end
4989
- end
4990
-
4991
- context 'when arrayFilters is provided' do
4992
-
4993
- let(:selector) do
4994
- { _id: 0 }
4995
- end
4996
-
4997
- context 'when the server supports arrayFilters' do
4998
- min_server_fcv '3.6'
4999
-
5000
- before do
5001
- authorized_collection.insert_one(_id: 0, x: [{ y: 1 }, { y: 2 }, { y: 3 }])
5002
- end
5003
-
5004
- let(:result) do
5005
- authorized_collection.find_one_and_update(selector,
5006
- { '$set' => { 'x.$[i].y' => 5 } },
5007
- options)
5008
- end
5009
-
5010
- context 'when a Symbol key is used' do
5011
-
5012
- let(:options) do
5013
- { array_filters: [{ 'i.y' => 3 }] }
5014
- end
5015
-
5016
-
5017
- it 'applies the arrayFilters' do
5018
- expect(result['x']).to eq([{ 'y' => 1 }, { 'y' => 2 }, { 'y' => 3 }])
5019
- expect(authorized_collection.find(selector).first['x'].last['y']).to eq(5)
5020
- end
5021
- end
5022
-
5023
- context 'when a String key is used' do
5024
-
5025
- let(:options) do
5026
- { 'array_filters' => [{ 'i.y' => 3 }] }
5027
- end
5028
-
5029
- it 'applies the arrayFilters' do
5030
- expect(result['x']).to eq([{ 'y' => 1 }, { 'y' => 2 }, { 'y' => 3 }])
5031
- expect(authorized_collection.find(selector).first['x'].last['y']).to eq(5)
5032
- end
5033
- end
5034
- end
5035
-
5036
- context 'when the server selected does not support arrayFilters' do
5037
- max_server_version '3.4'
5038
-
5039
- let(:result) do
5040
- authorized_collection.find_one_and_update(selector,
5041
- { '$set' => { 'x.$[i].y' => 5 } },
5042
- options)
5043
- end
5044
-
5045
- context 'when a Symbol key is used' do
5046
-
5047
- let(:options) do
5048
- { array_filters: [{ 'i.y' => 3 }] }
5049
- end
5050
-
5051
- it 'raises an exception' do
5052
- expect {
5053
- result
5054
- }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
5055
- end
5056
- end
5057
-
5058
- context 'when a String key is used' do
5059
-
5060
- let(:options) do
5061
- { 'array_filters' => [{ 'i.y' => 3 }] }
5062
- end
5063
-
5064
- it 'raises an exception' do
5065
- expect {
5066
- result
5067
- }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
5068
- end
5069
- end
5070
- end
5071
- end
5072
-
5073
- context 'when various options passed in' do
5074
- # w: 2 requires a replica set
5075
- require_topology :replica_set
5076
-
5077
- # https://jira.mongodb.org/browse/RUBY-2306
5078
- min_server_fcv '3.6'
5079
-
5080
- let(:session) do
5081
- authorized_client.start_session
5082
- end
5083
-
5084
- let(:events) do
5085
- subscriber.command_started_events('findAndModify')
5086
- end
5087
-
5088
- let(:collection) do
5089
- authorized_collection.with(write_concern: {w: 2})
5090
- end
5091
-
5092
- let(:selector) do
5093
- {field: 'test1'}
5094
- end
5095
-
5096
- before do
5097
- collection.insert_one({field: 'test1'}, session: session)
5098
- end
5099
-
5100
- let!(:command) do
5101
- Utils.get_command_event(authorized_client, 'findAndModify') do |client|
5102
- collection.find_one_and_update(selector, { '$set' => {field: 'testing'}},
5103
- :return_document => :after, write_concern: {w: 1}, upsert: true,
5104
- bypass_document_validation: true, max_time_ms: 100, session: session)
5105
- end.command
5106
- end
5107
-
5108
- it 'find and updates successfully with correct options sent to server' do
5109
- expect(events.length).to eq(1)
5110
- expect(command[:writeConcern]).to_not be_nil
5111
- expect(command[:writeConcern][:w]).to eq(1)
5112
- expect(command[:upsert]).to eq(true)
5113
- expect(command[:bypassDocumentValidation]).to be(true)
5114
- expect(command[:maxTimeMS]).to eq(100)
5115
- end
5116
- end
5117
- end
5118
-
5119
- describe '#find_one_and_replace' do
5120
-
5121
- before do
5122
- authorized_collection.insert_many([{ field: 'test1', other: 'sth' }])
5123
- end
5124
-
5125
- let(:selector) do
5126
- { field: 'test1' }
5127
- end
5128
-
5129
- context 'when a matching document is found' do
5130
-
5131
- context 'when no options are provided' do
5132
-
5133
- let(:document) do
5134
- authorized_collection.find_one_and_replace(selector, { field: 'testing' })
5135
- end
5136
-
5137
- it 'returns the original document' do
5138
- expect(document['field']).to eq('test1')
5139
- end
5140
- end
5141
-
5142
- context 'when a session is provided' do
5143
-
5144
- let(:operation) do
5145
- authorized_collection.find_one_and_replace(selector, { field: 'testing' }, session: session)
5146
- end
5147
-
5148
- let(:failed_operation) do
5149
- authorized_collection.find_one_and_replace({ '$._id' => 1}, { field: 'testing' }, session: session)
5150
- end
5151
-
5152
- let(:session) do
5153
- authorized_client.start_session
5154
- end
5155
-
5156
- let(:client) do
5157
- authorized_client
5158
- end
5159
-
5160
- it_behaves_like 'an operation using a session'
5161
- it_behaves_like 'a failed operation using a session'
5162
- end
5163
-
5164
- context 'when return_document options are provided' do
5165
-
5166
- context 'when return_document is :after' do
5167
-
5168
- let(:document) do
5169
- authorized_collection.find_one_and_replace(selector, { field: 'testing' }, :return_document => :after)
5170
- end
5171
-
5172
- it 'returns the new document' do
5173
- expect(document['field']).to eq('testing')
5174
- end
5175
- end
5176
-
5177
- context 'when return_document is :before' do
5178
-
5179
- let(:document) do
5180
- authorized_collection.find_one_and_replace(selector, { field: 'testing' }, :return_document => :before)
5181
- end
5182
-
5183
- it 'returns the original document' do
5184
- expect(document['field']).to eq('test1')
5185
- end
5186
- end
5187
- end
5188
-
5189
- context 'when a projection is provided' do
5190
-
5191
- let(:document) do
5192
- authorized_collection.find_one_and_replace(selector, { field: 'testing' }, projection: { _id: 1 })
5193
- end
5194
-
5195
- it 'returns the document with limited fields' do
5196
- expect(document['field']).to be_nil
5197
- expect(document['_id']).to_not be_nil
5198
- end
5199
- end
5200
-
5201
- context 'when a sort is provided' do
5202
-
5203
- let(:document) do
5204
- authorized_collection.find_one_and_replace(selector, { field: 'testing' }, :sort => { field: 1 })
5205
- end
5206
-
5207
- it 'returns the original document' do
5208
- expect(document['field']).to eq('test1')
5209
- end
5210
- end
5211
- end
5212
-
5213
- context 'when no matching document is found' do
5214
-
5215
- context 'when no upsert options are provided' do
5216
-
5217
- let(:selector) do
5218
- { field: 'test5' }
5219
- end
5220
-
5221
- let(:document) do
5222
- authorized_collection.find_one_and_replace(selector, { field: 'testing' })
5223
- end
5224
-
5225
- it 'returns nil' do
5226
- expect(document).to be_nil
5227
- end
5228
- end
5229
-
5230
- context 'when upsert options are provided' do
5231
-
5232
- let(:selector) do
5233
- { field: 'test5' }
5234
- end
5235
-
5236
- let(:document) do
5237
- authorized_collection.find_one_and_replace(selector, { field: 'testing' }, :upsert => true, :return_document => :after)
5238
- end
5239
-
5240
- it 'returns the new document' do
5241
- expect(document['field']).to eq('testing')
5242
- end
5243
- end
5244
- end
5245
-
5246
- context 'when max_time_ms is provided' do
5247
-
5248
- it 'includes the max_time_ms value in the command' do
5249
- expect {
5250
- authorized_collection.find_one_and_replace(selector, { field: 'testing' }, max_time_ms: 0.1)
5251
- }.to raise_error(Mongo::Error::OperationFailure)
5252
- end
5253
- end
5254
-
5255
- context 'when the operation fails' do
5256
-
5257
- let(:result) do
5258
- authorized_collection.find_one_and_replace(selector, { field: 'testing' }, max_time_ms: 0.1)
5259
- end
5260
-
5261
- it 'raises an OperationFailure' do
5262
- expect {
5263
- result
5264
- }.to raise_exception(Mongo::Error::OperationFailure)
5265
- end
5266
- end
5267
-
5268
- context 'when collection has a validator' do
5269
- min_server_fcv '3.2'
5270
-
5271
- around(:each) do |spec|
5272
- authorized_client[:validating].drop
5273
- authorized_client[:validating,
5274
- :validator => { :a => { '$exists' => true } }].tap do |c|
5275
- c.create
5276
- end
5277
- spec.run
5278
- collection_with_validator.drop
5279
- end
5280
-
5281
- before do
5282
- collection_with_validator.insert_one({ a: 1 })
5283
- end
5284
-
5285
- context 'when the document is valid' do
5286
-
5287
- let(:result) do
5288
- collection_with_validator.find_one_and_replace(
5289
- { a: 1 }, { a: 5 }, :return_document => :after)
5290
- end
5291
-
5292
- it 'replaces successfully when document is valid' do
5293
- expect(result[:a]).to eq(5)
5294
- end
5295
- end
5296
-
5297
- context 'when the document is invalid' do
5298
-
5299
- context 'when bypass_document_validation is not set' do
5300
-
5301
- let(:result2) do
5302
- collection_with_validator.find_one_and_replace(
5303
- { a: 1 }, { x: 5 }, :return_document => :after)
5304
- end
5305
-
5306
- it 'raises OperationFailure' do
5307
- expect {
5308
- result2
5309
- }.to raise_exception(Mongo::Error::OperationFailure)
5310
- end
5311
- end
5312
-
5313
- context 'when bypass_document_validation is true' do
5314
-
5315
- let(:result3) do
5316
- collection_with_validator.find_one_and_replace(
5317
- { a: 1 }, { x: 1 }, :bypass_document_validation => true,
5318
- :return_document => :after)
5319
- end
5320
-
5321
- it 'replaces successfully' do
5322
- expect(result3[:x]).to eq(1)
5323
- expect(result3[:a]).to be_nil
5324
- end
5325
- end
5326
- end
5327
- end
5328
-
5329
- context 'when write_concern is provided' do
5330
- min_server_fcv '3.2'
5331
- require_topology :single
5332
-
5333
- it 'uses the write concern' do
5334
- expect {
5335
- authorized_collection.find_one_and_replace(selector,
5336
- { field: 'testing' },
5337
- write_concern: { w: 2 })
5338
- }.to raise_error(Mongo::Error::OperationFailure)
5339
- end
5340
- end
5341
-
5342
- context 'when the collection has a write concern' do
5343
- min_server_fcv '3.2'
5344
- require_topology :single
5345
-
5346
- let(:collection) do
5347
- authorized_collection.with(write: { w: 2 })
5348
- end
5349
-
5350
- it 'uses the write concern' do
5351
- expect {
5352
- collection.find_one_and_replace(selector,
5353
- { field: 'testing' },
5354
- write_concern: { w: 2 })
5355
- }.to raise_error(Mongo::Error::OperationFailure)
5356
- end
5357
- end
5358
-
5359
- context 'when collation is provided' do
5360
-
5361
- let(:selector) do
5362
- { name: 'BANG' }
5363
- end
5364
-
5365
- let(:result) do
5366
- authorized_collection.find_one_and_replace(selector,
5367
- { name: 'doink' },
5368
- options)
5369
- end
5370
-
5371
- before do
5372
- authorized_collection.insert_one(name: 'bang')
5373
- end
5374
-
5375
- let(:options) do
5376
- { collation: { locale: 'en_US', strength: 2 } }
5377
- end
5378
-
5379
- context 'when the server selected supports collations' do
5380
- min_server_fcv '3.4'
5381
-
5382
- it 'applies the collation' do
5383
- expect(result['name']).to eq('bang')
5384
- expect(authorized_collection.find(name: 'doink').count).to eq(1)
5385
- end
5386
- end
5387
-
5388
- context 'when the server selected does not support collations' do
5389
- max_server_version '3.2'
5390
-
5391
- it 'raises an exception' do
5392
- expect {
5393
- result
5394
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
5395
- end
5396
-
5397
- context 'when a String key is used' do
5398
-
5399
- let(:options) do
5400
- { 'collation' => { locale: 'en_US', strength: 2 } }
5401
- end
5402
-
5403
- it 'raises an exception' do
5404
- expect {
5405
- result
5406
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
5407
- end
5408
- end
5409
- end
5410
- end
5411
-
5412
- context 'when collation is not specified' do
5413
-
5414
- let(:selector) do
5415
- { name: 'BANG' }
5416
- end
5417
-
5418
- let(:result) do
5419
- authorized_collection.find_one_and_replace(selector, { name: 'doink' })
5420
- end
5421
-
5422
- before do
5423
- authorized_collection.insert_one(name: 'bang')
5424
- end
5425
-
5426
- it 'does not apply the collation' do
5427
- expect(result).to be_nil
5428
- end
5429
- end
5430
-
5431
- context 'when various options passed in' do
5432
- # https://jira.mongodb.org/browse/RUBY-2306
5433
- min_server_fcv '3.6'
5434
-
5435
- before do
5436
- authorized_collection.insert_one({field: 'test1'})
5437
- end
5438
-
5439
- let(:session) do
5440
- authorized_client.start_session
5441
- end
5442
-
5443
- let(:events) do
5444
- subscriber.command_started_events('findAndModify')
5445
- end
5446
-
5447
- let(:collection) do
5448
- authorized_collection.with(write_concern: { w: 2 })
5449
- end
5450
-
5451
- let!(:command) do
5452
- Utils.get_command_event(authorized_client, 'findAndModify') do |client|
5453
- collection.find_one_and_replace(selector, { '$set' => {field: 'test5'}},
5454
- :return_document => :after, write_concern: {w: 1}, session: session,
5455
- upsert: true, bypass_document_validation: false, max_time_ms: 200)
5456
- end.command
5457
- end
5458
-
5459
- it 'find and replaces successfully with correct options sent to server' do
5460
- expect(events.length).to eq(1)
5461
- expect(command[:writeConcern]).to_not be_nil
5462
- expect(command[:writeConcern][:w]).to eq(1)
5463
- expect(command[:upsert]).to be(true)
5464
- expect(command[:bypassDocumentValidation]).to be_nil
5465
- expect(command[:maxTimeMS]).to eq(200)
5466
- end
683
+ it 'includes the namespace' do
684
+ expect(authorized_collection.inspect).to include(authorized_collection.namespace)
5467
685
  end
5468
686
  end
5469
687