mongo 2.15.0 → 2.16.1

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 (332) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +1 -1
  4. data/lib/mongo/bulk_write.rb +2 -2
  5. data/lib/mongo/client.rb +45 -5
  6. data/lib/mongo/cluster/periodic_executor.rb +4 -3
  7. data/lib/mongo/cluster/reapers/cursor_reaper.rb +76 -43
  8. data/lib/mongo/cluster/sdam_flow.rb +9 -3
  9. data/lib/mongo/cluster/topology/base.rb +13 -9
  10. data/lib/mongo/cluster/topology/load_balanced.rb +102 -0
  11. data/lib/mongo/cluster/topology.rb +28 -8
  12. data/lib/mongo/cluster.rb +136 -51
  13. data/lib/mongo/collection/view/aggregation.rb +5 -10
  14. data/lib/mongo/collection/view/builder/aggregation.rb +6 -5
  15. data/lib/mongo/collection/view/builder/map_reduce.rb +12 -49
  16. data/lib/mongo/collection/view/builder.rb +0 -4
  17. data/lib/mongo/collection/view/iterable.rb +58 -24
  18. data/lib/mongo/collection/view/map_reduce.rb +39 -15
  19. data/lib/mongo/collection/view/readable.rb +60 -51
  20. data/lib/mongo/collection/view/writable.rb +178 -175
  21. data/lib/mongo/collection/view.rb +15 -21
  22. data/lib/mongo/collection.rb +13 -13
  23. data/lib/mongo/cursor/kill_spec.rb +38 -0
  24. data/lib/mongo/cursor.rb +72 -31
  25. data/lib/mongo/database/view.rb +1 -1
  26. data/lib/mongo/error/bad_load_balancer_target.rb +26 -0
  27. data/lib/mongo/error/missing_service_id.rb +26 -0
  28. data/lib/mongo/error/no_service_connection_available.rb +49 -0
  29. data/lib/mongo/error/notable.rb +7 -0
  30. data/lib/mongo/error.rb +3 -0
  31. data/lib/mongo/grid/fs_bucket.rb +21 -2
  32. data/lib/mongo/id.rb +7 -5
  33. data/lib/mongo/index/view.rb +22 -41
  34. data/lib/mongo/monitoring/event/cmap/pool_cleared.rb +7 -4
  35. data/lib/mongo/monitoring/event/command_failed.rb +1 -1
  36. data/lib/mongo/monitoring/event/command_started.rb +2 -0
  37. data/lib/mongo/monitoring/publishable.rb +2 -2
  38. data/lib/mongo/operation/aggregate/command.rb +8 -0
  39. data/lib/mongo/operation/context.rb +19 -1
  40. data/lib/mongo/operation/count/command.rb +6 -0
  41. data/lib/mongo/operation/count/op_msg.rb +6 -0
  42. data/lib/mongo/operation/create/command.rb +7 -1
  43. data/lib/mongo/operation/create/op_msg.rb +7 -0
  44. data/lib/mongo/operation/create_index/command.rb +17 -1
  45. data/lib/mongo/operation/create_index/op_msg.rb +17 -4
  46. data/lib/mongo/operation/delete/command.rb +6 -3
  47. data/lib/mongo/operation/delete/legacy.rb +9 -2
  48. data/lib/mongo/operation/delete/op_msg.rb +8 -1
  49. data/lib/mongo/operation/distinct/command.rb +6 -0
  50. data/lib/mongo/operation/distinct/op_msg.rb +7 -0
  51. data/lib/mongo/operation/explain/command.rb +13 -1
  52. data/lib/mongo/operation/explain/legacy.rb +12 -5
  53. data/lib/mongo/operation/explain/op_msg.rb +9 -1
  54. data/lib/mongo/operation/find/builder/command.rb +110 -0
  55. data/lib/mongo/{collection/view → operation/find}/builder/flags.rb +10 -14
  56. data/lib/mongo/operation/find/builder/legacy.rb +123 -0
  57. data/lib/mongo/{collection/view → operation/find}/builder/modifiers.rb +31 -25
  58. data/lib/mongo/{cursor → operation/find}/builder.rb +4 -4
  59. data/lib/mongo/operation/find/command.rb +9 -0
  60. data/lib/mongo/operation/find/legacy.rb +10 -1
  61. data/lib/mongo/operation/find/op_msg.rb +12 -0
  62. data/lib/mongo/operation/find.rb +1 -0
  63. data/lib/mongo/operation/get_more/command.rb +1 -0
  64. data/lib/mongo/operation/get_more/command_builder.rb +38 -0
  65. data/lib/mongo/operation/get_more/op_msg.rb +1 -0
  66. data/lib/mongo/operation/get_more.rb +1 -0
  67. data/lib/mongo/operation/kill_cursors/command.rb +8 -0
  68. data/lib/mongo/operation/kill_cursors/command_builder.rb +35 -0
  69. data/lib/mongo/operation/kill_cursors/legacy.rb +2 -1
  70. data/lib/mongo/operation/kill_cursors/op_msg.rb +10 -0
  71. data/lib/mongo/operation/kill_cursors.rb +1 -0
  72. data/lib/mongo/operation/map_reduce/command.rb +8 -0
  73. data/lib/mongo/operation/map_reduce/op_msg.rb +1 -1
  74. data/lib/mongo/operation/shared/executable.rb +15 -1
  75. data/lib/mongo/operation/shared/polymorphic_operation.rb +1 -1
  76. data/lib/mongo/operation/shared/read_preference_supported.rb +3 -1
  77. data/lib/mongo/operation/shared/response_handling.rb +1 -0
  78. data/lib/mongo/operation/shared/sessions_supported.rb +12 -12
  79. data/lib/mongo/operation/shared/specifiable.rb +11 -29
  80. data/lib/mongo/operation/shared/validatable.rb +87 -0
  81. data/lib/mongo/operation/shared/write.rb +1 -1
  82. data/lib/mongo/operation/update/command.rb +6 -3
  83. data/lib/mongo/operation/update/legacy.rb +19 -11
  84. data/lib/mongo/operation/update/op_msg.rb +7 -4
  85. data/lib/mongo/operation/write_command/command.rb +51 -0
  86. data/lib/mongo/operation/write_command/op_msg.rb +43 -0
  87. data/lib/mongo/operation/write_command.rb +32 -0
  88. data/lib/mongo/operation.rb +10 -0
  89. data/lib/mongo/protocol/query.rb +35 -18
  90. data/lib/mongo/server/connection.rb +25 -3
  91. data/lib/mongo/server/connection_base.rb +12 -1
  92. data/lib/mongo/server/connection_common.rb +38 -1
  93. data/lib/mongo/server/connection_pool/generation_manager.rb +71 -0
  94. data/lib/mongo/server/connection_pool.rb +100 -27
  95. data/lib/mongo/server/description/features.rb +17 -16
  96. data/lib/mongo/server/description/load_balancer.rb +33 -0
  97. data/lib/mongo/server/description.rb +85 -6
  98. data/lib/mongo/server/monitor/connection.rb +5 -6
  99. data/lib/mongo/server/monitor.rb +2 -1
  100. data/lib/mongo/server/pending_connection.rb +47 -31
  101. data/lib/mongo/server/push_monitor.rb +10 -1
  102. data/lib/mongo/server.rb +73 -26
  103. data/lib/mongo/server_selector/base.rb +5 -1
  104. data/lib/mongo/session/session_pool.rb +11 -0
  105. data/lib/mongo/session.rb +21 -1
  106. data/lib/mongo/socket/ocsp_verifier.rb +6 -37
  107. data/lib/mongo/uri/options_mapper.rb +1 -0
  108. data/lib/mongo/uri/srv_protocol.rb +6 -8
  109. data/lib/mongo/uri.rb +18 -0
  110. data/lib/mongo/utils.rb +0 -7
  111. data/lib/mongo/version.rb +1 -1
  112. data/mongo.gemspec +1 -1
  113. data/spec/integration/auth_spec.rb +31 -1
  114. data/spec/integration/awaited_ismaster_spec.rb +1 -1
  115. data/spec/integration/bulk_write_spec.rb +1 -1
  116. data/spec/integration/change_stream_spec.rb +3 -3
  117. data/spec/integration/client_construction_spec.rb +54 -0
  118. data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +1 -1
  119. data/spec/integration/client_side_encryption/auto_encryption_command_monitoring_spec.rb +1 -1
  120. data/spec/integration/client_side_encryption/bson_size_limit_spec.rb +1 -1
  121. data/spec/integration/client_side_encryption/data_key_spec.rb +1 -1
  122. data/spec/integration/client_spec.rb +2 -0
  123. data/spec/integration/command_monitoring_spec.rb +1 -1
  124. data/spec/integration/command_spec.rb +1 -1
  125. data/spec/integration/connection_spec.rb +52 -35
  126. data/spec/integration/crud_spec.rb +174 -1
  127. data/spec/integration/cursor_pinning_spec.rb +121 -0
  128. data/spec/integration/cursor_reaping_spec.rb +8 -4
  129. data/spec/integration/fork_reconnect_spec.rb +1 -5
  130. data/spec/integration/get_more_spec.rb +1 -1
  131. data/spec/integration/heartbeat_events_spec.rb +1 -1
  132. data/spec/integration/map_reduce_spec.rb +77 -0
  133. data/spec/integration/query_cache_spec.rb +47 -2
  134. data/spec/integration/query_cache_transactions_spec.rb +1 -1
  135. data/spec/integration/read_concern_spec.rb +1 -1
  136. data/spec/integration/read_preference_spec.rb +1 -1
  137. data/spec/integration/reconnect_spec.rb +30 -12
  138. data/spec/integration/retryable_errors_spec.rb +1 -1
  139. data/spec/integration/retryable_writes/retryable_writes_36_and_older_spec.rb +1 -1
  140. data/spec/integration/retryable_writes/retryable_writes_40_and_newer_spec.rb +1 -1
  141. data/spec/integration/sdam_error_handling_spec.rb +5 -3
  142. data/spec/integration/sdam_events_spec.rb +35 -19
  143. data/spec/integration/sdam_prose_spec.rb +1 -1
  144. data/spec/integration/server_monitor_spec.rb +1 -0
  145. data/spec/integration/server_selector_spec.rb +22 -5
  146. data/spec/integration/server_spec.rb +2 -0
  147. data/spec/integration/srv_monitoring_spec.rb +1 -1
  148. data/spec/integration/step_down_spec.rb +1 -1
  149. data/spec/integration/transaction_pinning_spec.rb +120 -0
  150. data/spec/integration/versioned_api_examples_spec.rb +45 -0
  151. data/spec/integration/x509_auth_spec.rb +1 -1
  152. data/spec/lite_spec_helper.rb +1 -2
  153. data/spec/mongo/address/unix_spec.rb +1 -0
  154. data/spec/mongo/auth/cr_spec.rb +2 -3
  155. data/spec/mongo/auth/ldap_spec.rb +2 -3
  156. data/spec/mongo/auth/scram_spec.rb +2 -3
  157. data/spec/mongo/auth/user/view_spec.rb +1 -1
  158. data/spec/mongo/auth/x509_spec.rb +2 -3
  159. data/spec/mongo/bulk_write_spec.rb +3 -3
  160. data/spec/mongo/client_construction_spec.rb +259 -28
  161. data/spec/mongo/client_spec.rb +6 -4
  162. data/spec/mongo/cluster/cursor_reaper_spec.rb +36 -21
  163. data/spec/mongo/cluster/periodic_executor_spec.rb +3 -1
  164. data/spec/mongo/cluster_spec.rb +44 -3
  165. data/spec/mongo/collection/view/aggregation_spec.rb +1 -1
  166. data/spec/mongo/collection/view/builder/find_command_spec.rb +4 -0
  167. data/spec/mongo/collection/view/builder/op_query_spec.rb +4 -0
  168. data/spec/mongo/collection/view/map_reduce_spec.rb +1 -1
  169. data/spec/mongo/collection_crud_spec.rb +7 -2
  170. data/spec/mongo/collection_ddl_spec.rb +1 -1
  171. data/spec/mongo/collection_spec.rb +1 -1
  172. data/spec/mongo/cursor/builder/get_more_command_spec.rb +4 -0
  173. data/spec/mongo/cursor/builder/op_get_more_spec.rb +4 -0
  174. data/spec/mongo/cursor_spec.rb +15 -5
  175. data/spec/mongo/database_spec.rb +15 -15
  176. data/spec/mongo/error/operation_failure_heavy_spec.rb +1 -1
  177. data/spec/mongo/grid/fs_bucket_spec.rb +18 -12
  178. data/spec/mongo/grid/stream/write_spec.rb +3 -9
  179. data/spec/mongo/grid/stream_spec.rb +1 -1
  180. data/spec/mongo/index/view_spec.rb +2 -2
  181. data/spec/mongo/operation/delete/op_msg_spec.rb +1 -1
  182. data/spec/mongo/{collection/view → operation/find}/builder/flags_spec.rb +2 -2
  183. data/spec/mongo/{collection/view → operation/find}/builder/modifiers_spec.rb +2 -2
  184. data/spec/mongo/operation/find/legacy_spec.rb +1 -0
  185. data/spec/mongo/operation/insert/bulk_spec.rb +1 -1
  186. data/spec/mongo/operation/insert/op_msg_spec.rb +1 -1
  187. data/spec/mongo/operation/kill_cursors_spec.rb +4 -1
  188. data/spec/mongo/operation/read_preference_legacy_spec.rb +4 -0
  189. data/spec/mongo/operation/read_preference_op_msg_spec.rb +2 -0
  190. data/spec/mongo/operation/update/bulk_spec.rb +1 -1
  191. data/spec/mongo/operation/update/op_msg_spec.rb +1 -1
  192. data/spec/mongo/query_cache_spec.rb +6 -2
  193. data/spec/mongo/server/connection_common_spec.rb +62 -11
  194. data/spec/mongo/server/connection_pool_spec.rb +73 -7
  195. data/spec/mongo/server/connection_spec.rb +138 -43
  196. data/spec/mongo/server/description_spec.rb +1 -1
  197. data/spec/mongo/server/monitor/connection_spec.rb +22 -0
  198. data/spec/mongo/server/monitor_spec.rb +4 -3
  199. data/spec/mongo/server/push_monitor_spec.rb +101 -0
  200. data/spec/mongo/session/session_pool_spec.rb +42 -10
  201. data/spec/mongo/session_transaction_spec.rb +15 -30
  202. data/spec/mongo/socket/unix_spec.rb +1 -0
  203. data/spec/mongo/uri_option_parsing_spec.rb +38 -5
  204. data/spec/runners/change_streams/test.rb +1 -1
  205. data/spec/runners/cmap.rb +1 -1
  206. data/spec/runners/connection_string.rb +7 -3
  207. data/spec/runners/crud/operation.rb +5 -3
  208. data/spec/runners/crud/requirement.rb +1 -0
  209. data/spec/runners/crud.rb +1 -1
  210. data/spec/runners/sdam.rb +2 -1
  211. data/spec/runners/transactions/test.rb +2 -2
  212. data/spec/runners/unified/assertions.rb +2 -3
  213. data/spec/runners/unified/event_subscriber.rb +2 -2
  214. data/spec/runners/unified/support_operations.rb +10 -2
  215. data/spec/runners/unified/test.rb +3 -0
  216. data/spec/runners/unified.rb +1 -1
  217. data/spec/shared/lib/mrss/cluster_config.rb +6 -1
  218. data/spec/shared/lib/mrss/constraints.rb +11 -5
  219. data/spec/shared/lib/mrss/event_subscriber.rb +200 -0
  220. data/spec/shared/lib/mrss/server_version_registry.rb +17 -12
  221. data/spec/shared/share/Dockerfile.erb +5 -4
  222. data/spec/shared/shlib/server.sh +70 -20
  223. data/spec/spec_tests/change_streams_spec.rb +1 -1
  224. data/spec/spec_tests/cmap_spec.rb +4 -1
  225. data/spec/spec_tests/command_monitoring_spec.rb +2 -2
  226. data/spec/spec_tests/data/command_monitoring/find.yml +9 -9
  227. data/spec/spec_tests/data/crud/read/aggregate-collation.yml +2 -1
  228. data/spec/spec_tests/data/crud/read/aggregate-out.yml +1 -0
  229. data/spec/spec_tests/data/crud/read/count-collation.yml +2 -1
  230. data/spec/spec_tests/data/crud/read/distinct-collation.yml +2 -1
  231. data/spec/spec_tests/data/crud/read/find-collation.yml +2 -1
  232. data/spec/spec_tests/data/crud/write/bulkWrite-collation.yml +2 -1
  233. data/spec/spec_tests/data/crud/write/deleteMany-collation.yml +2 -1
  234. data/spec/spec_tests/data/crud/write/deleteOne-collation.yml +2 -1
  235. data/spec/spec_tests/data/crud/write/findOneAndDelete-collation.yml +3 -2
  236. data/spec/spec_tests/data/crud/write/findOneAndReplace-collation.yml +2 -1
  237. data/spec/spec_tests/data/crud/write/findOneAndUpdate-collation.yml +3 -2
  238. data/spec/spec_tests/data/crud/write/replaceOne-collation.yml +3 -2
  239. data/spec/spec_tests/data/crud/write/updateMany-collation.yml +2 -1
  240. data/spec/spec_tests/data/crud/write/updateOne-collation.yml +2 -1
  241. data/spec/spec_tests/data/load_balancers/event-monitoring.yml +99 -0
  242. data/spec/spec_tests/data/load_balancers/lb-connection-establishment.yml +36 -0
  243. data/spec/spec_tests/data/load_balancers/non-lb-connection-establishment.yml +56 -0
  244. data/spec/spec_tests/data/load_balancers/server-selection.yml +50 -0
  245. data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch-serverErrors.yml +1 -1
  246. data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch.yml +1 -1
  247. data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch-serverErrors.yml +1 -1
  248. data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch.yml +1 -1
  249. data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch-serverErrors.yml +1 -1
  250. data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch.yml +1 -1
  251. data/spec/spec_tests/data/retryable_reads/mapReduce.yml +3 -1
  252. data/spec/spec_tests/data/sdam/load-balanced/discover_load_balancer.yml +25 -0
  253. data/spec/spec_tests/data/sdam_integration/find-network-error.yml +2 -0
  254. data/spec/spec_tests/data/sdam_integration/find-shutdown-error.yml +2 -0
  255. data/spec/spec_tests/data/sdam_integration/hello-command-error.yml +3 -1
  256. data/spec/spec_tests/data/sdam_integration/hello-network-error.yml +3 -1
  257. data/spec/spec_tests/data/sdam_integration/hello-timeout.yml +2 -0
  258. data/spec/spec_tests/data/sdam_integration/insert-network-error.yml +2 -0
  259. data/spec/spec_tests/data/sdam_integration/insert-shutdown-error.yml +2 -0
  260. data/spec/spec_tests/data/sdam_monitoring/load_balancer.yml +65 -0
  261. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-directConnection.yml +13 -0
  262. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-replicaSet-errors.yml +6 -0
  263. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-true-multiple-hosts.yml +5 -0
  264. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-true-txt.yml +10 -0
  265. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/direct-connection-false.yml +0 -0
  266. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/direct-connection-true.yml +0 -0
  267. data/spec/spec_tests/data/seed_list_discovery/replica-set/encoded-userinfo-and-db.yml +15 -0
  268. data/spec/spec_tests/data/seed_list_discovery/replica-set/loadBalanced-false-txt.yml +10 -0
  269. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/longer-parent-in-return.yml +0 -0
  270. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/misformatted-option.yml +0 -0
  271. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/no-results.yml +0 -0
  272. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/not-enough-parts.yml +0 -0
  273. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-result-default-port.yml +0 -0
  274. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-txt-record-multiple-strings.yml +0 -0
  275. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-txt-record.yml +0 -0
  276. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch1.yml +0 -0
  277. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch2.yml +0 -0
  278. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch3.yml +0 -0
  279. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch4.yml +0 -0
  280. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch5.yml +0 -0
  281. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/returned-parent-too-short.yml +0 -0
  282. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/returned-parent-wrong.yml +0 -0
  283. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-results-default-port.yml +0 -0
  284. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-results-nonstandard-port.yml +0 -0
  285. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-txt-records.yml +0 -0
  286. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-not-allowed-option.yml +0 -0
  287. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-overridden-ssl-option.yml +0 -0
  288. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-overridden-uri-option.yml +0 -0
  289. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-unallowed-option.yml +0 -0
  290. data/spec/spec_tests/data/seed_list_discovery/replica-set/uri-with-admin-database.yml +13 -0
  291. data/spec/spec_tests/data/seed_list_discovery/replica-set/uri-with-auth.yml +12 -0
  292. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/uri-with-port.yml +0 -0
  293. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/uri-with-two-hosts.yml +0 -0
  294. data/spec/spec_tests/data/transactions/retryable-abort-errorLabels.yml +2 -0
  295. data/spec/spec_tests/data/transactions/retryable-abort.yml +2 -0
  296. data/spec/spec_tests/data/transactions/retryable-commit-errorLabels.yml +2 -0
  297. data/spec/spec_tests/data/transactions/retryable-commit.yml +2 -0
  298. data/spec/spec_tests/data/transactions/retryable-writes.yml +2 -0
  299. data/spec/spec_tests/data/uri_options/connection-options.yml +60 -0
  300. data/spec/spec_tests/load_balancers_spec.rb +15 -0
  301. data/spec/spec_tests/retryable_reads_spec.rb +2 -2
  302. data/spec/spec_tests/retryable_writes_spec.rb +1 -1
  303. data/spec/spec_tests/sdam_integration_spec.rb +1 -1
  304. data/spec/spec_tests/sdam_monitoring_spec.rb +10 -5
  305. data/spec/spec_tests/sdam_spec.rb +1 -1
  306. data/spec/spec_tests/seed_list_discovery_spec.rb +118 -0
  307. data/spec/spec_tests/uri_options_spec.rb +4 -4
  308. data/spec/stress/fork_reconnect_stress_spec.rb +1 -5
  309. data/spec/stress/push_monitor_close_spec.rb +44 -0
  310. data/spec/support/certificates/atlas-ocsp-ca.crt +82 -90
  311. data/spec/support/certificates/atlas-ocsp.crt +127 -122
  312. data/spec/support/common_shortcuts.rb +2 -3
  313. data/spec/support/matchers.rb +13 -0
  314. data/spec/support/shared/auth_context.rb +16 -0
  315. data/spec/support/shared/session.rb +2 -2
  316. data/spec/support/spec_config.rb +10 -11
  317. data/spec/support/using_hash.rb +31 -0
  318. data/spec/support/utils.rb +1 -1
  319. data.tar.gz.sig +0 -0
  320. metadata +1077 -1029
  321. metadata.gz.sig +0 -0
  322. data/lib/mongo/collection/view/builder/find_command.rb +0 -173
  323. data/lib/mongo/collection/view/builder/op_query.rb +0 -94
  324. data/lib/mongo/cursor/builder/get_more_command.rb +0 -80
  325. data/lib/mongo/cursor/builder/kill_cursors_command.rb +0 -111
  326. data/lib/mongo/cursor/builder/op_get_more.rb +0 -64
  327. data/lib/mongo/cursor/builder/op_kill_cursors.rb +0 -106
  328. data/lib/mongo/server/context.rb +0 -72
  329. data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +0 -66
  330. data/spec/runners/unified/using_hash.rb +0 -34
  331. data/spec/spec_tests/dns_seedlist_discovery_spec.rb +0 -79
  332. data/spec/support/event_subscriber.rb +0 -221
