mongo 2.13.0.beta1 → 2.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +1 -5
  4. data/Rakefile +50 -9
  5. data/lib/mongo.rb +13 -2
  6. data/lib/mongo/address.rb +1 -1
  7. data/lib/mongo/address/ipv4.rb +1 -1
  8. data/lib/mongo/address/ipv6.rb +1 -1
  9. data/lib/mongo/auth/aws/request.rb +31 -5
  10. data/lib/mongo/bulk_write.rb +18 -0
  11. data/lib/mongo/caching_cursor.rb +74 -0
  12. data/lib/mongo/client.rb +238 -31
  13. data/lib/mongo/cluster.rb +56 -20
  14. data/lib/mongo/cluster/sdam_flow.rb +13 -10
  15. data/lib/mongo/cluster/topology/replica_set_no_primary.rb +3 -2
  16. data/lib/mongo/cluster/topology/sharded.rb +1 -1
  17. data/lib/mongo/cluster/topology/single.rb +2 -2
  18. data/lib/mongo/collection.rb +66 -24
  19. data/lib/mongo/collection/view.rb +24 -20
  20. data/lib/mongo/collection/view/aggregation.rb +25 -4
  21. data/lib/mongo/collection/view/builder/find_command.rb +38 -18
  22. data/lib/mongo/collection/view/explainable.rb +27 -8
  23. data/lib/mongo/collection/view/iterable.rb +72 -12
  24. data/lib/mongo/collection/view/readable.rb +19 -3
  25. data/lib/mongo/collection/view/writable.rb +55 -5
  26. data/lib/mongo/crypt/encryption_io.rb +6 -6
  27. data/lib/mongo/cursor.rb +16 -3
  28. data/lib/mongo/database.rb +37 -4
  29. data/lib/mongo/database/view.rb +18 -3
  30. data/lib/mongo/distinguishing_semaphore.rb +55 -0
  31. data/lib/mongo/error.rb +5 -0
  32. data/lib/mongo/error/invalid_read_concern.rb +28 -0
  33. data/lib/mongo/error/invalid_server_auth_host.rb +22 -0
  34. data/lib/mongo/error/invalid_session.rb +2 -1
  35. data/lib/mongo/error/operation_failure.rb +11 -5
  36. data/lib/mongo/error/server_certificate_revoked.rb +22 -0
  37. data/lib/mongo/error/sessions_not_supported.rb +35 -0
  38. data/lib/mongo/error/unsupported_option.rb +14 -12
  39. data/lib/mongo/event/base.rb +6 -0
  40. data/lib/mongo/grid/file.rb +5 -0
  41. data/lib/mongo/grid/file/chunk.rb +2 -0
  42. data/lib/mongo/grid/fs_bucket.rb +15 -13
  43. data/lib/mongo/grid/stream/write.rb +9 -3
  44. data/lib/mongo/index/view.rb +3 -0
  45. data/lib/mongo/lint.rb +2 -1
  46. data/lib/mongo/logger.rb +3 -3
  47. data/lib/mongo/monitoring.rb +38 -0
  48. data/lib/mongo/monitoring/command_log_subscriber.rb +10 -2
  49. data/lib/mongo/monitoring/event/command_failed.rb +11 -0
  50. data/lib/mongo/monitoring/event/command_started.rb +37 -2
  51. data/lib/mongo/monitoring/event/command_succeeded.rb +11 -0
  52. data/lib/mongo/monitoring/event/server_closed.rb +1 -1
  53. data/lib/mongo/monitoring/event/server_description_changed.rb +27 -4
  54. data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +9 -2
  55. data/lib/mongo/monitoring/event/server_heartbeat_started.rb +9 -2
  56. data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +9 -2
  57. data/lib/mongo/monitoring/event/server_opening.rb +1 -1
  58. data/lib/mongo/monitoring/event/topology_changed.rb +1 -1
  59. data/lib/mongo/monitoring/event/topology_closed.rb +1 -1
  60. data/lib/mongo/monitoring/event/topology_opening.rb +1 -1
  61. data/lib/mongo/monitoring/publishable.rb +6 -3
  62. data/lib/mongo/monitoring/server_description_changed_log_subscriber.rb +9 -1
  63. data/lib/mongo/monitoring/topology_changed_log_subscriber.rb +1 -1
  64. data/lib/mongo/operation.rb +2 -0
  65. data/lib/mongo/operation/aggregate/result.rb +9 -8
  66. data/lib/mongo/operation/collections_info/command.rb +5 -0
  67. data/lib/mongo/operation/collections_info/result.rb +18 -1
  68. data/lib/mongo/operation/delete/bulk_result.rb +2 -0
  69. data/lib/mongo/operation/delete/result.rb +3 -0
  70. data/lib/mongo/operation/explain/command.rb +4 -0
  71. data/lib/mongo/operation/explain/legacy.rb +4 -0
  72. data/lib/mongo/operation/explain/op_msg.rb +6 -0
  73. data/lib/mongo/operation/explain/result.rb +3 -0
  74. data/lib/mongo/operation/find/legacy/result.rb +2 -0
  75. data/lib/mongo/operation/find/result.rb +13 -0
  76. data/lib/mongo/operation/get_more/result.rb +3 -0
  77. data/lib/mongo/operation/indexes/result.rb +5 -0
  78. data/lib/mongo/operation/insert/bulk_result.rb +5 -0
  79. data/lib/mongo/operation/insert/result.rb +5 -0
  80. data/lib/mongo/operation/list_collections/result.rb +5 -0
  81. data/lib/mongo/operation/map_reduce/result.rb +10 -0
  82. data/lib/mongo/operation/parallel_scan/result.rb +4 -0
  83. data/lib/mongo/operation/result.rb +35 -6
  84. data/lib/mongo/operation/shared/bypass_document_validation.rb +1 -0
  85. data/lib/mongo/operation/shared/causal_consistency_supported.rb +1 -0
  86. data/lib/mongo/operation/shared/collections_info_or_list_collections.rb +2 -0
  87. data/lib/mongo/operation/shared/executable.rb +1 -0
  88. data/lib/mongo/operation/shared/idable.rb +2 -1
  89. data/lib/mongo/operation/shared/limited.rb +1 -0
  90. data/lib/mongo/operation/shared/object_id_generator.rb +1 -0
  91. data/lib/mongo/operation/shared/result/aggregatable.rb +1 -0
  92. data/lib/mongo/operation/shared/sessions_supported.rb +1 -0
  93. data/lib/mongo/operation/shared/specifiable.rb +1 -0
  94. data/lib/mongo/operation/shared/write.rb +1 -0
  95. data/lib/mongo/operation/shared/write_concern_supported.rb +1 -0
  96. data/lib/mongo/operation/update/legacy/result.rb +7 -0
  97. data/lib/mongo/operation/update/result.rb +8 -0
  98. data/lib/mongo/operation/users_info/result.rb +3 -0
  99. data/lib/mongo/protocol/message.rb +47 -10
  100. data/lib/mongo/protocol/msg.rb +34 -1
  101. data/lib/mongo/protocol/query.rb +36 -0
  102. data/lib/mongo/protocol/serializers.rb +5 -2
  103. data/lib/mongo/query_cache.rb +242 -0
  104. data/lib/mongo/retryable.rb +8 -1
  105. data/lib/mongo/server.rb +15 -4
  106. data/lib/mongo/server/app_metadata.rb +27 -3
  107. data/lib/mongo/server/connection.rb +4 -4
  108. data/lib/mongo/server/connection_base.rb +38 -12
  109. data/lib/mongo/server/connection_common.rb +2 -2
  110. data/lib/mongo/server/connection_pool.rb +3 -0
  111. data/lib/mongo/server/description.rb +13 -1
  112. data/lib/mongo/server/monitor.rb +76 -44
  113. data/lib/mongo/server/monitor/connection.rb +57 -9
  114. data/lib/mongo/server/pending_connection.rb +14 -4
  115. data/lib/mongo/server/push_monitor.rb +173 -0
  116. data/{spec/runners/transactions/context.rb → lib/mongo/server/push_monitor/connection.rb} +9 -14
  117. data/lib/mongo/server_selector.rb +0 -1
  118. data/lib/mongo/server_selector/base.rb +583 -1
  119. data/lib/mongo/server_selector/nearest.rb +1 -6
  120. data/lib/mongo/server_selector/primary.rb +1 -6
  121. data/lib/mongo/server_selector/primary_preferred.rb +7 -10
  122. data/lib/mongo/server_selector/secondary.rb +1 -6
  123. data/lib/mongo/server_selector/secondary_preferred.rb +1 -7
  124. data/lib/mongo/session.rb +7 -1
  125. data/lib/mongo/socket.rb +26 -12
  126. data/lib/mongo/socket/ocsp_cache.rb +97 -0
  127. data/lib/mongo/socket/ocsp_verifier.rb +368 -0
  128. data/lib/mongo/socket/ssl.rb +46 -25
  129. data/lib/mongo/socket/tcp.rb +1 -1
  130. data/lib/mongo/srv/monitor.rb +7 -13
  131. data/lib/mongo/srv/resolver.rb +14 -10
  132. data/lib/mongo/timeout.rb +2 -0
  133. data/lib/mongo/topology_version.rb +9 -0
  134. data/lib/mongo/uri.rb +21 -390
  135. data/lib/mongo/uri/options_mapper.rb +582 -0
  136. data/lib/mongo/uri/srv_protocol.rb +3 -2
  137. data/lib/mongo/utils.rb +73 -0
  138. data/lib/mongo/version.rb +1 -1
  139. data/spec/NOTES.aws-auth.md +12 -7
  140. data/spec/README.aws-auth.md +2 -2
  141. data/spec/README.md +63 -1
  142. data/spec/integration/awaited_ismaster_spec.rb +28 -0
  143. data/spec/integration/bson_symbol_spec.rb +4 -2
  144. data/spec/integration/bulk_write_spec.rb +67 -0
  145. data/spec/integration/change_stream_examples_spec.rb +6 -2
  146. data/spec/integration/change_stream_spec.rb +1 -1
  147. data/spec/integration/check_clean_slate_spec.rb +16 -0
  148. data/spec/integration/client_authentication_options_spec.rb +92 -28
  149. data/spec/integration/client_construction_spec.rb +1 -0
  150. data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +9 -5
  151. data/spec/integration/connect_single_rs_name_spec.rb +5 -2
  152. data/spec/integration/connection_pool_populator_spec.rb +4 -2
  153. data/spec/integration/connection_spec.rb +7 -4
  154. data/spec/integration/crud_spec.rb +4 -4
  155. data/spec/integration/cursor_reaping_spec.rb +54 -18
  156. data/spec/integration/docs_examples_spec.rb +6 -0
  157. data/spec/integration/fork_reconnect_spec.rb +56 -1
  158. data/spec/integration/grid_fs_bucket_spec.rb +48 -0
  159. data/spec/integration/heartbeat_events_spec.rb +4 -23
  160. data/spec/integration/ocsp_connectivity_spec.rb +26 -0
  161. data/spec/integration/ocsp_verifier_cache_spec.rb +188 -0
  162. data/spec/integration/ocsp_verifier_spec.rb +334 -0
  163. data/spec/integration/query_cache_spec.rb +1045 -0
  164. data/spec/integration/query_cache_transactions_spec.rb +190 -0
  165. data/spec/integration/read_concern_spec.rb +1 -1
  166. data/spec/integration/retryable_errors_spec.rb +1 -1
  167. data/spec/integration/retryable_writes/retryable_writes_40_and_newer_spec.rb +1 -0
  168. data/spec/integration/retryable_writes/shared/performs_legacy_retries.rb +4 -2
  169. data/spec/integration/retryable_writes/shared/performs_modern_retries.rb +3 -3
  170. data/spec/integration/retryable_writes/shared/performs_no_retries.rb +2 -2
  171. data/spec/integration/sdam_error_handling_spec.rb +122 -15
  172. data/spec/integration/sdam_events_spec.rb +80 -6
  173. data/spec/integration/sdam_prose_spec.rb +64 -0
  174. data/spec/integration/server_monitor_spec.rb +25 -1
  175. data/spec/integration/server_selection_spec.rb +36 -0
  176. data/spec/integration/size_limit_spec.rb +23 -5
  177. data/spec/integration/srv_monitoring_spec.rb +38 -3
  178. data/spec/integration/srv_spec.rb +56 -0
  179. data/spec/integration/ssl_uri_options_spec.rb +2 -2
  180. data/spec/integration/transactions_examples_spec.rb +17 -7
  181. data/spec/integration/zlib_compression_spec.rb +25 -0
  182. data/spec/lite_spec_helper.rb +20 -9
  183. data/spec/mongo/address_spec.rb +1 -1
  184. data/spec/mongo/auth/aws/request_region_spec.rb +42 -0
  185. data/spec/mongo/auth/aws/request_spec.rb +76 -0
  186. data/spec/mongo/auth/scram_spec.rb +1 -1
  187. data/spec/mongo/auth/user_spec.rb +1 -1
  188. data/spec/mongo/bulk_write_spec.rb +2 -2
  189. data/spec/mongo/caching_cursor_spec.rb +70 -0
  190. data/spec/mongo/client_construction_spec.rb +386 -3
  191. data/spec/mongo/client_encryption_spec.rb +16 -10
  192. data/spec/mongo/client_spec.rb +85 -3
  193. data/spec/mongo/cluster/topology/replica_set_spec.rb +53 -10
  194. data/spec/mongo/cluster/topology/sharded_spec.rb +1 -1
  195. data/spec/mongo/cluster/topology/single_spec.rb +19 -8
  196. data/spec/mongo/cluster/topology/unknown_spec.rb +1 -1
  197. data/spec/mongo/cluster/topology_spec.rb +1 -1
  198. data/spec/mongo/cluster_spec.rb +37 -35
  199. data/spec/mongo/collection/view/change_stream_resume_spec.rb +7 -7
  200. data/spec/mongo/collection/view/explainable_spec.rb +87 -4
  201. data/spec/mongo/collection/view/map_reduce_spec.rb +2 -0
  202. data/spec/mongo/collection/view/readable_spec.rb +36 -0
  203. data/spec/mongo/collection_spec.rb +572 -0
  204. data/spec/mongo/crypt/auto_decryption_context_spec.rb +1 -1
  205. data/spec/mongo/crypt/auto_encryption_context_spec.rb +1 -1
  206. data/spec/mongo/crypt/binary_spec.rb +1 -6
  207. data/spec/mongo/crypt/binding/binary_spec.rb +1 -6
  208. data/spec/mongo/crypt/binding/context_spec.rb +2 -7
  209. data/spec/mongo/crypt/binding/helpers_spec.rb +1 -6
  210. data/spec/mongo/crypt/binding/mongocrypt_spec.rb +2 -7
  211. data/spec/mongo/crypt/binding/status_spec.rb +1 -6
  212. data/spec/mongo/crypt/binding/version_spec.rb +1 -6
  213. data/spec/mongo/crypt/data_key_context_spec.rb +1 -1
  214. data/spec/mongo/crypt/explicit_decryption_context_spec.rb +1 -1
  215. data/spec/mongo/crypt/explicit_encryption_context_spec.rb +1 -1
  216. data/spec/mongo/crypt/status_spec.rb +1 -6
  217. data/spec/mongo/database_spec.rb +353 -8
  218. data/spec/mongo/distinguishing_semaphore_spec.rb +63 -0
  219. data/spec/mongo/error/no_server_available_spec.rb +1 -1
  220. data/spec/mongo/error/operation_failure_spec.rb +40 -0
  221. data/spec/mongo/index/view_spec.rb +148 -2
  222. data/spec/mongo/logger_spec.rb +13 -11
  223. data/spec/mongo/monitoring/event/server_closed_spec.rb +1 -1
  224. data/spec/mongo/monitoring/event/server_description_changed_spec.rb +1 -4
  225. data/spec/mongo/monitoring/event/server_opening_spec.rb +1 -1
  226. data/spec/mongo/monitoring/event/topology_changed_spec.rb +1 -1
  227. data/spec/mongo/monitoring/event/topology_closed_spec.rb +1 -1
  228. data/spec/mongo/monitoring/event/topology_opening_spec.rb +1 -1
  229. data/spec/mongo/operation/delete/op_msg_spec.rb +3 -3
  230. data/spec/mongo/operation/insert/command_spec.rb +2 -2
  231. data/spec/mongo/operation/insert/op_msg_spec.rb +3 -3
  232. data/spec/mongo/operation/read_preference_op_msg_spec.rb +1 -1
  233. data/spec/mongo/operation/update/command_spec.rb +2 -2
  234. data/spec/mongo/operation/update/op_msg_spec.rb +3 -3
  235. data/spec/mongo/protocol/msg_spec.rb +10 -0
  236. data/spec/mongo/query_cache_spec.rb +280 -0
  237. data/spec/mongo/semaphore_spec.rb +51 -0
  238. data/spec/mongo/server/app_metadata_shared.rb +82 -2
  239. data/spec/mongo/server/connection_auth_spec.rb +2 -2
  240. data/spec/mongo/server/connection_pool_spec.rb +7 -3
  241. data/spec/mongo/server/connection_spec.rb +15 -8
  242. data/spec/mongo/server/description_spec.rb +18 -0
  243. data/spec/mongo/server_selector/nearest_spec.rb +23 -23
  244. data/spec/mongo/server_selector/primary_preferred_spec.rb +26 -26
  245. data/spec/mongo/server_selector/primary_spec.rb +9 -9
  246. data/spec/mongo/server_selector/secondary_preferred_spec.rb +22 -22
  247. data/spec/mongo/server_selector/secondary_spec.rb +18 -18
  248. data/spec/mongo/server_selector_spec.rb +6 -6
  249. data/spec/mongo/session_spec.rb +35 -0
  250. data/spec/mongo/socket/ssl_spec.rb +4 -4
  251. data/spec/mongo/socket_spec.rb +1 -1
  252. data/spec/mongo/uri/srv_protocol_spec.rb +64 -33
  253. data/spec/mongo/uri_option_parsing_spec.rb +11 -11
  254. data/spec/mongo/uri_spec.rb +68 -41
  255. data/spec/mongo/utils_spec.rb +39 -0
  256. data/spec/runners/auth.rb +3 -0
  257. data/spec/runners/change_streams/test.rb +3 -3
  258. data/spec/runners/cmap.rb +1 -1
  259. data/spec/runners/command_monitoring.rb +3 -34
  260. data/spec/runners/connection_string.rb +35 -124
  261. data/spec/runners/crud/context.rb +9 -5
  262. data/spec/runners/crud/operation.rb +59 -27
  263. data/spec/runners/crud/spec.rb +0 -8
  264. data/spec/runners/crud/test.rb +1 -1
  265. data/spec/runners/crud/test_base.rb +0 -19
  266. data/spec/runners/sdam.rb +2 -2
  267. data/spec/runners/server_selection.rb +242 -28
  268. data/spec/runners/transactions.rb +12 -12
  269. data/spec/runners/transactions/operation.rb +151 -25
  270. data/spec/runners/transactions/test.rb +62 -18
  271. data/spec/shared/LICENSE +20 -0
  272. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  273. data/spec/shared/lib/mrss/constraints.rb +303 -0
  274. data/spec/shared/lib/mrss/lite_constraints.rb +175 -0
  275. data/spec/shared/lib/mrss/spec_organizer.rb +149 -0
  276. data/spec/spec_helper.rb +3 -1
  277. data/spec/spec_tests/cmap_spec.rb +7 -3
  278. data/spec/spec_tests/command_monitoring_spec.rb +22 -12
  279. data/spec/spec_tests/crud_spec.rb +1 -1
  280. data/spec/spec_tests/data/change_streams/change-streams-errors.yml +4 -9
  281. data/spec/spec_tests/data/change_streams/change-streams-resume-whitelist.yml +66 -0
  282. data/spec/spec_tests/data/change_streams/change-streams.yml +0 -1
  283. data/spec/spec_tests/data/cmap/pool-checkout-connection.yml +6 -2
  284. data/spec/spec_tests/data/cmap/pool-create-min-size.yml +3 -0
  285. data/spec/spec_tests/data/connection_string/valid-warnings.yml +24 -0
  286. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/MaxStalenessTooSmall.yml +15 -0
  287. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/NoKnownServers.yml +4 -3
  288. data/spec/spec_tests/data/max_staleness/Unknown/SmallMaxStaleness.yml +1 -0
  289. data/spec/spec_tests/data/sdam_integration/cancel-server-check.yml +96 -0
  290. data/spec/spec_tests/data/sdam_integration/connectTimeoutMS.yml +88 -0
  291. data/spec/spec_tests/data/sdam_integration/find-network-error.yml +83 -0
  292. data/spec/spec_tests/data/sdam_integration/find-shutdown-error.yml +116 -0
  293. data/spec/spec_tests/data/sdam_integration/insert-network-error.yml +86 -0
  294. data/spec/spec_tests/data/sdam_integration/insert-shutdown-error.yml +115 -0
  295. data/spec/spec_tests/data/sdam_integration/isMaster-command-error.yml +168 -0
  296. data/spec/spec_tests/data/sdam_integration/isMaster-network-error.yml +162 -0
  297. data/spec/spec_tests/data/sdam_integration/isMaster-timeout.yml +229 -0
  298. data/spec/spec_tests/data/sdam_integration/rediscover-quickly-after-step-down.yml +87 -0
  299. data/spec/spec_tests/data/sdam_monitoring/discovered_standalone.yml +1 -3
  300. data/spec/spec_tests/data/sdam_monitoring/standalone.yml +2 -2
  301. data/spec/spec_tests/data/sdam_monitoring/standalone_repeated.yml +2 -2
  302. data/spec/spec_tests/data/sdam_monitoring/standalone_suppress_equal_description_changes.yml +2 -2
  303. data/spec/spec_tests/data/sdam_monitoring/standalone_to_rs_with_me_mismatch.yml +2 -2
  304. data/spec/spec_tests/data/uri_options/auth-options.yml +25 -0
  305. data/spec/spec_tests/data/uri_options/compression-options.yml +6 -3
  306. data/spec/spec_tests/data/uri_options/read-preference-options.yml +24 -0
  307. data/spec/spec_tests/data/uri_options/ruby-connection-options.yml +1 -0
  308. data/spec/spec_tests/data/uri_options/tls-options.yml +160 -4
  309. data/spec/spec_tests/dns_seedlist_discovery_spec.rb +9 -1
  310. data/spec/spec_tests/max_staleness_spec.rb +4 -142
  311. data/spec/spec_tests/retryable_reads_spec.rb +2 -2
  312. data/spec/spec_tests/sdam_integration_spec.rb +13 -0
  313. data/spec/spec_tests/sdam_monitoring_spec.rb +1 -2
  314. data/spec/spec_tests/server_selection_spec.rb +4 -116
  315. data/spec/spec_tests/uri_options_spec.rb +31 -33
  316. data/spec/stress/cleanup_spec.rb +17 -2
  317. data/spec/stress/connection_pool_stress_spec.rb +10 -8
  318. data/spec/stress/fork_reconnect_stress_spec.rb +1 -1
  319. data/spec/support/certificates/atlas-ocsp-ca.crt +28 -0
  320. data/spec/support/certificates/atlas-ocsp.crt +41 -0
  321. data/spec/support/client_registry.rb +1 -0
  322. data/spec/support/client_registry_macros.rb +11 -2
  323. data/spec/support/cluster_config.rb +4 -0
  324. data/spec/support/common_shortcuts.rb +45 -0
  325. data/spec/support/constraints.rb +6 -253
  326. data/spec/support/event_subscriber.rb +123 -33
  327. data/spec/support/keyword_struct.rb +26 -0
  328. data/spec/support/matchers.rb +16 -0
  329. data/spec/support/ocsp +1 -0
  330. data/spec/support/session_registry.rb +52 -0
  331. data/spec/support/shared/server_selector.rb +13 -1
  332. data/spec/support/spec_config.rb +60 -13
  333. data/spec/support/spec_setup.rb +1 -1
  334. data/spec/support/utils.rb +84 -1
  335. metadata +1027 -937
  336. metadata.gz.sig +0 -0
  337. data/lib/mongo/server_selector/selectable.rb +0 -560
  338. data/spec/runners/sdam_monitoring.rb +0 -89
  339. data/spec/support/lite_constraints.rb +0 -141
