mongo 2.11.4 → 2.12.3

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 (357) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CONTRIBUTING.md +1 -1
  5. data/README.md +2 -1
  6. data/lib/mongo.rb +3 -0
  7. data/lib/mongo/address.rb +44 -19
  8. data/lib/mongo/auth.rb +1 -0
  9. data/lib/mongo/auth/credential_cache.rb +51 -0
  10. data/lib/mongo/auth/scram/conversation.rb +20 -16
  11. data/lib/mongo/auth/user.rb +0 -8
  12. data/lib/mongo/auth/user/view.rb +4 -4
  13. data/lib/mongo/background_thread.rb +1 -1
  14. data/lib/mongo/bulk_write.rb +5 -5
  15. data/lib/mongo/client.rb +143 -14
  16. data/lib/mongo/client_encryption.rb +103 -0
  17. data/lib/mongo/cluster.rb +8 -4
  18. data/lib/mongo/cluster/reapers/cursor_reaper.rb +18 -6
  19. data/lib/mongo/cluster/sdam_flow.rb +54 -58
  20. data/lib/mongo/collection.rb +3 -3
  21. data/lib/mongo/collection/view.rb +1 -1
  22. data/lib/mongo/collection/view/aggregation.rb +1 -1
  23. data/lib/mongo/collection/view/change_stream.rb +12 -3
  24. data/lib/mongo/collection/view/iterable.rb +14 -5
  25. data/lib/mongo/collection/view/map_reduce.rb +2 -2
  26. data/lib/mongo/collection/view/readable.rb +9 -7
  27. data/lib/mongo/collection/view/writable.rb +7 -7
  28. data/lib/mongo/crypt.rb +33 -0
  29. data/lib/mongo/crypt/auto_decryption_context.rb +40 -0
  30. data/lib/mongo/crypt/auto_encrypter.rb +179 -0
  31. data/lib/mongo/crypt/auto_encryption_context.rb +44 -0
  32. data/lib/mongo/crypt/binary.rb +155 -0
  33. data/lib/mongo/crypt/binding.rb +1229 -0
  34. data/lib/mongo/crypt/context.rb +135 -0
  35. data/lib/mongo/crypt/data_key_context.rb +162 -0
  36. data/lib/mongo/crypt/encryption_io.rb +289 -0
  37. data/lib/mongo/crypt/explicit_decryption_context.rb +40 -0
  38. data/lib/mongo/crypt/explicit_encrypter.rb +117 -0
  39. data/lib/mongo/crypt/explicit_encryption_context.rb +89 -0
  40. data/lib/mongo/crypt/handle.rb +315 -0
  41. data/lib/mongo/crypt/hooks.rb +90 -0
  42. data/lib/mongo/crypt/kms_context.rb +67 -0
  43. data/lib/mongo/crypt/status.rb +131 -0
  44. data/lib/mongo/cursor.rb +64 -32
  45. data/lib/mongo/database.rb +23 -6
  46. data/lib/mongo/database/view.rb +13 -4
  47. data/lib/mongo/dbref.rb +9 -2
  48. data/lib/mongo/error.rb +5 -1
  49. data/lib/mongo/error/bulk_write_error.rb +16 -14
  50. data/lib/mongo/error/crypt_error.rb +31 -0
  51. data/lib/mongo/error/{failed_stringprep_validation.rb → failed_string_prep_validation.rb} +0 -0
  52. data/lib/mongo/error/invalid_cursor_operation.rb +27 -0
  53. data/lib/mongo/error/kms_error.rb +22 -0
  54. data/lib/mongo/error/max_bson_size.rb +14 -3
  55. data/lib/mongo/error/mongocryptd_spawn_error.rb +22 -0
  56. data/lib/mongo/error/no_server_available.rb +8 -3
  57. data/lib/mongo/error/notable.rb +0 -15
  58. data/lib/mongo/error/operation_failure.rb +1 -0
  59. data/lib/mongo/error/parser.rb +1 -1
  60. data/lib/mongo/grid/file.rb +5 -0
  61. data/lib/mongo/grid/file/chunk.rb +2 -0
  62. data/lib/mongo/grid/file/info.rb +3 -2
  63. data/lib/mongo/grid/fs_bucket.rb +15 -13
  64. data/lib/mongo/grid/stream/write.rb +9 -3
  65. data/lib/mongo/index/view.rb +3 -3
  66. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +1 -1
  67. data/lib/mongo/monitoring/event/command_started.rb +6 -1
  68. data/lib/mongo/operation/collections_info.rb +6 -3
  69. data/lib/mongo/operation/delete/op_msg.rb +1 -1
  70. data/lib/mongo/operation/find/op_msg.rb +4 -1
  71. data/lib/mongo/operation/get_more/op_msg.rb +4 -1
  72. data/lib/mongo/operation/insert/command.rb +3 -2
  73. data/lib/mongo/operation/insert/legacy.rb +3 -2
  74. data/lib/mongo/operation/insert/op_msg.rb +3 -3
  75. data/lib/mongo/operation/result.rb +36 -27
  76. data/lib/mongo/operation/shared/executable.rb +11 -9
  77. data/lib/mongo/operation/shared/executable_no_validate.rb +2 -2
  78. data/lib/mongo/operation/shared/op_msg_or_command.rb +2 -2
  79. data/lib/mongo/operation/shared/op_msg_or_find_command.rb +2 -2
  80. data/lib/mongo/operation/shared/op_msg_or_list_indexes_command.rb +2 -2
  81. data/lib/mongo/operation/shared/read_preference_supported.rb +68 -19
  82. data/lib/mongo/operation/shared/response_handling.rb +1 -1
  83. data/lib/mongo/operation/shared/sessions_supported.rb +44 -3
  84. data/lib/mongo/operation/shared/write.rb +17 -10
  85. data/lib/mongo/operation/update/op_msg.rb +1 -1
  86. data/lib/mongo/protocol/bit_vector.rb +2 -1
  87. data/lib/mongo/protocol/compressed.rb +6 -5
  88. data/lib/mongo/protocol/insert.rb +3 -1
  89. data/lib/mongo/protocol/message.rb +94 -15
  90. data/lib/mongo/protocol/msg.rb +207 -37
  91. data/lib/mongo/protocol/query.rb +7 -9
  92. data/lib/mongo/protocol/serializers.rb +43 -15
  93. data/lib/mongo/retryable.rb +1 -1
  94. data/lib/mongo/server.rb +10 -4
  95. data/lib/mongo/server/connection.rb +20 -9
  96. data/lib/mongo/server/connection_base.rb +118 -18
  97. data/lib/mongo/server/connection_common.rb +61 -0
  98. data/lib/mongo/server/connection_pool.rb +37 -1
  99. data/lib/mongo/server/connection_pool/populator.rb +1 -1
  100. data/lib/mongo/server/description.rb +9 -11
  101. data/lib/mongo/server/monitor.rb +2 -0
  102. data/lib/mongo/server/monitor/connection.rb +3 -18
  103. data/lib/mongo/server/pending_connection.rb +2 -1
  104. data/lib/mongo/session.rb +3 -3
  105. data/lib/mongo/session/session_pool.rb +8 -3
  106. data/lib/mongo/socket.rb +29 -16
  107. data/lib/mongo/socket/ssl.rb +23 -8
  108. data/lib/mongo/socket/tcp.rb +12 -3
  109. data/lib/mongo/srv/monitor.rb +73 -42
  110. data/lib/mongo/srv/result.rb +0 -1
  111. data/lib/mongo/timeout.rb +49 -0
  112. data/lib/mongo/uri.rb +30 -1
  113. data/lib/mongo/uri/srv_protocol.rb +1 -1
  114. data/lib/mongo/version.rb +1 -1
  115. data/mongo.gemspec +1 -3
  116. data/spec/README.md +228 -7
  117. data/spec/integration/auth_spec.rb +53 -0
  118. data/spec/integration/bulk_write_spec.rb +19 -0
  119. data/spec/integration/{client_options_spec.rb → client_authentication_options_spec.rb} +10 -10
  120. data/spec/integration/client_construction_spec.rb +100 -1
  121. data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +353 -0
  122. data/spec/integration/client_side_encryption/auto_encryption_command_monitoring_spec.rb +303 -0
  123. data/spec/integration/client_side_encryption/auto_encryption_mongocryptd_spawn_spec.rb +72 -0
  124. data/spec/integration/client_side_encryption/auto_encryption_old_wire_version_spec.rb +79 -0
  125. data/spec/integration/client_side_encryption/auto_encryption_reconnect_spec.rb +221 -0
  126. data/spec/integration/client_side_encryption/auto_encryption_spec.rb +601 -0
  127. data/spec/integration/client_side_encryption/bson_size_limit_spec.rb +187 -0
  128. data/spec/integration/client_side_encryption/bypass_mongocryptd_spawn_spec.rb +78 -0
  129. data/spec/integration/client_side_encryption/client_close_spec.rb +63 -0
  130. data/spec/integration/client_side_encryption/corpus_spec.rb +233 -0
  131. data/spec/integration/client_side_encryption/custom_endpoint_spec.rb +132 -0
  132. data/spec/integration/client_side_encryption/data_key_spec.rb +165 -0
  133. data/spec/integration/client_side_encryption/explicit_encryption_spec.rb +114 -0
  134. data/spec/integration/client_side_encryption/external_key_vault_spec.rb +141 -0
  135. data/spec/integration/client_side_encryption/views_spec.rb +44 -0
  136. data/spec/integration/client_update_spec.rb +154 -0
  137. data/spec/integration/command_monitoring_spec.rb +3 -1
  138. data/spec/integration/command_spec.rb +44 -10
  139. data/spec/integration/connection_spec.rb +57 -0
  140. data/spec/integration/crud_spec.rb +89 -0
  141. data/spec/integration/grid_fs_bucket_spec.rb +48 -0
  142. data/spec/integration/read_preference_spec.rb +26 -0
  143. data/spec/integration/reconnect_spec.rb +7 -6
  144. data/spec/integration/size_limit_spec.rb +111 -0
  145. data/spec/integration/srv_monitoring_spec.rb +16 -8
  146. data/spec/integration/zlib_compression_spec.rb +25 -0
  147. data/spec/kerberos/kerberos_spec.rb +87 -0
  148. data/spec/lite_spec_helper.rb +34 -29
  149. data/spec/mongo/auth/cr_spec.rb +8 -0
  150. data/spec/mongo/auth/ldap_spec.rb +5 -1
  151. data/spec/mongo/auth/scram/conversation_spec.rb +5 -6
  152. data/spec/mongo/auth/scram/negotiation_spec.rb +74 -75
  153. data/spec/mongo/auth/scram_spec.rb +45 -35
  154. data/spec/mongo/auth/user/view_spec.rb +3 -6
  155. data/spec/mongo/auth/x509_spec.rb +5 -1
  156. data/spec/mongo/bulk_write/result_spec.rb +11 -7
  157. data/spec/mongo/client_construction_spec.rb +206 -2
  158. data/spec/mongo/client_encryption_spec.rb +405 -0
  159. data/spec/mongo/cluster/cursor_reaper_spec.rb +12 -8
  160. data/spec/mongo/cluster/socket_reaper_spec.rb +14 -3
  161. data/spec/mongo/collection/view/aggregation_spec.rb +0 -2
  162. data/spec/mongo/collection/view/change_stream_spec.rb +7 -7
  163. data/spec/mongo/collection/view/map_reduce_spec.rb +3 -3
  164. data/spec/mongo/collection/view_spec.rb +1 -1
  165. data/spec/mongo/collection_spec.rb +28 -9
  166. data/spec/mongo/crypt/auto_decryption_context_spec.rb +90 -0
  167. data/spec/mongo/crypt/auto_encrypter_spec.rb +187 -0
  168. data/spec/mongo/crypt/auto_encryption_context_spec.rb +107 -0
  169. data/spec/mongo/crypt/binary_spec.rb +115 -0
  170. data/spec/mongo/crypt/binding/binary_spec.rb +56 -0
  171. data/spec/mongo/crypt/binding/context_spec.rb +257 -0
  172. data/spec/mongo/crypt/binding/helpers_spec.rb +46 -0
  173. data/spec/mongo/crypt/binding/mongocrypt_spec.rb +144 -0
  174. data/spec/mongo/crypt/binding/status_spec.rb +99 -0
  175. data/spec/mongo/crypt/binding/version_spec.rb +22 -0
  176. data/spec/mongo/crypt/binding_unloaded_spec.rb +20 -0
  177. data/spec/mongo/crypt/data_key_context_spec.rb +213 -0
  178. data/spec/mongo/crypt/encryption_io_spec.rb +136 -0
  179. data/spec/mongo/crypt/explicit_decryption_context_spec.rb +72 -0
  180. data/spec/mongo/crypt/explicit_encryption_context_spec.rb +170 -0
  181. data/spec/mongo/crypt/handle_spec.rb +232 -0
  182. data/spec/mongo/crypt/helpers/mongo_crypt_spec_helper.rb +108 -0
  183. data/spec/mongo/crypt/status_spec.rb +152 -0
  184. data/spec/mongo/cursor_spec.rb +24 -4
  185. data/spec/mongo/database_spec.rb +20 -0
  186. data/spec/mongo/error/bulk_write_error_spec.rb +49 -0
  187. data/spec/mongo/error/crypt_error_spec.rb +26 -0
  188. data/spec/mongo/error/max_bson_size_spec.rb +35 -0
  189. data/spec/mongo/error/no_server_available_spec.rb +11 -1
  190. data/spec/mongo/error/notable_spec.rb +59 -0
  191. data/spec/mongo/error/operation_failure_spec.rb +6 -6
  192. data/spec/mongo/operation/aggregate_spec.rb +1 -1
  193. data/spec/mongo/operation/collections_info_spec.rb +1 -1
  194. data/spec/mongo/operation/command_spec.rb +3 -3
  195. data/spec/mongo/operation/create_index_spec.rb +3 -3
  196. data/spec/mongo/operation/create_user_spec.rb +3 -3
  197. data/spec/mongo/operation/delete/bulk_spec.rb +6 -6
  198. data/spec/mongo/operation/delete/op_msg_spec.rb +1 -6
  199. data/spec/mongo/operation/delete_spec.rb +7 -7
  200. data/spec/mongo/operation/drop_index_spec.rb +2 -2
  201. data/spec/mongo/operation/find/legacy_spec.rb +2 -1
  202. data/spec/mongo/operation/get_more_spec.rb +1 -1
  203. data/spec/mongo/operation/indexes_spec.rb +1 -1
  204. data/spec/mongo/operation/insert/bulk_spec.rb +7 -7
  205. data/spec/mongo/operation/insert/op_msg_spec.rb +3 -6
  206. data/spec/mongo/operation/insert_spec.rb +12 -12
  207. data/spec/mongo/operation/map_reduce_spec.rb +2 -2
  208. data/spec/mongo/operation/read_preference_legacy_spec.rb +351 -0
  209. data/spec/mongo/operation/read_preference_op_msg_spec.rb +194 -0
  210. data/spec/mongo/operation/remove_user_spec.rb +3 -3
  211. data/spec/mongo/operation/update/bulk_spec.rb +6 -6
  212. data/spec/mongo/operation/update/op_msg_spec.rb +3 -6
  213. data/spec/mongo/operation/update_spec.rb +7 -7
  214. data/spec/mongo/operation/update_user_spec.rb +1 -1
  215. data/spec/mongo/protocol/compressed_spec.rb +2 -3
  216. data/spec/mongo/protocol/delete_spec.rb +9 -8
  217. data/spec/mongo/protocol/get_more_spec.rb +9 -8
  218. data/spec/mongo/protocol/insert_spec.rb +9 -8
  219. data/spec/mongo/protocol/kill_cursors_spec.rb +6 -5
  220. data/spec/mongo/protocol/msg_spec.rb +57 -53
  221. data/spec/mongo/protocol/query_spec.rb +12 -12
  222. data/spec/mongo/protocol/registry_spec.rb +1 -1
  223. data/spec/mongo/protocol/reply_spec.rb +1 -1
  224. data/spec/mongo/protocol/update_spec.rb +10 -9
  225. data/spec/mongo/server/connection_pool_spec.rb +1 -1
  226. data/spec/mongo/server/connection_spec.rb +28 -7
  227. data/spec/mongo/socket_spec.rb +1 -1
  228. data/spec/mongo/srv/monitor_spec.rb +88 -69
  229. data/spec/mongo/timeout_spec.rb +85 -0
  230. data/spec/mongo/uri/srv_protocol_spec.rb +2 -2
  231. data/spec/mongo/uri_spec.rb +52 -5
  232. data/spec/mongo/write_concern_spec.rb +13 -1
  233. data/spec/{support → runners}/auth.rb +14 -1
  234. data/spec/{support → runners}/change_streams.rb +1 -1
  235. data/spec/{support → runners}/change_streams/operation.rb +0 -0
  236. data/spec/{support → runners}/cmap.rb +1 -1
  237. data/spec/{support → runners}/cmap/verifier.rb +0 -0
  238. data/spec/{support → runners}/command_monitoring.rb +0 -0
  239. data/spec/runners/connection_string.rb +358 -4
  240. data/spec/{support → runners}/crud.rb +9 -9
  241. data/spec/{support → runners}/crud/context.rb +0 -0
  242. data/spec/{support → runners}/crud/operation.rb +7 -3
  243. data/spec/{support → runners}/crud/outcome.rb +0 -0
  244. data/spec/{support → runners}/crud/requirement.rb +1 -1
  245. data/spec/{support → runners}/crud/spec.rb +12 -1
  246. data/spec/{support → runners}/crud/test.rb +0 -0
  247. data/spec/{support → runners}/crud/test_base.rb +0 -0
  248. data/spec/{support → runners}/crud/verifier.rb +10 -12
  249. data/spec/{support → runners}/gridfs.rb +0 -0
  250. data/spec/{support → runners}/sdam_monitoring.rb +0 -0
  251. data/spec/{support → runners}/server_discovery_and_monitoring.rb +0 -0
  252. data/spec/{support → runners}/server_selection.rb +0 -0
  253. data/spec/{support → runners}/server_selection_rtt.rb +0 -0
  254. data/spec/{support → runners}/transactions.rb +9 -11
  255. data/spec/{support → runners}/transactions/context.rb +0 -0
  256. data/spec/{support → runners}/transactions/operation.rb +0 -0
  257. data/spec/{support → runners}/transactions/spec.rb +0 -0
  258. data/spec/{support → runners}/transactions/test.rb +37 -5
  259. data/spec/spec_helper.rb +0 -5
  260. data/spec/spec_tests/auth_spec.rb +3 -3
  261. data/spec/spec_tests/client_side_encryption_spec.rb +8 -0
  262. data/spec/spec_tests/connection_string_spec.rb +1 -1
  263. data/spec/spec_tests/data/auth/connection-string.yml +13 -0
  264. data/spec/spec_tests/data/client_side_encryption/aggregate.yml +134 -0
  265. data/spec/spec_tests/data/client_side_encryption/badQueries.yml +526 -0
  266. data/spec/spec_tests/data/client_side_encryption/badSchema.yml +73 -0
  267. data/spec/spec_tests/data/client_side_encryption/basic.yml +116 -0
  268. data/spec/spec_tests/data/client_side_encryption/bulk.yml +88 -0
  269. data/spec/spec_tests/data/client_side_encryption/bypassAutoEncryption.yml +100 -0
  270. data/spec/spec_tests/data/client_side_encryption/bypassedCommand.yml +42 -0
  271. data/spec/spec_tests/data/client_side_encryption/count.yml +61 -0
  272. data/spec/spec_tests/data/client_side_encryption/countDocuments.yml +59 -0
  273. data/spec/spec_tests/data/client_side_encryption/delete.yml +105 -0
  274. data/spec/spec_tests/data/client_side_encryption/distinct.yml +73 -0
  275. data/spec/spec_tests/data/client_side_encryption/explain.yml +64 -0
  276. data/spec/spec_tests/data/client_side_encryption/find.yml +119 -0
  277. data/spec/spec_tests/data/client_side_encryption/findOneAndDelete.yml +57 -0
  278. data/spec/spec_tests/data/client_side_encryption/findOneAndReplace.yml +57 -0
  279. data/spec/spec_tests/data/client_side_encryption/findOneAndUpdate.yml +57 -0
  280. data/spec/spec_tests/data/client_side_encryption/getMore.yml +68 -0
  281. data/spec/spec_tests/data/client_side_encryption/insert.yml +102 -0
  282. data/spec/spec_tests/data/client_side_encryption/keyAltName.yml +71 -0
  283. data/spec/spec_tests/data/client_side_encryption/localKMS.yml +54 -0
  284. data/spec/spec_tests/data/client_side_encryption/localSchema.yml +72 -0
  285. data/spec/spec_tests/data/client_side_encryption/malformedCiphertext.yml +69 -0
  286. data/spec/spec_tests/data/client_side_encryption/maxWireVersion.yml +20 -0
  287. data/spec/spec_tests/data/client_side_encryption/missingKey.yml +49 -0
  288. data/spec/spec_tests/data/client_side_encryption/replaceOne.yml +64 -0
  289. data/spec/spec_tests/data/client_side_encryption/types.yml +527 -0
  290. data/spec/spec_tests/data/client_side_encryption/unsupportedCommand.yml +25 -0
  291. data/spec/spec_tests/data/client_side_encryption/updateMany.yml +77 -0
  292. data/spec/spec_tests/data/client_side_encryption/updateOne.yml +171 -0
  293. data/spec/spec_tests/data/read_write_concern/connection-string/write-concern.yml +1 -4
  294. data/spec/spec_tests/data/retryable_writes/insertOne-serverErrors.yml +21 -0
  295. data/spec/spec_tests/data/sdam/rs/incompatible_ghost.yml +2 -4
  296. data/spec/spec_tests/data/sdam/rs/incompatible_other.yml +1 -1
  297. data/spec/spec_tests/data/sdam/rs/primary_mismatched_me_not_removed.yml +73 -0
  298. data/spec/spec_tests/data/sdam/rs/primary_to_no_primary_mismatched_me.yml +1 -2
  299. data/spec/spec_tests/data/sdam/rs/repeated.yml +101 -0
  300. data/spec/spec_tests/data/sdam/rs/{primary_address_change.yml → ruby_primary_address_change.yml} +2 -0
  301. data/spec/spec_tests/data/sdam/rs/{secondary_wrong_set_name_with_primary_second.yml → ruby_secondary_wrong_set_name_with_primary_second.yml} +0 -0
  302. data/spec/spec_tests/data/sdam/sharded/ruby_discovered_single_mongos.yml +27 -0
  303. data/spec/spec_tests/data/sdam/sharded/{primary_address_change.yml → ruby_primary_different_address.yml} +1 -1
  304. data/spec/spec_tests/data/sdam/sharded/{primary_mismatched_me.yml → ruby_primary_mismatched_me.yml} +1 -1
  305. data/spec/spec_tests/data/sdam/single/{primary_address_change.yml → ruby_primary_different_address.yml} +1 -1
  306. data/spec/spec_tests/data/sdam/single/{primary_mismatched_me.yml → ruby_primary_mismatched_me.yml} +1 -1
  307. data/spec/spec_tests/data/sdam_monitoring/{replica_set_with_primary_change.yml → replica_set_primary_address_change.yml} +27 -5
  308. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_me_mismatch.yml +26 -74
  309. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_removal.yml +20 -16
  310. data/spec/spec_tests/data/sdam_monitoring/standalone_suppress_equal_description_changes.yml +73 -0
  311. data/spec/spec_tests/data/transactions/pin-mongos.yml +2 -3
  312. data/spec/spec_tests/data/uri_options/auth-options.yml +10 -0
  313. data/spec/spec_tests/data/uri_options/tls-options.yml +75 -4
  314. data/spec/spec_tests/read_write_concern_connection_string_spec.rb +1 -1
  315. data/spec/spec_tests/uri_options_spec.rb +6 -8
  316. data/spec/stress/connection_pool_timing_spec.rb +6 -3
  317. data/spec/support/certificates/README.md +4 -0
  318. data/spec/support/certificates/server-second-level-bundle.pem +77 -77
  319. data/spec/support/certificates/server-second-level.crt +52 -52
  320. data/spec/support/certificates/server-second-level.key +25 -25
  321. data/spec/support/certificates/server-second-level.pem +77 -77
  322. data/spec/support/client_registry.rb +19 -3
  323. data/spec/support/cluster_config.rb +9 -1
  324. data/spec/support/cluster_tools.rb +6 -1
  325. data/spec/support/common_shortcuts.rb +12 -0
  326. data/spec/support/constraints.rb +16 -0
  327. data/spec/support/crypt.rb +154 -0
  328. data/spec/support/crypt/corpus/corpus-key-aws.json +33 -0
  329. data/spec/support/crypt/corpus/corpus-key-local.json +31 -0
  330. data/spec/support/crypt/corpus/corpus-schema.json +2057 -0
  331. data/spec/support/crypt/corpus/corpus.json +3657 -0
  332. data/spec/support/crypt/corpus/corpus_encrypted.json +4152 -0
  333. data/spec/support/crypt/data_keys/key_document_aws.json +34 -0
  334. data/spec/support/crypt/data_keys/key_document_local.json +31 -0
  335. data/spec/support/crypt/external/external-key.json +31 -0
  336. data/spec/support/crypt/external/external-schema.json +19 -0
  337. data/spec/support/crypt/limits/limits-doc.json +102 -0
  338. data/spec/support/crypt/limits/limits-key.json +31 -0
  339. data/spec/support/crypt/limits/limits-schema.json +1405 -0
  340. data/spec/support/crypt/schema_maps/schema_map_aws.json +17 -0
  341. data/spec/support/crypt/schema_maps/schema_map_aws_key_alt_names.json +12 -0
  342. data/spec/support/crypt/schema_maps/schema_map_local.json +18 -0
  343. data/spec/support/crypt/schema_maps/schema_map_local_key_alt_names.json +12 -0
  344. data/spec/support/lite_constraints.rb +19 -1
  345. data/spec/support/matchers.rb +19 -0
  346. data/spec/support/shared/protocol.rb +2 -0
  347. data/spec/support/spec_config.rb +53 -13
  348. data/spec/support/utils.rb +140 -10
  349. metadata +894 -687
  350. metadata.gz.sig +0 -0
  351. data/lib/mongo/cluster/srv_monitor.rb +0 -127
  352. data/lib/mongo/srv/warning_result.rb +0 -35
  353. data/spec/enterprise_auth/kerberos_spec.rb +0 -58
  354. data/spec/mongo/cluster/srv_monitor_spec.rb +0 -214
  355. data/spec/mongo/operation/read_preference_spec.rb +0 -245
  356. data/spec/spec_tests/data/sdam/sharded/single_mongos.yml +0 -33
  357. data/spec/support/connection_string.rb +0 -354