@@ -71,32 +71,41 @@ module Mongo
71
71
  raise Error::InternalDriverError, "Connection description cannot be unknown after successful handshake: #{description.inspect}"
72
72
  end
73
73
 
74
- if speculative_auth_doc && (speculative_auth_result = result['speculativeAuthenticate'])
75
- unless description.features.scram_sha_1_enabled?
76
- raise Error::InvalidServerAuthResponse, "Speculative auth succeeded on a pre-3.0 server"
77
- end
78
- case speculative_auth_user.mechanism
79
- when :mongodb_x509
80
- # Done
81
- # We default auth mechanism to scram256, but if user specified
82
- # scram explicitly we may be able to authenticate speculatively
83
- # with scram.
84
- when :scram, :scram256
85
- authenticate!(
86
- speculative_auth_client_nonce: speculative_auth.conversation.client_nonce,
87
- speculative_auth_mech: speculative_auth_user.mechanism,
88
- speculative_auth_result: speculative_auth_result,
89
- )
90
- else
91
- raise Error::InternalDriverError, "Speculative auth unexpectedly succeeded for mechanism #{speculative_auth_user.mechanism.inspect}"
74
+ begin
75
+ if speculative_auth_doc && (speculative_auth_result = result['speculativeAuthenticate'])
76
+ unless description.features.scram_sha_1_enabled?
77
+ raise Error::InvalidServerAuthResponse, "Speculative auth succeeded on a pre-3.0 server"
78
+ end
79
+ case speculative_auth_user.mechanism
80
+ when :mongodb_x509
81
+ # Done
82
+ # We default auth mechanism to scram256, but if user specified
83
+ # scram explicitly we may be able to authenticate speculatively
84
+ # with scram.
85
+ when :scram, :scram256
86
+ authenticate!(
87
+ speculative_auth_client_nonce: speculative_auth.conversation.client_nonce,
88
+ speculative_auth_mech: speculative_auth_user.mechanism,
89
+ speculative_auth_result: speculative_auth_result,
90
+ )
91
+ else
92
+ raise Error::InternalDriverError, "Speculative auth unexpectedly succeeded for mechanism #{speculative_auth_user.mechanism.inspect}"
93
+ end
94
+ elsif !description.arbiter?
95
+ authenticate!
92
96
  end
