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
@@ -11,14 +11,6 @@ module Mongo
11
11
  def initialize(test_path)
12
12
  contents = File.read(test_path)
13
13
 
14
- # Since Ruby driver binds a client to a database, change the
15
- # database name in the spec to the one we are using
16
- contents.sub!(/"crud-tests"/, '"ruby-driver"')
17
- contents.sub!(/"retryable-reads-tests"/, '"ruby-driver"')
18
- contents.sub!(/"transaction-tests"/, '"ruby-driver"')
19
- contents.sub!(/"withTransaction-tests"/, '"ruby-driver"')
20
- contents.sub!(/ default_write_concern_db/, ' ruby-driver')
21
-
22
14
  @spec = YAML.load(contents)
23
15
  @description = File.basename(test_path)
24
16
  @data = BSON::ExtJSON.parse_obj(@spec['data'])
@@ -28,7 +28,7 @@ module Mongo
28
28
  @spec = crud_spec
29
29
  @data = data
30
30
  @description = test['description']
31
- @client_options = Utils.convert_client_options(test['clientOptions'] || {})
31
+ @client_options = ::Utils.convert_client_options(test['clientOptions'] || {})
32
32
 
33
33
  if test['failPoint']
34
34
  @fail_point_command = FAIL_POINT_BASE_COMMAND.merge(test['failPoint'])
@@ -45,25 +45,6 @@ module Mongo
45
45
  raise "Unknown target #{operation.object}"
46
46
  end
47
47
  end
48
-
49
- # If the deployment is a sharded cluster, creates a direct client
50
- # to each of the mongos nodes and yields each in turn to the
51
- # provided block. Does nothing in other topologies.
52
- def mongos_each_direct_client
53
- if ClusterConfig.instance.topology == :sharded
54
- client = ClientRegistry.instance.global_client('basic')
55
- client.cluster.next_primary
56
- client.cluster.servers.each do |server|
57
- direct_client = ClientRegistry.instance.new_local_client(
58
- [server.address.to_s],
59
- SpecConfig.instance.test_options.merge(
60
- connect: :sharded
61
- ).merge(SpecConfig.instance.auth_options))
62
- yield direct_client
63
- direct_client.close
64
- end
65
- end
66
- end
67
48
  end
68
49
  end
69
50
  end
@@ -149,7 +149,7 @@ module Mongo
149
149
  end
150
150
 
151
151
  def when
152
- Utils.underscore(@spec.fetch('when'))
152
+ ::Utils.underscore(@spec.fetch('when'))
153
153
  end
154
154
 
155
155
  def max_wire_version
@@ -161,7 +161,7 @@ module Mongo
161
161
  end
162
162
 
163
163
  def type
164
- Utils.underscore(@spec.fetch('type'))
164
+ ::Utils.underscore(@spec.fetch('type'))
165
165
  end
166
166
 
167
167
  def result
@@ -73,19 +73,6 @@ module Mongo
73
73
  @type = Mongo::Cluster::Topology.const_get(@test['topology_description']['type'])
74
74
  end
75
75
 
76
- # Whether this spec describes a replica set.
77
- #
78
- # @example Determine if the spec describes a replica set.
79
- # spec.replica_set?
80
- #
81
- # @return [true, false] If the spec describes a replica set.
82
- #
83
- # @since 2.0.0
84
- def replica_set?
85
- type == Mongo::Cluster::Topology::ReplicaSetNoPrimary ||
86
- type == Mongo::Cluster::Topology::ReplicaSetWithPrimary
87
- end
88
-
89
76
  # Does this spec expect a server to be found.
90
77
  #
91
78
  # @example Will a server be found with this spec.
@@ -98,15 +85,10 @@ module Mongo
98
85
  !in_latency_window.empty?
99
86
  end
100
87
 
101
- # Is the max staleness setting invalid.
88
+ # Whether the test requires an error to be raised during server selection.
102
89
  #
103
- # @example Will the max staleness setting be valid with other options.
104
- # spec.invalid_max_staleness?
105
- #
106
- # @return [ true, false ] If an error will be raised by the max staleness setting.
107
- #
108
- # @since 2.4.0
109
- def invalid_max_staleness?
90
+ # @return [ true, false ] Whether the test expects an error.
91
+ def error?
110
92
  @test['error']
