mongo 2.13.0 → 2.15.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
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