@@ -144,7 +144,7 @@ module Mongo
144
144
  # @note This only retries read operations on socket errors.
145
145
  #
146
146
  # @param [ Hash ] options Options.
147
- # @param [ Proc ] block The block to execute.
147
+ # @yield Calls the provided block with no arguments
148
148
  #
149
149
  # @option options [ String ] :retry_message Message to log when retrying.
150
150
  #
@@ -124,11 +124,16 @@ module Mongo
124
124
  # @deprecated
125
125
  def_delegators :monitor, :scan!
126
126
 
127
- # The last compressor discovered by the server monitor.
127
+ # The compressor negotiated by the server monitor, if any.
128
128
  #
129
- # The compressor state should be determined for each individual
130
- # connection rather than kept per server. A future version of the
131
- # driver will change how compressors are tracked and used.
129
+ # This attribute is nil if no server check has not yet completed, and if
130
+ # no compression was negatiated.
131
+ #
132
+ # @note Compression is negotiated for each connection separately.
133
+ #
134
+ # @return [ String | nil ] The negotiated compressor.
135
+ #
136
+ # @deprecated
132
137
  def compressor
133
138
  if monitor
134
139
  monitor.compressor
@@ -523,6 +528,7 @@ end
523
528
 
524
529
  require 'mongo/server/app_metadata'