111
93
  end
112
94
 
@@ -122,9 +104,6 @@ module Mongo
122
104
  #
123
105
  # @since 2.0.0
124
106
  def in_latency_window
125
- if read_preference['mode'] == :secondary_preferred && primary
126
- return @in_latency_window.push(primary).uniq
127
- end
128
107
  @in_latency_window
129
108
  end
130
109
 
@@ -134,13 +113,248 @@ module Mongo
134
113
  #
135
114
  # @since 2.0.0
136
115
  def candidate_servers
137
- @candidate_servers.select { |s| !['Unknown', 'PossiblePrimary'].include?(s['type']) }
116
+ @candidate_servers
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ def define_server_selection_spec_tests(test_paths)
124
+ # Linter insists that a server selection semaphore is present when
125
+ # performing server selection.
126
+ require_no_linting
127
+
128
+ test_paths.each do |file|
129
+
130
+ spec = Mongo::ServerSelection::Read::Spec.new(file)
131
+
132
+ context(spec.description) do
133
+ # Cluster needs a topology and topology needs a cluster...
134
+ # This temporary cluster is used for topology construction.
135
+ let(:temp_cluster) do
136
+ double('temp cluster').tap do |cluster|
137
+ allow(cluster).to receive(:servers_list).and_return([])
138
+ end
139
+ end
140
+
141
+ let(:topology) do
142
+ options = if spec.type <= Mongo::Cluster::Topology::ReplicaSetNoPrimary
143
+ {replica_set_name: 'foo'}
144
+ else
145
+ {}
146
+ end
147
+ spec.type.new(options, monitoring, temp_cluster)
148
+ end
149
+
150
+ let(:monitoring) do
151
+ Mongo::Monitoring.new(monitoring: false)
152
+ end
153
+
154
+ let(:listeners) do
155
+ Mongo::Event::Listeners.new
156
+ end
157
+
158
+ let(:options) do
159
+ if spec.heartbeat_frequency
160
+ {server_selection_timeout: 0.1, heartbeat_frequency: spec.heartbeat_frequency}
161
+ else
162
+ {server_selection_timeout: 0.1}
163
+ end
164
+ end
165
+
166
+ let(:cluster) do
167
+ double('cluster').tap do |c|
168
+ allow(c).to receive(:server_selection_semaphore)
169
+ allow(c).to receive(:connected?).and_return(true)
170
+ allow(c).to receive(:summary)
171
+ allow(c).to receive(:topology).and_return(topology)
172
+ allow(c).to receive(:single?).and_return(topology.single?)
173
+ allow(c).to receive(:sharded?).and_return(topology.sharded?)
174
+ allow(c).to receive(:replica_set?).and_return(topology.replica_set?)
175
+ allow(c).to receive(:unknown?).and_return(topology.unknown?)
176
+ allow(c).to receive(:options).and_return(options)
177
+ allow(c).to receive(:scan!).and_return(true)
178
+ allow(c).to receive(:app_metadata).and_return(app_metadata)
179
+ allow(c).to receive(:heartbeat_interval).and_return(
180
+ spec.heartbeat_frequency || Mongo::Server::Monitor::DEFAULT_HEARTBEAT_INTERVAL)
138
181
  end