@@ -0,0 +1,1045 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'QueryCache' do
4
+ around do |spec|
5
+ Mongo::QueryCache.clear
6
+ Mongo::QueryCache.cache { spec.run }
7
+ end
8
+
9
+ before do
10
+ authorized_collection.delete_many
11
+ subscriber.clear_events!
12
+ end
13
+
14
+ before(:all) do
15
+ # It is likely that there are other session leaks in the driver that are
16
+ # unrelated to the query cache. Clear the SessionRegistry at the start of
17
+ # these tests in order to detect leaks that occur only within the scope of
18
+ # these tests.
19
+ #
20
+ # Other session leaks will be detected and addressed as part of RUBY-2391.
21
+ SessionRegistry.instance.clear_registry
22
+ end
23
+
24
+ after do
25
+ SessionRegistry.instance.verify_sessions_ended!
26
+ end
27
+
28
+ let(:subscriber) { EventSubscriber.new }
29
+
30
+ let(:client) do
31
+ authorized_client.tap do |client|
32
+ client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
33
+ end
34
+ end
35
+
36
+ let(:authorized_collection) { client['collection_spec'] }
37
+
38
+ let(:events) do
39
+ subscriber.command_started_events('find')
40
+ end
41
+
42
+ describe '#cache' do
43
+
44
+ before do
45
+ Mongo::QueryCache.enabled = false
46
+ authorized_collection.insert_one({ name: 'testing' })
47
+ authorized_collection.find(name: 'testing').to_a
48
+ end
49
+
50
+ it 'enables the query cache inside the block' do
51
+ Mongo::QueryCache.cache do
52
+ authorized_collection.find(name: 'testing').to_a
53
+ expect(Mongo::QueryCache.enabled?).to be(true)
54
+ expect(Mongo::QueryCache.send(:cache_table).length).to eq(1)
55
+ expect(events.length).to eq(2)
56
+ end
57
+ authorized_collection.find(name: 'testing').to_a
58
+ expect(Mongo::QueryCache.enabled?).to be(false)
59
+ expect(Mongo::QueryCache.send(:cache_table).length).to eq(1)
60
+ expect(events.length).to eq(2)
61
+ end
62
+ end
63
+
64
+ describe '#uncached' do
65
+
66
+ before do
67
+ authorized_collection.insert_one({ name: 'testing' })
68
+ authorized_collection.find(name: 'testing').to_a
69
+ end
70
+
71
+ it 'disables the query cache inside the block' do
72
+ expect(Mongo::QueryCache.send(:cache_table).length).to eq(1)
73
+ Mongo::QueryCache.uncached do
74
+ authorized_collection.find(name: 'testing').to_a
75
+ expect(Mongo::QueryCache.enabled?).to be(false)
76
+ expect(events.length).to eq(2)
77
+ end
78
+ authorized_collection.find(name: 'testing').to_a
79
+ expect(Mongo::QueryCache.enabled?).to be(true)
80
+ expect(Mongo::QueryCache.send(:cache_table).length).to eq(1)
81
+ expect(events.length).to eq(2)
82
+ end
83
+ end
84
+
85
+ describe 'query with multiple batches' do
86
+ min_server_fcv '3.2'
87
+
88
+ before do
89
+ 102.times { |i| authorized_collection.insert_one(_id: i) }
90
+ end
91
+
92
+ let(:expected_results) { [*0..101].map { |id| { "_id" => id } } }
93
+
94
+ it 'returns the correct result' do
95
+ result = authorized_collection.find.to_a
96
+ expect(result.length).to eq(102)
97
+ expect(result).to eq(expected_results)
98
+ end
99
+
100
+ it 'returns the correct result multiple times' do
101
+ result1 = authorized_collection.find.to_a
102
+ result2 = authorized_collection.find.to_a
103
+ expect(result1).to eq(expected_results)
104
+ expect(result2).to eq(expected_results)
105
+ end
106
+
107
+ it 'caches the query' do
108
+ authorized_collection.find.to_a
109
+ authorized_collection.find.to_a
110
+ expect(subscriber.command_started_events('find').length).to eq(1)
111
+ expect(subscriber.command_started_events('getMore').length).to eq(1)
112
+ end
113
+
114
+ it 'uses cached cursor when limited' do
115
+ authorized_collection.find.to_a
116
+ result = authorized_collection.find({}, limit: 5).to_a
117
+
118
+ expect(result.length).to eq(5)
119
+ expect(result).to eq(expected_results.first(5))
120
+
121
+ expect(subscriber.command_started_events('find').length).to eq(1)
122
+ expect(subscriber.command_started_events('getMore').length).to eq(1)
123
+ end
124
+
125
+ it 'can be used with a block API' do
126
+ authorized_collection.find.to_a
127
+
128
+ result = []
129
+ authorized_collection.find.each do |doc|
130
+ result << doc
131
+ end
132
+
133
+ expect(result).to eq(expected_results)
134
+
135
+ expect(subscriber.command_started_events('find').length).to eq(1)
136
+ expect(subscriber.command_started_events('getMore').length).to eq(1)
137
+ end
138
+
139
+ context 'when the cursor isn\'t fully iterated the first time' do
140
+ it 'continues iterating' do
141
+ result1 = authorized_collection.find.first(5)
142
+
143
+ expect(result1.length).to eq(5)
144
+ expect(result1).to eq(expected_results.first(5))
145
+
146
+ expect(subscriber.command_started_events('find').length).to eq(1)
147
+ expect(subscriber.command_started_events('getMore').length).to eq(0)
148
+
149
+ result2 = authorized_collection.find.to_a
150
+
151
+ expect(result2.length).to eq(102)
152
+ expect(result2).to eq(expected_results)
153
+
154
+ expect(subscriber.command_started_events('find').length).to eq(1)
155
+ expect(subscriber.command_started_events('getMore').length).to eq(1)
156
+ end
157
+
158
+ it 'can be iterated multiple times' do
159
+ authorized_collection.find.first(5)
160
+ authorized_collection.find.to_a
161
+
162
+ result = authorized_collection.find.to_a
163
+
164
+ expect(result.length).to eq(102)
165
+ expect(result).to eq(expected_results)
166
+
167
+ expect(subscriber.command_started_events('find').length).to eq(1)
168
+ expect(subscriber.command_started_events('getMore').length).to eq(1)
169
+ end
170
+
171
+ it 'can be used with a block API' do
172
+ authorized_collection.find.first(5)
173
+
174
+ result = []
175
+ authorized_collection.find.each do |doc|
176
+ result << doc
177
+ end
178
+
179
+ expect(result.length).to eq(102)
180
+ expect(result).to eq(expected_results)
181
+
182
+ expect(subscriber.command_started_events('find').length).to eq(1)
183
+ expect(subscriber.command_started_events('getMore').length).to eq(1)
184
+ end
185
+ end
186
+ end
187
+
188
+ describe 'queries with read concern' do
189
+ require_wired_tiger
190
+ min_server_fcv '3.6'
191
+
192
+ before do
193
+ authorized_client['test'].drop
194
+ end
195
+
196
+ context 'when two queries have same read concern' do
197
+ before do
198
+ authorized_client['test', read_concern: { level: :majority }].find.to_a
199
+ authorized_client['test', read_concern: { level: :majority }].find.to_a
200
+ end
201
+
202
+ it 'executes one query' do
203
+ expect(events.length).to eq(1)
204
+ end
205
+ end
206
+
207
+ context 'when two queries have different read concerns' do
208
+ before do
209
+ authorized_client['test', read_concern: { level: :majority }].find.to_a
210
+ authorized_client['test', read_concern: { level: :local }].find.to_a
211
+ end
212
+
213
+ it 'executes two queries' do
214
+ expect(events.length).to eq(2)
215
+ end
216
+ end
217
+ end
218
+
219
+ describe 'queries with read preference' do
220
+ before do
221
+ subscriber.clear_events!
222
+ authorized_client['test'].drop
223
+ end
224
+
225
+ context 'when two queries have different read preferences' do
226
+ before do
227
+ authorized_client['test', read: { mode: :primary }].find.to_a
228
+ authorized_client['test', read: { mode: :primary_preferred }].find.to_a
229
+ end
230
+
231
+ it 'executes two queries' do
232
+ expect(events.length).to eq(2)
233
+ end
234
+ end
235
+
236
+ context 'when two queries have same read preference' do
237
+ before do
238
+ authorized_client['test', read: { mode: :primary }].find.to_a
239
+ authorized_client['test', read: { mode: :primary }].find.to_a
240
+ end
241
+
242
+ it 'executes one query' do
243
+ expect(events.length).to eq(1)
244
+ end
245
+ end
246
+ end
247
+
248
+ describe 'query fills up entire batch' do
249
+ before do
250
+ subscriber.clear_events!
251
+ authorized_client['test'].drop
252
+
253
+ 2.times { |i| authorized_client['test'].insert_one(_id: i) }
254
+ end
255
+
256
+ let(:expected_result) do
257
+ [{ "_id" => 0 }, { "_id" => 1 }]
258
+ end
259
+
260
+ # When the last batch runs out, try_next will return nil instead of a
261
+ # document. This test checks that nil is not added to the list of cached
262
+ # documents or returned as a result.
263
+ it 'returns the correct response' do
264
+ expect(authorized_client['test'].find({}, batch_size: 2).to_a).to eq(expected_result)
265
+ expect(authorized_client['test'].find({}, batch_size: 2).to_a).to eq(expected_result)
266
+ end
267
+ end
268
+
269
+ context 'when querying in the same collection' do
270
+
271
+ before do
272
+ 10.times do |i|
273
+ authorized_collection.insert_one(test: i)
274
+ end
275
+ end
276
+
277
+ context 'when query cache is disabled' do
278
+
279
+ before do
280
+ Mongo::QueryCache.enabled = false
281
+ authorized_collection.find(test: 1).to_a
282
+ end
283
+
284
+ it 'queries again' do
285
+ authorized_collection.find(test: 1).to_a
286
+ expect(events.length).to eq(2)
287
+ expect(Mongo::QueryCache.send(:cache_table).length).to eq(0)
288
+ end
289
+ end
290
+
291
+ context 'when query cache is enabled' do
292
+
293
+ before do
294
+ authorized_collection.find(test: 1).to_a
295
+ end
296
+
297
+ it 'does not query again' do
298
+ authorized_collection.find(test: 1).to_a
299
+ expect(events.length).to eq(1)
300
+ expect(Mongo::QueryCache.send(:cache_table).length).to eq(1)
301
+ end
302
+ end
303
+
304
+ context 'when query has collation' do
305
+ min_server_fcv '3.4'
306
+
307
+ let(:options1) do
308
+ { :collation => { locale: 'fr' } }
309
+ end
310
+
311
+ let(:options2) do
312
+ { collation: { locale: 'en_US' } }
313
+ end
314
+
315
+ before do
316
+ authorized_collection.find({ test: 3 }, options1).to_a
317
+ end
318
+
319
+ context 'when query has the same collation' do
320
+
321
+ it 'uses the cache' do
322
+ authorized_collection.find({ test: 3 }, options1).to_a
323
+ expect(events.length).to eq(1)
324
+ end
325
+ end
326
+
327
+ context 'when query has a different collation' do
328
+
329
+ it 'queries again' do
330
+ authorized_collection.find({ test: 3 }, options2).to_a
331
+ expect(events.length).to eq(2)
332
+ expect(Mongo::QueryCache.send(:cache_table)['ruby-driver.collection_spec'].length).to eq(2)
333
+ end
334
+ end
335
+ end
336
+
337
+ describe 'queries with limits' do
338
+ context 'when the first query has no limit and the second does' do
339
+ before do
340
+ authorized_collection.find.to_a.count
341
+ end
342
+
343
+ it 'uses the cache' do
344
+ results_limit_5 = authorized_collection.find.limit(5).to_a
345
+ results_limit_3 = authorized_collection.find.limit(3).to_a
346
+ results_no_limit = authorized_collection.find.to_a
347
+
348
+ expect(results_limit_5.length).to eq(5)
349
+ expect(results_limit_5.map { |r| r["test"] }).to eq([0, 1, 2, 3, 4])
350
+
351
+ expect(results_limit_3.length).to eq(3)
352
+ expect(results_limit_3.map { |r| r["test"] }).to eq([0, 1, 2])
353
+
354
+ expect(results_no_limit.length).to eq(10)
355
+ expect(results_no_limit.map { |r| r["test"] }).to eq([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
356
+
357
+ expect(events.length).to eq(1)
358
+ end
359
+ end
360
+
361
+ context 'when the first query has a limit' do
362
+ before do
363
+ authorized_collection.find.limit(2).to_a
364
+ end
365
+
366
+ context 'and the second query has a larger limit' do
367
+ let(:results) { authorized_collection.find.limit(3).to_a }
368
+
369
+ it 'queries again' do
370
+ expect(results.length).to eq(3)
371
+ expect(results.map { |result| result["test"] }).to eq([0, 1, 2])
372
+ expect(events.length).to eq(2)
373
+ end
374
+ end
375
+
376
+ context 'and two queries are performed with a larger limit' do
377
+ it 'uses the query cache for the third query' do
378
+ results1 = authorized_collection.find.limit(3).to_a
379
+ results2 = authorized_collection.find.limit(3).to_a
380
+
381
+ expect(results1.length).to eq(3)
382
+ expect(results1.map { |r| r["test"] }).to eq([0, 1, 2])
383
+
384
+ expect(results2.length).to eq(3)
385
+ expect(results2.map { |r| r["test"] }).to eq([0, 1, 2])
386
+
387
+ expect(events.length).to eq(2)
388
+ end
389
+ end
390
+
391
+ context 'and the second query has a smaller limit' do
392
+ let(:results) { authorized_collection.find.limit(1).to_a }
393
+
394
+ it 'uses the cached query' do
395
+ expect(results.count).to eq(1)
396
+ expect(results.first["test"]).to eq(0)
397
+ expect(events.length).to eq(1)
398
+ end
399
+ end
400
+
401
+ context 'and the second query has no limit' do
402
+ it 'queries again' do
403
+ expect(authorized_collection.find.to_a.count).to eq(10)
404
+ expect(events.length).to eq(2)
405
+ end
406
+ end
407
+ end
408
+ end
409
+
410
+ context 'when querying only the first' do
411
+
412
+ before do
413
+ 5.times do |i|
414
+ authorized_collection.insert_one(test: 11)
415
+ end
416
+ end
417
+
418
+ before do
419
+ authorized_collection.find({test: 11}).to_a
420
+ end
421
+
422
+ it 'does not query again' do
423
+ expect(authorized_collection.find({test: 11}).count).to eq(5)
424
+ authorized_collection.find({test: 11}).first
425
+ expect(events.length).to eq(1)
426
+ end
427
+
428
+ context 'when limiting the result' do
429
+
430
+ it 'does not query again' do
431
+ authorized_collection.find({test: 11}, limit: 2).to_a
432
+ expect(authorized_collection.find({test: 11}, limit: 2).to_a.count).to eq(2)
433
+ expect(events.length).to eq(1)
434
+ end
435
+ end
436
+ end
437
+
438
+ context 'when specifying a different skip value' do
439
+
440
+ before do
441
+ authorized_collection.find({}, {limit: 2, skip: 3}).to_a
442
+ end
443
+
444
+ it 'queries again' do
445
+ results = authorized_collection.find({}, {limit: 2, skip: 5}).to_a
446
+ expect(results.count).to eq(2)
447
+ expect(events.length).to eq(2)
448
+ end
449
+ end
450
+
451
+ context 'when sorting documents' do
452
+
453
+ before do
454
+ authorized_collection.find({}, desc).to_a
455
+ end
456
+
457
+ let(:desc) do
458
+ { sort: {test: -1} }
459
+ end
460
+
461
+ let(:asc) do
462
+ { sort: {test: 1} }
463
+ end
464
+
465
+ context 'with different selector' do
466
+
467
+ it 'queries again' do
468
+ authorized_collection.find({}, asc).to_a
469
+ expect(events.length).to eq(2)
470
+ end
471
+ end
472
+
473
+ it 'does not query again' do
474
+ authorized_collection.find({}, desc).to_a
475
+ expect(events.length).to eq(1)
476
+ end
477
+ end
478
+
479
+ context 'when inserting new documents' do
480
+ context 'when inserting and querying from same collection' do
481
+ before do
482
+ authorized_collection.find.to_a
483
+ authorized_collection.insert_one({ name: "bob" })
484
+ end
485
+
486
+ it 'queries again' do
487
+ authorized_collection.find.to_a
488
+ expect(events.length).to eq(2)
489
+ end
490
+ end
491
+
492
+ context 'when inserting and querying from different collections' do
493
+ before do
494
+ authorized_collection.find.to_a
495
+ authorized_client['different_collection'].insert_one({ name: "bob" })
496
+ end
497
+
498
+ it 'uses the cached query' do
499
+ authorized_collection.find.to_a
500
+ expect(events.length).to eq(1)
501
+ end
502
+ end
503
+ end
504
+
505
+ [:delete_many, :delete_one].each do |method|
506
+ context "when deleting with #{method}" do
507
+ context 'when deleting and querying from same collection' do
508
+ before do
509
+ authorized_collection.find.to_a
510
+ authorized_collection.send(method)
511
+ end
512
+
513
+ it 'queries again' do
514
+ authorized_collection.find.to_a
515
+ expect(events.length).to eq(2)
516
+ end
517
+ end
518
+
519
+ context 'when deleting and querying from different collections' do
520
+ before do
521
+ authorized_collection.find.to_a
522
+ authorized_client['different_collection'].send(method)
523
+ end
524
+
525
+ it 'uses the cached query' do
526
+ authorized_collection.find.to_a
527
+ expect(events.length).to eq(1)
528
+ end
529
+ end
530
+ end
531
+ end
532
+
533
+ [:find_one_and_delete, :find_one_and_replace, :find_one_and_update,
534
+ :update_one, :replace_one].each do |method|
535
+ context "when updating with #{method}" do
536
+ context 'when updating and querying from same collection' do
537
+ before do
538
+ authorized_collection.find.to_a
539
+ authorized_collection.send(method, { field: 'value' }, { field: 'new value' })
540
+ end
541
+
542
+ it 'queries again' do
543
+ authorized_collection.find.to_a
544
+ expect(events.length).to eq(2)
545
+ end
546
+ end
547
+
548
+ context 'when updating and querying from different collections' do
549
+ before do
550
+ authorized_collection.find.to_a
551
+ authorized_client['different_collection'].send(method, { field: 'value' }, { field: 'new value' })
552
+ end
553
+
554
+ it 'uses the cached query' do
555
+ authorized_collection.find.to_a
556
+ expect(events.length).to eq(1)
557
+ end
558
+ end
559
+ end
560
+ end
561
+
562
+ context 'when updating with #update_many' do
563
+ context 'when updating and querying from same collection' do
564
+ before do
565
+ authorized_collection.find.to_a
566
+ authorized_collection.update_many({ field: 'value' }, { "$inc" => { :field => 1 } })
567
+ end
568
+
569
+ it 'queries again' do
570
+ authorized_collection.find.to_a
571
+ expect(events.length).to eq(2)
572
+ end
573
+ end
574
+
575
+ context 'when updating and querying from different collections' do
576
+ before do
577
+ authorized_collection.find.to_a
578
+ authorized_client['different_collection'].update_many({ field: 'value' }, { "$inc" => { :field => 1 } })
579
+ end
580
+
581
+ it 'uses the cached query' do
582
+ authorized_collection.find.to_a
583
+ expect(events.length).to eq(1)
584
+ end
585
+ end
586
+ end
587
+
588
+ context 'when performing bulk write' do
589
+ context 'with insert_one' do
590
+ context 'when inserting and querying from same collection' do
591
+ before do
592
+ authorized_collection.find.to_a
593
+ authorized_collection.bulk_write([ { insert_one: { name: 'bob' } } ])
594
+ end
595
+
596
+ it 'queries again' do
597
+ authorized_collection.find.to_a
598
+ expect(events.length).to eq(2)
599
+ end
600
+ end
601
+
602
+ context 'when inserting and querying from different collection' do
603
+ before do
604
+ authorized_collection.find.to_a
605
+ authorized_client['different_collection'].bulk_write(
606
+ [ { insert_one: { name: 'bob' } } ]
607
+ )
608
+ end
609
+
610
+ it 'uses the cached query' do
611
+ authorized_collection.find.to_a
612
+ expect(events.length).to eq(1)
613
+ end
614
+ end
615
+ end
616
+
617
+ [:update_one, :update_many].each do |method|
618
+ context "with #{method}" do
619
+ context 'when updating and querying from same collection' do
620
+ before do
621
+ authorized_collection.find.to_a
622
+ authorized_collection.bulk_write([
623
+ {
624
+ method => {
625
+ filter: { field: 'value' },
626
+ update: { '$set' => { field: 'new value' } }
627
+ }
628
+ }
629
+ ])
630
+ end
631
+
632
+ it 'queries again' do
633
+ authorized_collection.find.to_a
634
+ expect(events.length).to eq(2)
635
+ end
636
+ end
637
+
638
+ context 'when updating and querying from different collection' do
639
+ before do
640
+ authorized_collection.find.to_a
641
+ authorized_client['different_collection'].bulk_write([
642
+ {
643
+ method => {
644
+ filter: { field: 'value' },
645
+ update: { '$set' => { field: 'new value' } }
646
+ }
647
+ }
648
+ ])
649
+ end
650
+
651
+ it 'uses the cached query' do
652
+ authorized_collection.find.to_a
653
+ expect(events.length).to eq(1)
654
+ end
655
+ end
656
+ end
657
+ end
658
+
659
+ [:delete_one, :delete_many].each do |method|
660
+ context "with #{method}" do
661
+ context 'when delete and querying from same collection' do
662
+ before do
663
+ authorized_collection.find.to_a
664
+ authorized_collection.bulk_write([
665
+ {
666
+ method => {
667
+ filter: { field: 'value' },
668
+ }
669
+ }
670
+ ])
671
+ end
672
+
673
+ it 'queries again' do
674
+ authorized_collection.find.to_a
675
+ expect(events.length).to eq(2)
676
+ end
677
+ end
678
+
679
+ context 'when delete and querying from different collection' do
680
+ before do
681
+ authorized_collection.find.to_a
682
+ authorized_client['different_collection'].bulk_write([
683
+ {
684
+ method => {
685
+ filter: { field: 'value' },
686
+ }
687
+ }
688
+ ])
689
+ end
690
+
691
+ it 'uses the cached query' do
692
+ authorized_collection.find.to_a
693
+ expect(events.length).to eq(1)
694
+ end
695
+ end
696
+ end
697
+ end
698
+
699
+ context 'with replace_one' do
700
+ context 'when replacing and querying from same collection' do
701
+ before do
702
+ authorized_collection.find.to_a
703
+ authorized_collection.bulk_write([
704
+ {
705
+ replace_one: {
706
+ filter: { field: 'value' },
707
+ replacement: { field: 'new value' }
708
+ }
709
+ }
710
+ ])
711
+ end
712
+
713
+ it 'queries again' do
714
+ authorized_collection.find.to_a
715
+ expect(events.length).to eq(2)
716
+ end
717
+ end
718
+
719
+ context 'when replacing and querying from different collection' do
720
+ before do
721
+ authorized_collection.find.to_a
722
+ authorized_client['different_collection'].bulk_write([
723
+ {
724
+ replace_one: {
725
+ filter: { field: 'value' },
726
+ replacement: { field: 'new value' }
727
+ }
728
+ }
729
+ ])
730
+ end
731
+
732
+ it 'uses the cached query' do
733
+ authorized_collection.find.to_a
734
+ expect(events.length).to eq(1)
735
+ end
736
+ end
737
+ end
738
+
739
+ context 'when query occurs between bulk write creation and execution' do
740
+ before do
741
+ authorized_collection.delete_many
742
+ end
743
+
744
+ it 'queries again' do
745
+ bulk_write = Mongo::BulkWrite.new(
746
+ authorized_collection,
747
+ [{ insert_one: { test: 1 } }]
748
+ )
749
+
750
+ expect(authorized_collection.find(test: 1).to_a.length).to eq(0)
751
+ bulk_write.execute
752
+ expect(authorized_collection.find(test: 1).to_a.length).to eq(1)
753
+ expect(events.length).to eq(2)
754
+ end
755
+ end
756
+ end
757
+
758
+ context 'when aggregating with $out' do
759
+ before do
760
+ authorized_collection.find.to_a
761
+ authorized_collection.aggregate([
762
+ { '$match' => { test: 1 } },
763
+ { '$out' => { coll: 'new_coll' } }
764
+ ])
765
+ end
766
+
767
+ it 'queries again' do
768
+ authorized_collection.find.to_a
769
+ expect(events.length).to eq(2)
770
+ end
771
+
772
+ it 'clears the cache' do
773
+ expect(Mongo::QueryCache.send(:cache_table)).to be_empty
774
+ end
775
+ end
776
+
777
+ context 'when aggregating with $merge' do
778
+ min_server_fcv '4.2'
779
+
780
+ before do
781
+ authorized_collection.delete_many
782
+ authorized_collection.find.to_a
783
+ authorized_collection.aggregate([
784
+ { '$match' => { 'test' => 1 } },
785
+ { '$merge' => {
786
+ into: {
787
+ db: SpecConfig.instance.test_db,
788
+ coll: 'new_coll',
789
+ },
790
+ on: "_id",
791
+ whenMatched: "replace",
792
+ whenNotMatched: "insert",
793
+ }
794
+ }
795
+ ])
796
+ end
797
+
798
+ it 'queries again' do
799
+ authorized_collection.find.to_a
800
+ expect(events.length).to eq(2)
801
+ end
802
+
803
+ it 'clears the cache' do
804
+ expect(Mongo::QueryCache.send(:cache_table)).to be_empty
805
+ end
806
+ end
807
+ end
808
+
809
+ context 'when aggregating' do
810
+ before do
811
+ 3.times { authorized_collection.insert_one(test: 1) }
812
+ end
813
+
814
+ let(:events) do
815
+ subscriber.command_started_events('aggregate')
816
+ end
817
+
818
+ let(:aggregation) do
819
+ authorized_collection.aggregate([ { '$match' => { test: 1 } } ])
820
+ end
821
+
822
+ it 'caches the aggregation' do
823
+ expect(aggregation.to_a.length).to eq(3)
824
+ expect(aggregation.to_a.length).to eq(3)
825
+ expect(events.length).to eq(1)
826
+ end
827
+
828
+ context 'with read concern' do
829
+ require_wired_tiger
830
+ min_server_fcv '3.6'
831
+
832
+ let(:aggregation_read_concern) do
833
+ authorized_client['collection_spec', { read_concern: { level: :local } }]
834
+ .aggregate([ { '$match' => { test: 1 } } ])
835
+ end
836
+
837
+ it 'queries twice' do
838
+ expect(aggregation.to_a.length).to eq(3)
839
+ expect(aggregation_read_concern.to_a.length).to eq(3)
840
+ expect(events.length).to eq(2)
841
+ end
842
+ end
843
+
844
+ context 'with read preference' do
845
+ let(:aggregation_read_preference) do
846
+ authorized_client['collection_spec', { read: { mode: :primary } }]
847
+ .aggregate([ { '$match' => { test: 1 } } ])
848
+ end
849
+
850
+ it 'queries twice' do
851
+ expect(aggregation.to_a.length).to eq(3)
852
+ expect(aggregation_read_preference.to_a.length).to eq(3)
853
+ expect(events.length).to eq(2)
854
+ end
855
+ end
856
+
857
+ context 'when collation is specified' do
858
+ min_server_fcv '3.4'
859
+
860
+ let(:aggregation_collation) do
861
+ authorized_collection.aggregate(
862
+ [ { '$match' => { test: 1 } } ],
863
+ { collation: { locale: 'fr' } }
864
+ )
865
+ end
866
+
867
+ it 'queries twice' do
868
+ expect(aggregation.to_a.length).to eq(3)
869
+ expect(aggregation_collation.to_a.length).to eq(3)
870
+ expect(events.length).to eq(2)
871
+ end
872
+ end
873
+
874
+ context 'when insert_one is performed on another collection' do
875
+ before do
876
+ aggregation.to_a
877
+ authorized_client['different_collection'].insert_one(name: 'bob')
878
+ aggregation.to_a
879
+ end
880
+
881
+ it 'queries again' do
882
+ expect(events.length).to eq(2)
883
+ end
884
+ end
885
+
886
+ context 'when insert_many is performed on another collection' do
887
+ before do
888
+ aggregation.to_a
889
+ authorized_client['different_collection'].insert_many([name: 'bob'])
890
+ aggregation.to_a
891
+ end
892
+
893
+ it 'queries again' do
894
+ expect(events.length).to eq(2)
895
+ end
896
+ end
897
+
898
+ [:delete_many, :delete_one].each do |method|
899
+ context "when #{method} is performed on another collection" do
900
+ before do
901
+ aggregation.to_a
902
+ authorized_client['different_collection'].send(method)
903
+ aggregation.to_a
904
+ end
905
+
906
+ it 'queries again' do
907
+ expect(events.length).to eq(2)
908
+ end
909
+ end
910
+ end
911
+
912
+ [:find_one_and_delete, :find_one_and_replace, :find_one_and_update,
913
+ :update_one, :replace_one].each do |method|
914
+ context "when #{method} is performed on another collection" do
915
+ before do
916
+ aggregation.to_a
917
+ authorized_client['different_collection'].send(method, { field: 'value' }, { field: 'new value' })
918
+ aggregation.to_a
919
+ end
920
+
921
+ it 'queries again' do
922
+ expect(events.length).to eq(2)
923
+ end
924
+ end
925
+ end
926
+
927
+ context 'when update_many is performed on another collection' do
928
+ before do
929
+ aggregation.to_a
930
+ authorized_client['different_collection'].update_many({ field: 'value' }, { "$inc" => { :field => 1 } })
931
+ aggregation.to_a
932
+ end
933
+
934
+ it 'queries again' do
935
+ expect(events.length).to eq(2)
936
+ end
937
+ end
938
+
939
+ context '#count_documents' do
940
+ context 'on same collection' do
941
+ it 'caches the query' do
942
+ expect(authorized_collection.count_documents(test: 1)).to eq(3)
943
+ expect(authorized_collection.count_documents(test: 1)).to eq(3)
944
+
945
+ expect(events.length).to eq(1)
946
+ end
947
+ end
948
+
949
+ context 'on different collections' do
950
+ let(:other_collection) { authorized_client['other_collection'] }
951
+
952
+ before do
953
+ other_collection.drop
954
+ 6.times { other_collection.insert_one(test: 1) }
955
+ end
956
+
957
+ it 'caches the query' do
958
+ expect(authorized_collection.count_documents(test: 1)).to eq(3)
959
+ expect(other_collection.count_documents(test: 1)).to eq(6)
960
+
961
+ expect(events.length).to eq(2)
962
+ end
963
+ end
964
+ end
965
+ end
966
+
967
+ context 'when find command fails and retries' do
968
+ require_fail_command
969
+ require_no_multi_shard
970
+ require_warning_clean
971
+
972
+ before do
973
+ 5.times do |i|
974
+ authorized_collection.insert_one(test: i)
975
+ end
976
+ end
977
+
978
+ before do
979
+ client.use('admin').command(
980
+ configureFailPoint: 'failCommand',
981
+ mode: { times: 1 },
982
+ data: {
983
+ failCommands: ['find'],
984
+ closeConnection: true
985
+ }
986
+ )
987
+ end
988
+
989
+ let(:command_name) { 'find' }
990
+
991
+ it 'uses modern retryable reads when using query cache' do
992
+ expect(Mongo::QueryCache.enabled?).to be(true)
993
+
994
+ expect(Mongo::Logger.logger).to receive(:warn).once.with(/modern.*attempt 1/).and_call_original
995
+ authorized_collection.find(test: 1).to_a
996
+ expect(Mongo::QueryCache.send(:cache_table).length).to eq(1)
997
+ expect(subscriber.command_started_events('find').length).to eq(2)
998
+
999
+ authorized_collection.find(test: 1).to_a
1000
+ expect(Mongo::QueryCache.send(:cache_table).length).to eq(1)
1001
+ expect(subscriber.command_started_events('find').length).to eq(2)
1002
+ end
1003
+ end
1004
+
1005
+ context 'when querying in a different collection' do
1006
+
1007
+ let(:database) { client.database }
1008
+
1009
+ let(:new_collection) do
1010
+ Mongo::Collection.new(database, 'foo')
1011
+ end
1012
+
1013
+ before do
1014
+ authorized_collection.find.to_a
1015
+ end
1016
+
1017
+ it 'queries again' do
1018
+ new_collection.find.to_a
1019
+ expect(Mongo::QueryCache.send(:cache_table).length).to eq(2)
1020
+ expect(events.length).to eq(2)
1021
+ end
1022
+ end
1023
+
1024
+ context 'with system collection' do
1025
+ let(:client) do
1026
+ ClientRegistry.instance.global_client('root_authorized').tap do |client|
1027
+ client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
1028
+ end
1029
+ end
1030
+
1031
+ before do
1032
+ begin
1033
+ client.database.users.remove('alanturing')
1034
+ rescue Mongo::Error::OperationFailure
1035
+ # can be user not found, ignore
1036
+ end
1037
+ end
1038
+
1039
+ it 'does not use the query cache' do
1040
+ client['system.users'].find.to_a
1041
+ client['system.users'].find.to_a
1042
+ expect(events.length).to eq(2)
1043
+ end
1044
+ end
1045
+ end