93
- elsif !description.arbiter?
94
- authenticate!
97
+ rescue Mongo::Error, Mongo::Error::AuthError => exc
98
+ exc.service_id = service_id
99
+ raise
95
100
  end
96
101
 
97
102
  if description.unknown?
98
103
  raise Error::InternalDriverError, "Connection description cannot be unknown after successful authentication: #{description.inspect}"
99
104
  end
105
+
106
+ if server.load_balancer? && !description.mongos?
107
+ raise Error::BadLoadBalancerTarget, "Load-balanced operation requires being connected a mongos, but the server at #{address.seed} reported itself as #{description.server_type.to_s.gsub('_', ' ')}"
108
+ end
100
109
  end
101
110
 
102
111
  private
@@ -111,16 +120,14 @@ module Mongo
111
120
  raise Error::InternalDriverError, "Cannot handshake because there is no usable socket (for #{address})"
112
121
  end
113
122
 
114
- hello_doc = handshake_document(
115
- app_metadata,
116
- speculative_auth_doc: speculative_auth_doc,
117
- server_api: options[:server_api],
123
+ hello_command = handshake_command(
124
+ handshake_document(
125
+ app_metadata,
126
+ speculative_auth_doc: speculative_auth_doc,
127
+ load_balancer: server.load_balancer?,
128
+ server_api: options[:server_api]
129
+ )
118
130
  )
119
-
120
- # TODO (DR): OP_MSG should be used if api version is declared.
121
- # See https://github.com/mongodb/specifications/blob/master/source/message/OP_MSG.rst#id5
122
- hello_command = Protocol::Query.new(Database::ADMIN, Database::COMMAND, hello_doc, :limit => -1)
123
-
124
131
  doc = nil
125
132
  @server.handle_handshake_failure! do
126
133
  begin
@@ -144,6 +151,10 @@ module Mongo
144
151
  end
145
152
  end
146
153
 
154
+ if @server.force_load_balancer?
155
+ doc['serviceId'] ||= "fake:#{rand(2**32-1)+1}"
156
+ end
157
+
147
158
  post_handshake(doc, @server.round_trip_time_averager.average_round_trip_time)
148
159
 
149
160
  doc
@@ -193,7 +204,7 @@ module Mongo
193
204
  # This is a separate method to keep the nesting level down.
194
205
  #
195
206
  # @return [ Server::Description ] The server description calculated from
196
- # hello response for this particular connection.
207
+ # the handshake response for this particular connection.
197
208
  def post_handshake(response, average_rtt)
198
209
  if response["ok"] == 1
199
210
  # Auth mechanism is entirely dependent on the contents of
@@ -210,7 +221,12 @@ module Mongo
210
221
  @sasl_supported_mechanisms = nil
211
222
  end
212
223
 
213
- @description = Description.new(address, response, average_rtt).tap do |new_description|
224
+ @description = Description.new(
225
+ address, response,
226
+ average_round_trip_time: average_rtt,
227
+ load_balancer: server.load_balancer?,
228
+ force_load_balancer: options[:connect] == :load_balanced,
229
+ ).tap do |new_description|
214
230
  @server.cluster.run_sdam_flow(@server.description, new_description)
215
231
  end
216
232
  end
@@ -110,13 +110,22 @@ module Mongo
110
110
  if new_description.topology_version
111
111
  @topology_version = new_description.topology_version
112
112
  end
113
- rescue Mongo::Error => exc
113
+ rescue IOError, SocketError, SystemCallError, Mongo::Error => exc
114
+ stop_requested = @lock.synchronize { @stop_requested }
115
+ if stop_requested
116
+ # Ignore the exception, see RUBY-2771.
117
+ return
118
+ end
119
+
114
120
  msg = "Error running awaited hello on #{server.address}"
115
121
  Utils.warn_bg_exception(msg, exc,
116
122
  logger: options[:logger],
117
123
  log_prefix: options[:log_prefix],
118
124
  bg_error_backtrace: options[:bg_error_backtrace],
119
125
  )
126
+
127
+ # Avoid tight looping in push monitor - see RUBY-2806.
128
+ sleep(0.5)
120
129
  end
121
130
 
122
131
  def check
data/lib/mongo/server.rb CHANGED
@@ -54,6 +54,9 @@ module Mongo
54
54
  # done by this server. Note: setting this option to false will make
55
55
  # the server non-functional. It is intended for use in tests which
56
56
  # manually invoke SDAM state transitions.
57
+ # @option options [ true | false ] :load_balancer Whether this server
58
+ # is a load balancer.
59
+ # @option options [ String ] :connect The client connection mode.
57
60
  #
58
61
  # @since 2.0.0
59
62
  def initialize(address, cluster, monitoring, event_listeners, options = {})
@@ -69,7 +72,10 @@ module Mongo
69
72
  end
70
73
  @scan_semaphore = DistinguishingSemaphore.new
71
74
  @round_trip_time_averager = RoundTripTimeAverager.new
72
- @description = Description.new(address, {})
75
+ @description = Description.new(address, {},
76
+ load_balancer: !!@options[:load_balancer],
77
+ force_load_balancer: force_load_balancer?,
78
+ )
73
79
  @last_scan = nil
74
80
  @last_scan_monotime = nil
75
81
  unless options[:monitoring_io] == false
@@ -107,6 +113,15 @@ module Mongo
107
113
  # description the monitor refreshes.
108
114
  attr_reader :description
109
115
 
116
+ # Returns whether this server is forced to be a load balancer.
117
+ #
118
+ # @return [ true | false ] Whether this server is forced to be a load balancer.
119
+ #
120
+ # @api private
121
+ def force_load_balancer?
122
+ options[:connect] == :load_balanced
123
+ end
124
+
110
125
  # @return [ Time | nil ] last_scan The time when the last server scan
111
126
  # completed, or nil if the server has not been scanned yet.
112
127
  #
@@ -180,6 +195,7 @@ module Mongo
180
195
  :secondary?,
181
196
  :standalone?,
182
197
  :unknown?,
198
+ :load_balancer?,
183
199
  :last_write_date,
184
200
  :logical_session_timeout
185
201
 
@@ -222,20 +238,6 @@ module Mongo
222
238
  address == other.address
223
239
  end
224
240
 
225
- # Get a new context for this server in which to send messages.
226
- #
227
- # @example Get the server context.
228
- # server.context
229
- #
230
- # @return [ Mongo::Server::Context ] context The server context.
231
- #
232
- # @since 2.0.0
233
- #
234
- # @deprecated Will be removed in version 3.0
235
- def context
236
- Context.new(self)
237
- end
238
-
239
241
  # Determine if a connection to the server is able to be established and
240
242
  # messages can be sent to it.
241
243
  #
@@ -301,13 +303,20 @@ module Mongo
301
303
  #
302
304
  # @api private
303
305
  def start_monitoring
306
+ publish_opening_event
307
+ if options[:monitoring_io] != false
308
+ monitor.run!
309
+ end
310
+ end
311
+
312
+ # Publishes the server opening event.
313
+ #
314
+ # @api private
315
+ def publish_opening_event
304
316
  publish_sdam_event(
305
317
  Monitoring::SERVER_OPENING,
306
318
  Monitoring::Event::ServerOpening.new(address, cluster.topology)
307
319
  )
308
- if options[:monitoring_io] != false
309
- monitor.run!
310
- end
311
320
  end
312
321
 
313
322
  # Get a pretty printed server inspection.
@@ -327,6 +336,8 @@ module Mongo
327
336
  # @api private
328
337
  def status
329
338
  case
339
+ when load_balancer?
340
+ 'LB'
330
341
  when primary?
331
342
  'PRIMARY'
332
343
  when secondary?
@@ -433,8 +444,8 @@ module Mongo
433
444
  # @return [ Object ] The result of the block execution.
434
445
  #
435
446
  # @since 2.3.0
436
- def with_connection(&block)
437
- pool.with_connection(&block)
447
+ def with_connection(service_id: nil, &block)
448
+ pool.with_connection(service_id: service_id, &block)
438
449
  end
439
450
 
440
451
  # Handle handshake failure.
@@ -444,7 +455,11 @@ module Mongo
444
455
  def handle_handshake_failure!
445
456
  yield
446
457
  rescue Mongo::Error::SocketError, Mongo::Error::SocketTimeoutError => e
447
- unknown!(generation: e.generation, stop_push_monitor: true)
458
+ unknown!(
459
+ generation: e.generation,
460
+ service_id: e.service_id,
461
+ stop_push_monitor: true,
462
+ )
448
463
  raise
449
464
  end
450
465
 
@@ -467,7 +482,11 @@ module Mongo
467
482
  raise
468
483
  rescue Mongo::Error::SocketError => e
469
484
  # non-timeout network error
470
- unknown!(generation: e.generation, stop_push_monitor: true)
485
+ unknown!(
486
+ generation: e.generation,
487
+ service_id: e.service_id,
488
+ stop_push_monitor: true,
489
+ )
471
490
  raise
472
491
  rescue Auth::Unauthorized
473
492
  # auth error, keep server description and topology as they are
@@ -513,13 +532,33 @@ module Mongo
513
532
  # respective server is cleared. Set this option to true to keep the
514
533
  # existing connection pool (required when handling not master errors
515
534
  # on 4.2+ servers).
535
+ # @option options [ Object ] :service_id Discard state for the specified
536
+ # service id only.
516
537
  # @option options [ TopologyVersion ] :topology_version Topology version
517
538
  # of the error response that is causing the server to be marked unknown.
518
539
  # @option options [ true | false ] :stop_push_monitor Whether to stop
519
540
  # the PushMonitor associated with the server, if any.
541
+ # @option options [ Object ] :service_id Discard state for the specified
542
+ # service id only.
520
543
  #
521
544
  # @since 2.4.0, SDAM events are sent as of version 2.7.0
522
545
  def unknown!(options = {})
546
+ if load_balancer?
547
+ # When the client is in load-balanced topology, servers (the one and
548
+ # only that can be) starts out as a load balancer and stays as a
549
+ # load balancer indefinitely. As such it is not marked unknown.
550
+ #
551
+ # However, this method also clears connection pool for the server
552
+ # when the latter is marked unknown, and this part needs to happen
553
+ # when the server is a load balancer.
554
+ if service_id = options[:service_id]
555
+ pool.disconnect!(service_id: service_id)
556
+ elsif Lint.enabled?
557
+ raise Error::LintError, 'Load balancer was asked to be marked unknown without a service id'
558
+ end
559
+ return
560
+ end
561
+
523
562
  if options[:generation] && options[:generation] < pool.generation
524
563
  return
525
564
  end
@@ -537,10 +576,16 @@ module Mongo
537
576
  # SDAM flow will update description on the server without in-place
538
577
  # mutations and invoke SDAM transitions as needed.
539
578
  config = {}
579
+ if options[:service_id]
580
+ config['serviceId'] = options[:service_id]
581
+ end
540
582
  if options[:topology_version]
541
583
  config['topologyVersion'] = options[:topology_version]
542
584
  end
543
- new_description = Description.new(address, config)
585
+ new_description = Description.new(address, config,
586
+ load_balancer: load_balancer?,
587
+ force_load_balancer: options[:connect] == :load_balanced,
588
+ )
544
589
  cluster.run_sdam_flow(description, new_description, options)
545
590
  end
546
591
 
@@ -549,11 +594,14 @@ module Mongo
549
594
  @description = description
550
595
  end
551
596
 
597
+ # @param [ Object ] :service_id Close connections with the specified
598
+ # service id only.
599
+ #
552
600
  # @api private
553
- def clear_connection_pool
601
+ def clear_connection_pool(service_id: nil)
554
602
  @pool_lock.synchronize do
555
603
  if @pool
556
- @pool.disconnect!
604
+ @pool.disconnect!(service_id: service_id)
557
605
  end
558
606
  end
559
607
  end
@@ -577,7 +625,6 @@ require 'mongo/server/connection_base'
577
625
  require 'mongo/server/pending_connection'
578
626
  require 'mongo/server/connection'
579
627
  require 'mongo/server/connection_pool'
580
- require 'mongo/server/context'
581
628
  require 'mongo/server/description'
582
629
  require 'mongo/server/monitor'
583
630
  require 'mongo/server/round_trip_time_averager'
@@ -173,6 +173,10 @@ module Mongo
173
173
  #
174
174
  # @since 2.0.0
175
175
  def select_server(cluster, ping = nil, session = nil)
176
+ if cluster.topology.is_a?(Cluster::Topology::LoadBalanced)
177
+ return cluster.servers.first
178
+ end
179
+
176
180
  server_selection_timeout = cluster.options[:server_selection_timeout] || SERVER_SELECTION_TIMEOUT
177
181
 
178
182
  # Special handling for zero timeout: if we have to select a server,
@@ -247,7 +251,7 @@ module Mongo
247
251
  end
248
252
 
249
253
  if session && session.starting_transaction? && cluster.sharded?
250
- session.pin(server)
254
+ session.pin_to_server(server)
251
255
  end
252
256
 
253
257
  return server
@@ -133,6 +133,13 @@ module Mongo
133
133
  private
134
134
 
135
135
  def about_to_expire?(session)
136
+ # Load balancers spec explicitly requires to ignore the logical session
137
+ # timeout value.
138
+ # No rationale is provided as of the time of this writing.
139
+ if @cluster.load_balanced?
140
+ return false
141
+ end
142
+
136
143
  logical_session_timeout = @cluster.logical_session_timeout
137
144
 
138
145
  if logical_session_timeout
@@ -142,6 +149,10 @@ module Mongo
142
149
  end
143
150
 
144
151
  def prune!
152
+ # Load balancers spec explicitly requires not to prune sessions.
153
+ # No rationale is provided as of the time of this writing.
154
+ return if @cluster.load_balanced?
155
+
145
156
  while !@queue.empty?
146
157
  if about_to_expire?(@queue[-1])
147
158
  @queue.pop
data/lib/mongo/session.rb CHANGED
@@ -208,6 +208,12 @@ module Mongo
208
208
  # @api private
209
209
  attr_reader :pinned_server
210
210
 
211
+ # @return [ Object | nil ] The service id that this session is pinned to,
212
+ # if any.
213
+ #
214
+ # @api private
215
+ attr_reader :pinned_service_id
216
+
211
217
  # @return [ BSON::Document | nil ] Recovery token for the sharded
212
218
  # transaction being executed on this session, if any.
213
219
  #
@@ -430,6 +436,7 @@ module Mongo
430
436
  transaction_in_progress = false
431
437
  raise
432
438
  end
439
+ @state = NO_TRANSACTION_STATE
433
440
  next
434
441
  else
435
442
  transaction_in_progress = false
@@ -695,7 +702,7 @@ module Mongo
695
702
  # @param [ Server ] server The server to pin this session to.
696
703
  #
697
704
  # @api private
698
- def pin(server)
705
+ def pin_to_server(server)
699
706
  if server.nil?
700
707
  raise ArgumentError, 'Cannot pin to a nil server'
701
708
  end
@@ -707,11 +714,24 @@ module Mongo
707
714
  @pinned_server = server
708
715
  end
709
716
 
717
+ # Pins this session to the specified service.
718
+ #
719
+ # @param [ Object ] service_id The service id to pin this session to.
720
+ #
721
+ # @api private
722
+ def pin_to_service(service_id)
723
+ if service_id.nil?
724
+ raise ArgumentError, 'Cannot pin to a nil service id'
725
+ end
726
+ @pinned_service_id = service_id
727
+ end
728
+
710
729
  # Unpins this session from the pinned server, if the session was pinned.
711
730
  #
712
731
  # @api private
713
732
  def unpin
714
733
  @pinned_server = nil
734
+ @pinned_service_id = nil
715
735
  end
716
736
 
717
737
  # Unpins this session from the pinned server, if the session was pinned
@@ -237,43 +237,12 @@ module Mongo
237
237
  return false
238
238
  end
239
239
 
240
- if resp.respond_to?(:find_response)
241
- # Ruby 2.4+
242
- resp = resp.find_response(cert_id)
243
- # TODO make a new class instead of patching the stdlib one?
244
- resp.instance_variable_set('@uri', uri)
245
- resp.instance_variable_set('@original_uri', original_uri)
246
- class << resp
247
- attr_reader :uri, :original_uri
248
- end
249
- else
250
- # Ruby 2.3
251
- found = nil
252
- resp.status.each do |_cert_id, cert_status, revocation_reason, revocation_time, this_update, next_update, extensions|
253
- if _cert_id.cmp(cert_id)
254
- found = OpenStruct.new(
255
- cert_status: cert_status,
256
- certid: _cert_id,
257
- next_update: next_update,
258
- this_update: this_update,
259
- revocation_reason: revocation_reason,
260
- revocation_time: revocation_time,
261
- extensions: extensions,
262
- uri: uri,
263
- original_uri: original_uri,
264
- )
265
- class << found
266
- # Unlike the stdlib method, this one doesn't accept
267
- # any arguments.
268
- def check_validity
269
- now = Time.now
270
- this_update <= now && next_update >= now
271
- end
272
- end
273
- break
274
- end
275
- end
276
- resp = found
240
+ resp = resp.find_response(cert_id)
241
+ # TODO make a new class instead of patching the stdlib one?
242
+ resp.instance_variable_set('@uri', uri)
243
+ resp.instance_variable_set('@original_uri', original_uri)
244
+ class << resp
245
+ attr_reader :uri, :original_uri
277
246
  end
278
247
 
279
248
  unless resp
@@ -268,6 +268,7 @@ module Mongo
268
268
  # Topology options
269
269
  uri_option 'directConnection', :direct_connection, type: :bool
270
270
  uri_option 'connect', :connect, type: :symbol
271
+ uri_option 'loadBalanced', :load_balanced, type: :bool
271
272
 
272
273
  # Auth Options
273
274
  uri_option 'authSource', :auth_source
@@ -80,7 +80,7 @@ module Mongo
80
80
  DOT_PARTITION = '.'.freeze
81
81
 
82
82
  # @return [ Array<String> ] VALID_TXT_OPTIONS The valid options for a TXT record to specify.
83
- VALID_TXT_OPTIONS = ['replicaset', 'authsource'].freeze
83
+ VALID_TXT_OPTIONS = %w(replicaset authsource loadbalanced).freeze
84
84
 
85
85
  # @return [ String ] INVALID_HOST Error message format string indicating that the hostname in
86
86
  # in the URI does not fit the expected form.
@@ -102,11 +102,6 @@ module Mongo
102
102
  # were found.
103
103
  NO_SRV_RECORDS = "The DNS query returned no SRV records for '%s'".freeze
104
104
 
105
- # @return [ String ] INVALID_TXT_RECORD_OPTION Error message format string indicating that an
106
- # unexpected TXT record option was found.
107
- INVALID_TXT_RECORD_OPTION = "TXT records can only specify the options " +
108
- "[#{VALID_TXT_OPTIONS.join(', ')}].".freeze
109
-
110
105
  # @return [ String ] FORMAT The expected SRV URI format.
111
106
  FORMAT = 'mongodb+srv://[username:password@]host[/[database][?options]]'.freeze
112
107
 
@@ -222,8 +217,11 @@ module Mongo
222
217
  def parse_txt_options!(string)
223
218
  string.split(INDIV_URI_OPTS_DELIM).reduce({}) do |txt_options, opt|
224
219
  raise Error::InvalidTXTRecord.new(INVALID_OPTS_VALUE_DELIM) unless opt.index(URI_OPTS_VALUE_DELIM)
225
- key, value = opt.split(URI_OPTS_VALUE_DELIM)
226
- raise Error::InvalidTXTRecord.new(INVALID_TXT_RECORD_OPTION) unless VALID_TXT_OPTIONS.include?(key.downcase)
220
+ key, value = opt.split('=')
221
+ unless VALID_TXT_OPTIONS.include?(key.downcase)
222
+ msg = "TXT records can only specify the options [#{VALID_TXT_OPTIONS.join(', ')}]: #{string}"
223
+ raise Error::InvalidTXTRecord.new(msg)
224
+ end
227
225
  options_mapper.add_uri_option(key, value, txt_options)
228
226
  txt_options
229
227
  end
data/lib/mongo/uri.rb CHANGED
@@ -520,6 +520,24 @@ module Mongo
520
520
  elsif uri_options[:direct_connection] == false && uri_options[:connect].to_s == 'direct'
521
521
  raise_invalid_error_no_fmt!("directConnection=false cannot be used with connect=direct")
522
522
  end
523
+
524
+ if uri_options[:load_balanced]
525
+ if servers.length > 1
526
+ raise_invalid_error_no_fmt!("loadBalanced=true cannot be used with multiple seeds")
527
+ end
528
+
529
+ if uri_options[:direct_connection]
530
+ raise_invalid_error_no_fmt!("directConnection=true cannot be used with loadBalanced=true")
531
+ end
532
+
533
+ if uri_options[:connect] && uri_options[:connect].to_sym == :direct
534
+ raise_invalid_error_no_fmt!("connect=direct cannot be used with loadBalanced=true")
535
+ end
536
+
537
+ if uri_options[:replica_set]
538
+ raise_invalid_error_no_fmt!("loadBalanced=true cannot be used with replicaSet option")
539
+ end
540
+ end
523
541
  end
524
542
  end
525
543
  end
data/lib/mongo/utils.rb CHANGED
@@ -102,13 +102,6 @@ module Mongo
102
102
  Process.clock_gettime(Process::CLOCK_MONOTONIC)
103
103
  end
104
104
 
105
- # Hash#compact implementation for Ruby 2.3
106
- module_function def compact_hash(hash)
107
- Hash[hash.reject do |k, v|
108
- v.nil?
109
- end]
110
- end
111
-
112
105
  # Hash#compact implementation for Ruby 2.3/2.4
113
106
  # Implementation based on activesupport 5.2.3
114
107
  module_function def slice_hash(hash, *keys)
data/lib/mongo/version.rb CHANGED
@@ -20,5 +20,5 @@ module Mongo
20
20
  # The current version of the driver.
21
21
  #
22
22
  # @since 2.0.0
23
- VERSION = '2.15.0'.freeze
23
+ VERSION = '2.16.1'.freeze
24
24
  end
data/mongo.gemspec CHANGED
@@ -36,7 +36,7 @@ Gem::Specification.new do |s|
36
36
  s.require_paths = ['lib']
37
37
  s.bindir = 'bin'
38
38
 
39
- s.required_ruby_version = ">= 2.3"
39
+ s.required_ruby_version = ">= 2.4"
40
40
 
41
41
  s.add_dependency 'bson', '>=4.8.2', '<5.0.0'
42
42
  end
@@ -14,7 +14,7 @@ describe 'Auth' do
14
14
  end
15
15
 
16
16
  let(:base_options) do
17
- SpecConfig.instance.monitoring_options
17
+ SpecConfig.instance.monitoring_options.merge(connect: SpecConfig.instance.test_options[:connect])
18
18
  end
19
19
 
20
20
  let(:connection) do
@@ -276,4 +276,34 @@ describe 'Auth' do
276
276
  client.database.command(ping: 1)
277
277
  end
278
278
  end
279
+
280
+ context 'in lb topology' do
281
+ require_topology :load_balanced
282
+
283
+ context 'when authentication fails with network error' do
284
+ let(:server) do
285
+ authorized_client.cluster.next_primary
286
+ end
287
+
288
+ let(:base_options) do
289
+ SpecConfig.instance.monitoring_options.merge(connect: SpecConfig.instance.test_options[:connect])
290
+ end
291
+
292
+ let(:connection) do
293
+ Mongo::Server::Connection.new(server, base_options)
294
+ end
295
+
296
+ it 'includes service id in exception' do
297
+ expect_any_instance_of(Mongo::Server::PendingConnection).to receive(:authenticate!).and_raise(Mongo::Error::SocketError)
298
+
299
+ begin
300
+ connection.connect!
301
+ rescue Mongo::Error::SocketError => exc
302
+ exc.service_id.should_not be nil
303
+ else
304
+ fail 'Expected the SocketError to be raised'
305
+ end
306
+ end
307
+ end
308
+ end
279
309
  end
@@ -9,7 +9,7 @@ describe 'awaited hello' do
9
9
  # If we send the consecutive hello commands to different mongoses,
10
10
  # they have different process ids, and so the awaited one would return
11
11
  # immediately.
12
- require_no_multi_shard
12
+ require_no_multi_mongos
13
13
 
14
14
  let(:client) { authorized_client }
15
15
 
@@ -21,7 +21,7 @@ describe 'Bulk writes' do
21
21
  end
22
22
 
23
23
  context 'when bulk write needs to be split' do
24
- let(:subscriber) { EventSubscriber.new }
24
+ let(:subscriber) { Mrss::EventSubscriber.new }
25
25
 
26
26
  let(:max_bson_size) { Mongo::Server::ConnectionBase::DEFAULT_MAX_BSON_OBJECT_SIZE }
27
27