182
+ end
183
+
184
+ # One of the spec test assertions is on the set of servers that are
185
+ # eligible for selection without taking latency into account.
186
+ # In the driver, latency is taken into account at various points during
187
+ # server selection, hence there isn't a method that can be called to
188
+ # retrieve the list of servers without accounting for latency.
189
+ # Work around this by executing server selection with all servers set
190
+ # to zero latency, when evaluating the candidate server set.
191
+ let(:ignore_latency) { false }
192
+
193
+ let(:candidate_servers) do
194
+ spec.candidate_servers.collect do |server|
195
+ features = double('features').tap do |feat|
196
+ allow(feat).to receive(:max_staleness_enabled?).and_return(server['maxWireVersion'] && server['maxWireVersion'] >= 5)
197
+ allow(feat).to receive(:check_driver_support!).and_return(true)
198
+ end
199
+ address = Mongo::Address.new(server['address'])
200
+ Mongo::Server.new(address, cluster, monitoring, listeners,
201
+ {monitoring_io: false}.update(options)
202
+ ).tap do |s|
203
+ allow(s).to receive(:average_round_trip_time) do
204
+ if ignore_latency
205
+ 0
206
+ elsif server['avg_rtt_ms']
207
+ server['avg_rtt_ms'] / 1000.0
208
+ end
209
+ end
210
+ allow(s).to receive(:tags).and_return(server['tags'])
211
+ allow(s).to receive(:secondary?).and_return(server['type'] == 'RSSecondary')
212
+ allow(s).to receive(:primary?).and_return(server['type'] == 'RSPrimary')
213
+ allow(s).to receive(:mongos?).and_return(server['type'] == 'Mongos')
214
+ allow(s).to receive(:standalone?).and_return(server['type'] == 'Standalone')
215
+ allow(s).to receive(:unknown?).and_return(server['type'] == 'Unknown')
216
+ allow(s).to receive(:connectable?).and_return(true)
217
+ allow(s).to receive(:last_write_date).and_return(
218
+ Time.at(server['lastWrite']['lastWriteDate']['$numberLong'].to_f / 1000)) if server['lastWrite']
219
+ allow(s).to receive(:last_scan).and_return(
220
+ Time.at(server['lastUpdateTime'].to_f / 1000))
221
+ allow(s).to receive(:features).and_return(features)
222
+ allow(s).to receive(:replica_set_name).and_return('foo')
223
+ end
224
+ end
225
+ end
226
+
227
+ let(:suitable_servers) do
228
+ spec.suitable_servers.collect do |server|
229
+ Mongo::Server.new(Mongo::Address.new(server['address']), cluster, monitoring, listeners,
230
+ options.merge(monitoring_io: false))
231
+ end
232
+ end
139
233
 
140
- private
234
+ let(:in_latency_window) do
235
+ spec.in_latency_window.collect do |server|
236
+ Mongo::Server.new(Mongo::Address.new(server['address']), cluster, monitoring, listeners,
237
+ options.merge(monitoring_io: false))
238
+ end
239
+ end
240
+
241
+ let(:server_selector_definition) do
242
+ { mode: spec.read_preference['mode'] }.tap do |definition|
243
+ definition[:tag_sets] = spec.read_preference['tag_sets']
244
+ definition[:max_staleness] = spec.max_staleness if spec.max_staleness
245
+ end
246
+ end
247
+
248
+ let(:server_selector) do
249
+ Mongo::ServerSelector.get(server_selector_definition)
250
+ end
251
+
252
+ let(:app_metadata) do
253
+ Mongo::Server::AppMetadata.new({})
254
+ end
255
+
256
+ before do
257
+ allow(cluster).to receive(:servers_list).and_return(candidate_servers)
258
+ allow(cluster).to receive(:servers) do
259
+ # Copy Cluster#servers definition because clusters is a double
260
+ cluster.topology.servers(cluster.servers_list)
261
+ end
262
+ allow(cluster).to receive(:addresses).and_return(candidate_servers.map(&:address))
263
+ end
264
+
265
+ if spec.error?
266
+
267
+ it 'Raises an InvalidServerPreference exception' do
268
+
269
+ expect do
270
+ server_selector.select_server(cluster)
271
+ end.to raise_exception(Mongo::Error::InvalidServerPreference)
272
+ end
273
+
274
+ else
275
+
276
+ if spec.server_available?
277
+
278
+ it 'has non-empty suitable servers' do
279
+ spec.suitable_servers.should be_a(Array)
280
+ spec.suitable_servers.should_not be_empty
281
+ end
282
+
283
+ if spec.in_latency_window.length == 1
284
+
285
+ it 'selects the expected server' do
286
+ [server_selector.select_server(cluster)].should == in_latency_window
287
+ end
288
+
289
+ else
290
+
291
+ it 'selects a server in the suitable list' do
292
+ in_latency_window.should include(server_selector.select_server(cluster))
293
+ end
294
+
295
+ let(:expected_addresses) do
296
+ in_latency_window.map(&:address).map(&:seed).sort
297
+ end
298
+
299
+ let(:actual_addresses) do
300
+ server_selector.suitable_servers(cluster).map(&:address).map(&:seed).sort
301
+ end
302
+
303
+ it 'identifies expected suitable servers' do
304
+ actual_addresses.should == expected_addresses
305
+ end
306
+
307
+ end
308
+
309
+ context 'candidate servers without taking latency into account' do
310
+ let(:ignore_latency) { true }
311
+
312
+ let(:expected_addresses) do
313
+ suitable_servers.map(&:address).map(&:seed).sort
314
+ end
315
+
316
+ let(:actual_addresses) do
317
+ servers = server_selector.send(:suitable_servers, cluster)
318
+
319
+ # The tests expect that only secondaries are "suitable" for
320
+ # server selection with secondary preferred read preference.
321
+ # In actuality, primaries are also suitable, and the driver
322
+ # returns the primaries also. Remove primaries from the
323
+ # actual set when read preference is secondary preferred.
324
+ # HOWEVER, if a test ends up selecting a primary, then it
325
+ # includes that primary into its suitable servers. Therefore
326
+ # only remove primaries when the number of suitable servers
327
+ # is greater than 1.
328
+ servers.delete_if do |server|
329
+ server_selector.is_a?(Mongo::ServerSelector::SecondaryPreferred) &&
330
+ server.primary? &&
331
+ servers.length > 1
332
+ end
333
+
334
+ # Since we remove the latency requirement, the servers
335
+ # may be returned in arbitrary order.
336
+ servers.map(&:address).map(&:seed).sort
337
+ end
338
+
339
+ it 'identifies expected suitable servers' do
340
+ actual_addresses.should == expected_addresses
341
+ end
342
+ end
343
+
344
+ else
345
+
346
+ # Runner does not handle non-empty suitable servers with
347
+ # no servers in latency window.
348
+ it 'has empty suitable servers' do
349
+ expect(spec.suitable_servers).to eq([])
350
+ end
351
+
352
+ it 'Raises a NoServerAvailable Exception' do
353
+ expect do
354
+ server_selector.select_server(cluster)
355
+ end.to raise_exception(Mongo::Error::NoServerAvailable)
356
+ end
141
357
 