525
530
  require 'mongo/server/connectable'
531
+ require 'mongo/server/connection_common'
526
532
  require 'mongo/server/connection_base'
527
533
  require 'mongo/server/pending_connection'
528
534
  require 'mongo/server/connection'
@@ -174,7 +174,7 @@ module Mongo
174
174
  unless @socket
175
175
  # When @socket is assigned, the socket should have handshaken and
176
176
  # authenticated and be usable.
177
- @socket = do_connect
177
+ @socket, @description = do_connect
178
178
 
179
179
  publish_cmap_event(
180
180
  Monitoring::Event::Cmap::ConnectionReady.new(address, id)
@@ -186,13 +186,17 @@ module Mongo
186
186
  end
187
187
 
188
188
  # Separate method to permit easier mocking in the test suite.
189
+ #
190
+ # @return [ Array<Socket, Server::Description> ] Connected socket and
191
+ # a server description instance from the ismaster response of the
192
+ # returned socket.
189
193
  def do_connect
190
194
  socket = address.socket(socket_timeout, ssl_options, address.options)
191
195
 
192
196
  begin
193
- handshake!(socket)
194
- unless description.arbiter?
195
- pending_connection = PendingConnection.new(socket, @server, monitoring, options.merge(id: id))
197
+ new_description = handshake!(socket)
198
+ unless new_description.arbiter?
199
+ pending_connection = PendingConnection.new(socket, new_description, @server, monitoring, options.merge(id: id))
196
200
  authenticate!(pending_connection)
197
201
  end
198
202
  rescue Exception
@@ -200,7 +204,7 @@ module Mongo
200
204
  raise
201
205
  end
202
206
 
203
- socket
207
+ [socket, new_description]
204
208
  end
205
209
  private :do_connect
206
210
 
@@ -303,6 +307,8 @@ module Mongo
303
307
 
304
308
  private
305
309
 
310
+ # @return [ Server::Description ] The server description calculated from
311
+ # ismaster response for this particular connection.
306
312
  def handshake!(socket)
307
313
  unless socket
308
314
  raise Error::HandshakeError, "Cannot handshake because there is no usable socket (for #{address})"
@@ -314,7 +320,7 @@ module Mongo
314
320
  response, exc, rtt, average_rtt =
315
321
  @server.round_trip_time_averager.measure do
316
322
  socket.write(app_metadata.ismaster_bytes)
317
- Protocol::Message.deserialize(socket, max_message_size).documents[0]
323
+ Protocol::Message.deserialize(socket, Protocol::Message::MAX_MESSAGE_SIZE).documents[0]
318
324
  end
319
325
 
320
326
  if exc
@@ -330,6 +336,9 @@ module Mongo
330
336
  end
331
337
 
332
338
  # This is a separate method to keep the nesting level down.
339
+ #
340
+ # @return [ Server::Description ] The server description calculated from
341
+ # ismaster response for this particular connection.
333
342
  def post_handshake(response, average_rtt)
334
343
  if response["ok"] == 1
335
344
  # Auth mechanism is entirely dependent on the contents of
@@ -359,12 +368,14 @@ module Mongo
359
368
  :mongodb_cr
360
369
  end
361
370
  end
371
+ set_compressor!(response)
362
372
  else
363
373
  @auth_mechanism = nil
364
374
  end
365
375
 
366
- @description = Description.new(address, response, average_rtt)
367
- @server.cluster.run_sdam_flow(@server.description, @description)
376
+ Description.new(address, response, average_rtt).tap do |new_description|
377
+ @server.cluster.run_sdam_flow(@server.description, new_description)
378
+ end
368
379
  end
369
380
 
370
381
  def authenticate!(pending_connection)
@@ -389,7 +400,7 @@ module Mongo
389
400
  @auth_mechanism || (@server.features.scram_sha_1_enabled? ? :scram : :mongodb_cr)
390
401
  end
391
402
 
392
- def deliver(message)
403
+ def deliver(message, client, options = {})
393
404
  begin
394
405
  super
395
406
  # Important: timeout errors are not handled here
@@ -22,10 +22,30 @@ module Mongo
22
22
  # the classes which include this module is not part of the public API.
23
23
  #
24
24
  # @api semipublic
25
- class ConnectionBase
25
+ class ConnectionBase < ConnectionCommon
26
26
  extend Forwardable
27
27
  include Monitoring::Publishable
28
28
 
29
+ # The maximum allowed size in bytes that a user-supplied document may
30
+ # take up when serialized, if the server's ismaster response does not
31
+ # include maxBsonObjectSize field.
32
+ #
33
+ # The commands that are sent to the server may exceed this size by
34
+ # MAX_BSON_COMMAND_OVERHEAD.
35
+ #
36
+ # @api private
37
+ DEFAULT_MAX_BSON_OBJECT_SIZE = 16777216
38
+
39
+ # The additional overhead allowed for command data (i.e. fields added
40
+ # to the command document by the driver, as opposed to documents
41
+ # provided by the user) when serializing a complete command to BSON.
42
+ #
43
+ # @api private
44
+ MAX_BSON_COMMAND_OVERHEAD = 16384
45
+
46
+ # @api private
47
+ REDUCED_MAX_BSON_SIZE = 2097152
48
+
29
49
  # @return [ Hash ] options The passed in options.
30
50
  attr_reader :options
31
51
 
@@ -38,14 +58,31 @@ module Mongo
38
58
  def_delegators :server, :address
39
59
 
40
60
  def_delegators :server,
41
- :features,
42
- :max_bson_object_size,
43
- :max_message_size,
44
- :mongos?,
45
- :compressor,
46
61
  :cluster_time,
47
62
  :update_cluster_time
48
63
 
64
+ # Returns the server description for this connection, derived from
65
+ # the isMaster response for the handshake performed on this connection.
66
+ #
67
+ # @note A connection object that hasn't yet connected (handshaken and
68
+ # authenticated, if authentication is required) does not have a
69
+ # description. While handshaking and authenticating the driver must
70
+ # be using global defaults, in particular not assuming that the
71
+ # properties of a particular connection are the same as properties
72
+ # of other connections made to the same address (since the server
73
+ # on the other end could have been shut down and a different server
74
+ # version could have been launched).
75
+ #
76
+ # @return [ Server::Description ] Server description for this connection.
77
+ # @api private
78
+ attr_reader :description
79
+
80
+ def_delegators :description,
81
+ :features,
82
+ :max_bson_object_size,
83
+ :max_message_size,
84
+ :mongos?
85
+
49
86
  def app_metadata
50
87
  @app_metadata ||= begin
51
88
  same = true
@@ -78,11 +115,16 @@ module Mongo
78
115
  # @param [ Array<Message> ] messages A one-element array containing
79
116
  # the message to dispatch.
80
117
  # @param [ Integer ] operation_id The operation id to link messages.
118
+ # @param [ Hash ] options
119
+ #
120
+ # @option options [ Boolean ] :deserialize_as_bson Whether to deserialize
121
+ # the response to this message using BSON objects in place of native
122
+ # Ruby types wherever possible.
81
123
  #
82
124
  # @return [ Protocol::Message | nil ] The reply if needed.
83
125
  #
84
126
  # @since 2.0.0
85
- def dispatch(messages, operation_id = nil)
127
+ def dispatch(messages, operation_id = nil, client = nil, options = {})
86
128
  # The monitoring code does not correctly handle multiple messages,
87
129
  # and the driver internally does not send more than one message at
88
130
  # a time ever. Thus prohibit multiple message use for now.
@@ -90,13 +132,16 @@ module Mongo
90
132
  raise ArgumentError, 'Can only dispatch one message at a time'
91
133
  end
92
134
  message = messages.first
93
- deliver(message)
135
+ deliver(message, client, options)
94
136
  end
95
137
 
96
138
  private
97
139
 
98
- def deliver(message)
99
- buffer = serialize(message)
140
+ def deliver(message, client, options = {})
141
+ if Lint.enabled? && !@socket
142
+ raise Error::LintError, "Trying to deliver a message over a disconnected connection (to #{address})"
143
+ end
144
+ buffer = serialize(message, client)
100
145
  ensure_connected do |socket|
101
146
  operation_id = Monitoring.next_operation_id
102
147
  command_started(address, operation_id, message.payload,
@@ -106,7 +151,7 @@ module Mongo
106
151
  begin
107
152
  socket.write(buffer.to_s)
108
153
  result = if message.replyable?
109
- Protocol::Message.deserialize(socket, max_message_size, message.request_id)
154
+ Protocol::Message.deserialize(socket, max_message_size, message.request_id, options)
110
155
  else
111
156
  nil
112
157
  end
@@ -118,18 +163,73 @@ module Mongo
118
163
  total_duration = Time.now - start
119
164
  command_completed(result, address, operation_id, message.payload, total_duration)
120
165
  end
166
+ if client && result
167
+ result = result.maybe_decrypt(client)
168
+ end
121
169
  result
122
170
  end
123
171
  end
124
172
 
125
- def serialize(message, buffer = BSON::ByteBuffer.new)
126
- start_size = 0
127
- message.compress!(compressor, options[:zlib_compression_level]).serialize(buffer, max_bson_object_size)
128
- if max_message_size &&
129
- (buffer.length - start_size) > max_message_size
130
- then
131
- raise Error::MaxMessageSize.new(max_message_size)
173
+ def serialize(message, client, buffer = BSON::ByteBuffer.new)
174
+ # Driver specifications only mandate the fixed 16MiB limit for
175
+ # serialized BSON documents. However, the server returns its
176
+ # active serialized BSON document size limit in the ismaster response,
177
+ # which is +max_bson_object_size+ below. The +DEFAULT_MAX_BSON_OBJECT_SIZE+
178
+ # is the 16MiB value mandated by the specifications which we use
179
+ # only as the default if the server's ismaster did not contain
180
+ # maxBsonObjectSize.
181
+ max_bson_size = max_bson_object_size || DEFAULT_MAX_BSON_OBJECT_SIZE
182
+ if client && client.encrypter && client.encrypter.encrypt?
183
+ # The client-side encryption specification requires bulk writes to
184
+ # be split at a reduced maxBsonObjectSize. If this message is a bulk
185
+ # write and its size exceeds the reduced size limit, the serializer
186
+ # will raise an exception, which is caught by BulkWrite. BulkWrite
187
+ # will split the operation into individual writes, which will
188
+ # not be subject to the reduced maxBsonObjectSize.
189
+ if message.bulk_write?
190
+ # Make the new maximum size equal to the specified reduced size
191
+ # limit plus the 16KiB overhead allowance.
192
+ max_bson_size = REDUCED_MAX_BSON_SIZE + MAX_BSON_COMMAND_OVERHEAD
193
+ end
194
+ else
195
+ max_bson_size += MAX_BSON_COMMAND_OVERHEAD
196
+ end
197
+
198
+ # RUBY-2234: It is necessary to check that the message size does not
199
+ # exceed the maximum bson object size before compressing and serializing
200
+ # the final message.
201
+ #
202
+ # This is to avoid the case where the user performs a bulk write
203
+ # larger than 16MiB which, when compressed, becomes smaller than 16MiB.
204
+ # If the driver does not split the bulk writes prior to compression,
205
+ # the entire operation will be sent to the server, which will raise an
206
+ # error because the uncompressed operation exceeds the maximum bson size.
207
+ #
208
+ # To address this problem, we serialize the message prior to compression
209
+ # and raise an exception if the serialized message exceeds the maximum
210
+ # bson size.
211
+ if max_message_size
212
+ # Create a separate buffer that contains the un-compressed message
213
+ # for the purpose of checking its size. Write any pre-existing contents
214
+ # from the original buffer into the temporary one.
215
+ temp_buffer = BSON::ByteBuffer.new
216
+
217
+ # TODO: address the fact that this line mutates the buffer.
218
+ temp_buffer.put_bytes(buffer.get_bytes(buffer.length))
219
+
220
+ message.serialize(temp_buffer, max_bson_size)
221
+ if temp_buffer.length > max_message_size
222
+ raise Error::MaxMessageSize.new(max_message_size)
223
+ end
132
224
  end
225
+
226
+ # RUBY-2335: When the un-compressed message is smaller than the maximum
227
+ # bson size limit, the message will be serialized twice. The operations
228
+ # layer should be refactored to allow compression on an already-
229
+ # serialized message.
230
+ final_message = message.maybe_compress(compressor, options[:zlib_compression_level])
231
+ final_message.serialize(buffer, max_bson_size)
232
+
133
233
  buffer
134
234
  end
135
235
  end
@@ -0,0 +1,61 @@
1
+ # Copyright (C) 2020 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+ class Server
17
+
18
+ # Common methods used by both monitoring and non-monitoring connections.
19
+ #
20
+ # @note Although methods of this module are part of the public API,
21
+ # the fact that these methods are defined on this module and not on
22
+ # the classes which include this module is not part of the public API.
23
+ #
24
+ # @api semipublic
25
+ class ConnectionCommon
26
+
27
+ # The compressor negotiated during the handshake for this connection,
28
+ # if any.
29
+ #
30
+ # This attribute is nil for connections that haven't completed the
31
+ # handshake yet, and for connections that negotiated no compression.
32
+ #
33
+ # @return [ String | nil ] The compressor.
34
+ attr_reader :compressor
35
+
36
+ private
37
+
38
+ def set_compressor!(reply)
39
+ server_compressors = reply['compression']
40
+
41
+ if options[:compressors]
42
+ if intersection = (server_compressors & options[:compressors])
43
+ @compressor = intersection.first
44
+ else
45
+ msg = if server_compressors
46
+ "The server at #{address} has no compression algorithms in common with those requested. " +
47
+ "Server algorithms: #{server_compressors.join(', ')}; " +
48
+ "Requested algorithms: #{options[:compressors].join(', ')}. " +
49
+ "Compression will not be used"
50
+ else
51
+ "The server at #{address} did not advertise compression support. " +
52
+ "Requested algorithms: #{options[:compressors].join(', ')}. " +
53
+ "Compression will not be used"
54
+ end
55
+ log_warn(msg)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -275,6 +275,8 @@ module Mongo
275
275
  #
276
276
  # @since 2.9.0
277
277
  def check_out
278
+ check_invariants
279
+
278
280
  publish_cmap_event(
279
281
  Monitoring::Event::Cmap::ConnectionCheckOutStarted.new(@server.address)
280
282
  )
@@ -345,7 +347,8 @@ module Mongo
345
347
  "from pool for #{@server.address} after #{wait_timeout} sec. " +
346
348
  "Connections in pool: #{@available_connections.length} available, " +
347
349
  "#{@checked_out_connections.length} checked out, " +
348
- "#{@pending_connections.length} pending"
350
+ "#{@pending_connections.length} pending " +
351
+ "(max size: #{max_size})"
349
352
  end
350
353
  raise Error::ConnectionCheckOutTimeout.new(msg, address: @server.address)
351
354
  end
@@ -379,7 +382,10 @@ module Mongo
379
382
  publish_cmap_event(
380
383
  Monitoring::Event::Cmap::ConnectionCheckedOut.new(@server.address, connection.id, self),
381
384
  )
385
+
382
386
  connection
387
+ ensure
388
+ check_invariants
383
389
  end
384
390
 
385
391
  # Check a connection back into the pool.
@@ -390,6 +396,8 @@ module Mongo
390
396
  #
391
397
  # @since 2.9.0
392
398
  def check_in(connection)
399
+ check_invariants
400
+
393
401
  @lock.synchronize do
394
402
  unless connection.connection_pool == self
395
403
  raise ArgumentError, "Trying to check in a connection which was not checked out by this pool: #{connection} checked out from pool #{connection.connection_pool} (for #{self})"
@@ -431,6 +439,8 @@ module Mongo
431
439
  @available_semaphore.signal
432
440
  end
433
441
  end
442
+ ensure
443
+ check_invariants
434
444
  end
435
445
 
436
446
  # Closes all idle connections in the pool and schedules currently checked
@@ -450,6 +460,8 @@ module Mongo
450
460
  def clear(options = nil)
451
461
  raise_if_closed!
452
462
 
463
+ check_invariants
464
+
453
465
  if options && options[:stop_populator]
454
466
  stop_populator
455
467
  end
@@ -471,6 +483,8 @@ module Mongo
471
483
  end
472
484
 
473
485
  true
486
+ ensure
487
+ check_invariants
474
488
  end
475
489
 
476
490
  # @since 2.1.0
@@ -734,6 +748,28 @@ module Mongo
734
748
  raise
735
749
  end
736
750
  end
751
+
752
+ def check_invariants
753
+ return unless Lint.enabled?
754
+
755
+ # Server summary calls pool summary which requires pool lock -> deadlock.
756
+ # Obtain the server summary ahead of time.
757
+ server_summary = @server.summary
758
+
759
+ @lock.synchronize do
760
+ @available_connections.each do |connection|
761
+ if connection.closed?
762
+ raise Error::LintError, "Available connection is closed: #{connection} for #{server_summary}"
763
+ end
764
+ end
765
+
766
+ @pending_connections.each do |connection|
767
+ if connection.closed?
768
+ raise Error::LintError, "Pending connection is closed: #{connection} for #{server_summary}"
769
+ end
770
+ end
771
+ end
772
+ end
737
773
  end
738
774
  end
739
775
  end