142
- def primary
143
- @candidate_servers.find { |s| s['type'] == 'RSPrimary' }
144
358
  end
145
359
  end
146
360
  end
@@ -12,7 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require 'runners/transactions/context'
16
15
  require 'runners/transactions/operation'
17
16
  require 'runners/transactions/spec'
18
17
  require 'runners/transactions/test'
@@ -26,21 +25,22 @@ def define_transactions_spec_tests(test_paths)
26
25
  context(spec.description) do
27
26
 
28
27
  define_spec_tests_with_requirements(spec) do |req|
28
+
29
29
  spec.tests.each do |test|
30
30
 
31
- before do
32
- if ClusterConfig.instance.topology == :sharded
33
- if test.multiple_mongoses? && SpecConfig.instance.addresses.length == 1
34
- skip "Test requires multiple mongoses"
35
- elsif !test.multiple_mongoses? && SpecConfig.instance.addresses.length > 1
36
- # Many transaction spec tests that do not specifically deal with
37
- # sharded transactions fail when run against a multi-mongos cluster
38
- skip "Test does not specify multiple mongoses"
31
+ context(test.description) do
32
+
33
+ before(:all) do
34
+ if ClusterConfig.instance.topology == :sharded
35
+ if test.multiple_mongoses? && SpecConfig.instance.addresses.length == 1
36
+ skip "Test requires multiple mongoses"
37
+ elsif !test.multiple_mongoses? && SpecConfig.instance.addresses.length > 1
38
+ # Many transaction spec tests that do not specifically deal with
39
+ # sharded transactions fail when run against a multi-mongos cluster
40
+ skip "Test does not specify multiple mongoses"
41
+ end
39
42
  end
40
43
  end
41
- end
42
-
43
- context(test.description) do
44
44
 
45
45
  if test.skip_reason
46
46
  before(:all) do
@@ -21,23 +21,8 @@ module Mongo
21
21
  arguments && arguments['session'] || object =~ /session/
22
22
  end
23
23
 
24
- def execute(target, session0, session1, active_session=nil)
25
- session = case arguments && arguments['session']
26
- when 'session0'
27
- session0
28
- when 'session1'
29
- session1
30
- else
31
- # active session could be nil
32
- active_session
33
- end
34
-
35
- context = Context.new(
36
- session0,
37
- session1,
38
- session)
39
-
40
- op_name = Utils.underscore(name).to_sym
24
+ def execute(target, context)
25
+ op_name = ::Utils.underscore(name).to_sym
41
26
  if op_name == :with_transaction
42
27
  args = [target]
43
28
  else
@@ -53,9 +38,14 @@ module Mongo
53
38
  result['error'] = false
54
39
  end
55
40
  end
41
+
56
42
  result
57
43
  rescue Mongo::Error::OperationFailure => e
58
- err_doc = e.instance_variable_get(:@result).send(:first_document)
44
+ result = e.instance_variable_get(:@result)
45
+ if result.nil?
46
+ raise "OperationFailure had nil result: #{e}"
47
+ end
48
+ err_doc = result.send(:first_document)
59
49
  error_code_name = err_doc['codeName'] || err_doc['writeConcernError'] && err_doc['writeConcernError']['codeName']
60
50
  if error_code_name.nil?
61
51
  # Sometimes the server does not return the error code name,
@@ -102,13 +92,13 @@ module Mongo
102
92
  command_value = cmd.delete(command_name)
103
93
  cmd = { command_name.to_sym => command_value }.merge(cmd)
104
94
 
105
- opts = Utils.snakeize_hash(context.transform_arguments(options)).dup
95
+ opts = ::Utils.snakeize_hash(transformed_options(context)).dup
106
96
  opts[:read] = opts.delete(:read_preference)
107
97
  database.command(cmd, opts).documents.first
108
98
  end
109
99
 
110
100
  def start_transaction(session, context)
111
- session.start_transaction(Utils.convert_operation_options(arguments['options']))
101
+ session.start_transaction(::Utils.convert_operation_options(arguments['options']))
112
102
  nil
113
103
  end
114
104
 
@@ -128,7 +118,7 @@ module Mongo
128
118
  end
129
119
 
130
120
  if arguments['options']
131
- options = Utils.snakeize_hash(arguments['options'])
121
+ options = ::Utils.snakeize_hash(arguments['options'])
132
122
  else
133
123
  options = nil
134
124
  end
@@ -136,7 +126,7 @@ module Mongo
136
126
  callback['operations'].each do |op_spec|
137
127
  op = Operation.new(@crud_test, op_spec)
138
128
  target = @crud_test.resolve_target(@crud_test.test_client, op)
139
- rv = op.execute(target, context.session0, context.session1, session)
129
+ rv = op.execute(target, context)
140
130
  if rv && rv['exception']
141
131
  raise rv['exception']
142
132
  end
@@ -151,7 +141,7 @@ module Mongo
151
141
  end
152
142
 
153
143
  def targeted_fail_point(collection, context)
154
- args = context.transform_arguments(options)
144
+ args = transformed_options(context)
155
145
  session = args[:session]
156
146
  unless session.pinned_server
157
147
  raise ArgumentError, 'Targeted fail point requires session to be pinned to a server'
@@ -169,7 +159,7 @@ module Mongo
169
159
  end
170
160
 
171
161
  def assert_session_pinned(collection, context)
172
- args = context.transform_arguments(options)
162
+ args = transformed_options(context)
173
163
  session = args[:session]
174
164
  unless session.pinned_server
175
165
  raise ArgumentError, 'Expected session to be pinned'
@@ -177,12 +167,148 @@ module Mongo
177
167
  end
178
168
 
179
169
  def assert_session_unpinned(collection, context)
180
- args = context.transform_arguments(options)
170
+ args = transformed_options(context)
181
171
  session = args[:session]
182
172
  if session.pinned_server
183
173
  raise ArgumentError, 'Expected session to not be pinned'
184
174
  end
185
175
  end
176
+
177
+ def wait_for_event(client, context)
178
+ deadline = Time.now + 5
179
+ loop do
180
+ events = _select_events(context)
181
+ if events.length >= arguments['count']
182
+ break
183
+ end
184
+ if Time.now >= deadline
185
+ raise "Did not receive an event matching #{arguments} in 5 seconds; received #{events.length} but expected #{arguments['count']} events"
186
+ else
187
+ sleep 0.1
188
+ end
189
+ end
190
+ end
191
+
192
+ def assert_event_count(client, context)
193
+ events = _select_events(context)
194
+ unless events.length == arguments['count']
195
+ raise "Exppected #{arguments['count']} #{arguments['event']} events, but have #{events.length}"
196
+ end
197
+ end
198
+
199
+ def _select_events(context)
200
+ case arguments['event']
201
+ when 'ServerMarkedUnknownEvent'
202
+ context.sdam_subscriber.all_events.select do |event|
203
+ event.is_a?(Mongo::Monitoring::Event::ServerDescriptionChanged) &&
204
+ event.new_description.unknown?
205
+ end
206
+ else
207
+ context.sdam_subscriber.all_events.select do |event|
208
+ event.class.name.sub(/.*::/, '') == arguments['event'].sub(/Event$/, '')
209
+ end
210
+ end
211
+ end
212
+
213
+ class ThreadContext
214
+ def initialize
215
+ @operations = Queue.new
216
+ @unexpected_operation_results = []
217
+ end
218
+
219
+ def stop?
220
+ !!@stop
221
+ end
222
+
223
+ def signal_stop
224
+ @stop = true
225
+ end
226
+
227
+ attr_reader :operations
228
+ attr_reader :unexpected_operation_results
229
+ end
230
+
231
+ def start_thread(client, context)
232
+ thread_context = ThreadContext.new
233
+ thread = Thread.new do
234
+ loop do
235
+ begin
236
+ op_spec = thread_context.operations.pop(true)
237
+ op = Operation.new(@crud_test, op_spec)
238
+ target = @crud_test.resolve_target(@crud_test.test_client, op)
239
+ result = op.execute(target, context)
240
+ if op_spec['error']
241
+ unless result['error']
242
+ thread_context.unexpected_operation_results << result
243
+ end
244
+ else
245
+ if result['error']
246
+ thread_context.unexpected_operation_results << result
247
+ end
248
+ end
249
+ rescue ThreadError
250
+ # Queue is empty
251
+ end
252
+ if thread_context.stop?
253
+ break
254
+ else
255
+ sleep 1
256
+ end
257
+ end
258
+ end
259
+ class << thread
260
+ attr_accessor :context
261
+ end
262
+ thread.context = thread_context
263
+ unless context.threads
264
+ context.threads ||= {}
265
+ end
266
+ context.threads[arguments['name']] = thread
267
+ end
268
+
269
+ def run_on_thread(client, context)
270
+ thread = context.threads.fetch(arguments['name'])
271
+ thread.context.operations << arguments['operation']
272
+ end
273
+
274
+ def wait_for_thread(client, context)
275
+ thread = context.threads.fetch(arguments['name'])
276
+ thread.context.signal_stop
277
+ thread.join
278
+ unless thread.context.unexpected_operation_results.empty?
279
+ raise "Thread #{arguments['name']} had #{thread.context.unexpected_operation_results}.length unexpected operation results"
280
+ end
281
+ end
282
+
283
+ def wait(client, context)
284
+ sleep arguments['ms'] / 1000.0
285
+ end
286
+
287
+ def record_primary(client, context)
288
+ context.primary_address = client.cluster.next_primary.address
289
+ end
290
+
291
+ def run_admin_command(support_client, context)
292
+ support_client.use('admin').database.command(arguments['command'])
293
+ end
294
+
295
+ def wait_for_primary_change(client, context)
296
+ timeout = if arguments['timeoutMS']
297
+ arguments['timeoutMS'] / 1000.0
298
+ else
299
+ 10
300
+ end
301
+ deadline = Time.now + timeout
302
+ loop do
303
+ client.cluster.scan!
304
+ if client.cluster.next_primary.address != context.primary_address
305
+ break
306
+ end
307
+ if Time.now >= deadline
308
+ raise "Failed to change primary in #{timeout} seconds"
309
+ end
310
+ end
311
+ end
186
312
  end
187
313
  end
188
314
  end