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
@@ -23,9 +23,9 @@ module Mongo
23
23
  module OpMsgOrListIndexesCommand
24
24
  include PolymorphicLookup
25
25
 
26
- def execute(server)
26
+ def execute(server, client:)
27
27
  operation = final_operation(server)
28
- operation.execute(server)
28
+ operation.execute(server, client: client)
29
29
  end
30
30
 
31
31
  private
@@ -15,19 +15,83 @@
15
15
  module Mongo
16
16
  module Operation
17
17
 
18
- # Shared behavior of operations that support read preference.
18
+ # Read preference handling for pre-OP_MSG operation implementations.
19
+ #
20
+ # This module is not used by OP_MSG operation classes (those deriving
21
+ # from OpMsgBase). Instead, read preference for those classes is handled
22
+ # in SessionsSupported module.
19
23
  #
20
24
  # @since 2.5.2
25
+ # @api private
21
26
  module ReadPreferenceSupported
22
27
 
23
28
  private
24
29
 
25
- SLAVE_OK = :slave_ok
26
-
30
+ # Get the options for executing the operation on a particular server.
31
+ #
32
+ # @param [ Server ] server The server that the operation will be
33
+ # executed on.
34
+ #
35
+ # @return [ Hash ] The options.
36
+ #
37
+ # @since 2.0.0
27
38
  def options(server)
28
- update_options_for_slave_ok(super, server)
39
+ add_slave_ok_flag_maybe(super, server)
40
+ end
41
+
42
+ # Adds :slave_ok flag to options based on the read preference specified
43
+ # in the operation or implied by the topology that the server is a
44
+ # part of.
45
+ #
46
+ # @param [ Hash ] options The options calculated so far.
47
+ #
48
+ # @return [ Hash ] The new options.
49
+ def add_slave_ok_flag_maybe(options, server)
50
+ add_flag =
51
+ # https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection.rst#topology-type-single
52
+ if server.standalone?
53
+ # Read preference is never sent to standalones.
54
+ false
55
+ elsif server.cluster.single?
56
+ # In Single topology the driver forces primaryPreferred read
57
+ # preference mode (via the slave_ok flag, in case of old servers)
58
+ # so that the query is satisfied.
59
+ true
60
+ else
61
+ # In replica sets and sharded clusters, read preference is passed
62
+ # to the server if one is specified by the application, and there
63
+ # is no default.
64
+ read && read.slave_ok?
65
+ end
66
+
67
+ if add_flag
68
+ options= options.dup
69
+ (options[:flags] ||= []) << :slave_ok
70
+ end
71
+
72
+ options
29
73
  end
30
74
 
75
+ def command(server)
76
+ sel = super
77
+ update_selector_for_read_pref(sel, server)
78
+ end
79
+
80
+ # Adds $readPreference field to the command document.
81
+ #
82
+ # $readPreference is only sent when the server is a mongos,
83
+ # following the rules described in
84
+ # https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection.rst#passing-read-preference-to-mongos.
85
+ # The topology does not matter for figuring out whether to send
86
+ # $readPreference since the decision is always made based on
87
+ # server type.
88
+ #
89
+ # $readPreference is not sent to pre-OP_MSG replica set members.
90
+ #
91
+ # @param [ Hash ] sel Existing command document.
92
+ # @param [ Server ] server The server that the command is to be sent to.
93
+ #
94
+ # @return [ Hash ] New command document to send to the server.
31
95
  def update_selector_for_read_pref(sel, server)
32
96
  if read && server.mongos? && read_pref = read.to_mongos
33
97
  Mongo::Lint.validate_camel_case_read_preference(read_pref)
@@ -37,21 +101,6 @@ module Mongo
37
101
  sel
38
102
  end
39
103
  end
40
-
41
- def update_options_for_slave_ok(opts, server)
42
- if (server.cluster.single? && !server.mongos?) || (read && read.slave_ok?)
43
- opts.dup.tap do |o|
44
- (o[:flags] ||= []) << SLAVE_OK
45
- end
46
- else
47
- opts
48
- end
49
- end
50
-
51
- def command(server)
52
- sel = super
53
- update_selector_for_read_pref(sel, server)
54
- end
55
104
  end
56
105
  end
57
106
  end
@@ -68,7 +68,7 @@ module Mongo
68
68
  # is included in BulkWrite which does not store the session in the
69
69
  # receiver (despite Specifiable doing so).
70
70
  #
71
- # @param [ Session | nil ] Session to consider.
71
+ # @param [ Session | nil ] session Session to consider.
72
72
  def unpin_maybe(session)
73
73
  yield
74
74
  rescue Mongo::Error => e
@@ -123,9 +123,8 @@ module Mongo
123
123
  sel = selector(server).dup
124
124
  add_write_concern!(sel)
125
125
  sel[Protocol::Msg::DATABASE_IDENTIFIER] = db_name
126
- unless server.standalone?
127
- sel['$readPreference'] = read.to_doc if read
128
- end
126
+
127
+ add_read_preference(sel, server)
129
128
 
130
129
  if server.features.sessions_enabled?
131
130
  apply_cluster_time!(sel, server)
@@ -139,6 +138,48 @@ module Mongo
139
138
  sel
140
139
  end
141
140
 
141
+ # Adds $readPreference field to the command document.
142
+ #
143
+ # $readPreference is only sent when the server is a mongos,
144
+ # following the rules described in
145
+ # https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection.rst#passing-read-preference-to-mongos.
146
+ # The topology does not matter for figuring out whether to send
147
+ # $readPreference since the decision is always made based on
148
+ # server type.
149
+ #
150
+ # $readPreference is sent to OP_MSG-grokking replica set members.
151
+ #
152
+ # @param [ Hash ] sel Existing command document which will be mutated.
153
+ # @param [ Server ] server The server that the command is to be sent to.
154
+ def add_read_preference(sel, server)
155
+ # https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection.rst#topology-type-single
156
+ if server.standalone?
157
+ # Read preference is never sent to standalones.
158
+ elsif server.cluster.single?
159
+ # In Single topology:
160
+ # - If no read preference is specified by the application, the driver
161
+ # adds mode: primaryPreferred.
162
+ # - If a read preference is specified by the application, the driver
163
+ # replaces the mode with primaryPreferred.
164
+ read_doc = if read
165
+ BSON::Document.new(read.to_doc)
166
+ else
167
+ BSON::Document.new
168
+ end
169
+ if [nil, 'primary'].include?(read_doc['mode'])
170
+ read_doc['mode'] = 'primaryPreferred'
171
+ end
172
+ sel['$readPreference'] = read_doc
173
+ else
174
+ # In replica sets and sharded clusters, read preference is passed
175
+ # to the server if one is specified by the application, and there
176
+ # is no default.
177
+ if read
178
+ sel['$readPreference'] = read.to_doc
179
+ end
180
+ end
181
+ end
182
+
142
183
  def apply_session_options(sel, server)
143
184
  apply_cluster_time!(sel, server)
144
185
  sel[:txnNumber] = BSON::Int64.new(txn_num) if txn_num
@@ -25,42 +25,49 @@ module Mongo
25
25
  # Execute the operation.
26
26
  #
27
27
  # @example
28
- # operation.execute(server)
28
+ # operation.execute(server, client: nil)
29
29
  #
30
30
  # @param [ Mongo::Server ] server The server to send the operation to.
31
+ # @param [ Mongo::Client ] client The client that will be used to
32
+ # perform auto-encryption if it is necessary to encrypt the command
33
+ # being executed (optional).
31
34
  #
32
35
  # @return [ Mongo::Operation::Result ] The operation result.
33
36
  #
34
37
  # @since 2.5.2
35
- def execute(server)
38
+ def execute(server, client:)
36
39
  validate!
37
- result = if server.features.op_msg_enabled?
38
- self.class::OpMsg.new(spec).execute(server)
40
+ op = if server.features.op_msg_enabled?
41
+ self.class::OpMsg.new(spec)
39
42
  elsif !acknowledged_write?
40
- self.class::Legacy.new(spec).execute(server)
43
+ self.class::Legacy.new(spec)
41
44
  else
42
- self.class::Command.new(spec).execute(server)
45
+ self.class::Command.new(spec)
43
46
  end
47
+ result = op.execute(server, client: client)
44
48
  validate_result(result, server)
45
49
  end
46
50
 
47
51
  # Execute the bulk write operation.
48
52
  #
49
53
  # @example
50
- # operation.bulk_execute(server)
54
+ # operation.bulk_execute(server, client: nil)
51
55
  #
52
56
  # @param [ Mongo::Server ] server The server to send the operation to.
57
+ # @param [ Mongo::Client ] client The client that will be used to
58
+ # perform auto-encryption if it is necessary to encrypt the command
59
+ # being executed (optional).
53
60
  #
54
61
  # @return [ Mongo::Operation::Delete::BulkResult,
55
62
  # Mongo::Operation::Insert::BulkResult,
56
63
  # Mongo::Operation::Update::BulkResult ] The bulk result.
57
64
  #
58
65
  # @since 2.5.2
59
- def bulk_execute(server)
66
+ def bulk_execute(server, client:)
60
67
  if server.features.op_msg_enabled?
61
- self.class::OpMsg.new(spec).execute(server).bulk_result
68
+ self.class::OpMsg.new(spec).execute(server, client: client).bulk_result
62
69
  else
63
- self.class::Command.new(spec).execute(server).bulk_result
70
+ self.class::Command.new(spec).execute(server, client: client).bulk_result
64
71
  end
65
72
  end
66
73
 
@@ -36,7 +36,7 @@ module Mongo
36
36
  end
37
37
 
38
38
  def message(server)
39
- section = { type: 1, payload: { identifier: IDENTIFIER, sequence: send(IDENTIFIER) } }
39
+ section = Protocol::Msg::Section1.new(IDENTIFIER, send(IDENTIFIER))
40
40
  Protocol::Msg.new(flags, {}, command(server), section)
41
41
  end
42
42
  end
@@ -47,9 +47,10 @@ module Mongo
47
47
  # Deserializes vector by decoding the symbol according to its mask
48
48
  #
49
49
  # @param [ String ] buffer Buffer containing the vector to be deserialized.
50
+ # @param [ Hash ] options This method does not currently accept any options.
50
51
  #
51
52
  # @return [ Array<Symbol> ] Flags contained in the vector
52
- def deserialize(buffer)
53
+ def deserialize(buffer, options = {})
53
54
  vector = buffer.get_int32
54
55
  flags = []
55
56
  @masks.each do |flag, mask|
@@ -60,15 +60,13 @@ module Mongo
60
60
  @request_id = message.request_id
61
61
  end
62
62
 
63
- # Inflate an OP_COMRESSED message and return the original message.
64
- #
65
- # @example Inflate a compressed message.
66
- # message.inflate!
63
+ # Inflates an OP_COMRESSED message and returns the original message.
67
64
  #
68
65
  # @return [ Protocol::Message ] The inflated message.
69
66
  #
70
67
  # @since 2.5.0
71
- def inflate!
68
+ # @api private
69
+ def maybe_inflate
72
70
  message = Registry.get(@original_op_code).allocate
73
71
  uncompressed_message = Zlib::Inflate.inflate(@compressed_message)
74
72
 
@@ -81,6 +79,9 @@ module Mongo
81
79
  Message.deserialize_field(message, buf, field)
82
80
  end
83
81
  end
82
+ if message.is_a?(Msg)
83
+ message.fix_after_deserialization
84
+ end
84
85
  message
85
86
  end
86
87
 
@@ -46,8 +46,10 @@ module Mongo
46
46
  # @param options [Hash] Additional options for the insertion.
47
47
  #
48
48
  # @option options :flags [Array] The flags for the insertion message.
49
- #
50
49
  # Supported flags: +:continue_on_error+
50
+ # @option options [ true, false ] validating_keys Whether keys should be
51
+ # validated for being valid document keys (i.e. not begin with $ and
52
+ # not contain dots).
51
53
  def initialize(database, collection, documents, options = {})
52
54
  @database = database
53
55
  @namespace = "#{database}.#{collection}"
@@ -95,27 +95,84 @@ module Mongo
95
95
  false
96
96
  end
97
97
 
98
- # Compress a message.
98
+ # Compress the message, if supported by the wire protocol used and if
99
+ # the command being sent permits compression. Otherwise returns self.
99
100
  #
100
101
  # @param [ String, Symbol ] compressor The compressor to use.
101
102
  # @param [ Integer ] zlib_compression_level The zlib compression level to use.
102
103
  #
103
- # @return [ self ] Always returns self. Other message types should override this method.
104
+ # @return [ self ] Always returns self. Other message types should
105
+ # override this method.
104
106
  #
105
107
  # @since 2.5.0
106
- def compress!(compressor, zlib_compression_level = nil)
108
+ # @api private
109
+ def maybe_compress(compressor, zlib_compression_level = nil)
107
110
  self
108
111
  end
109
112
 
110
- # Inflate a message.
113
+ # Compress the message, if the command being sent permits compression.
114
+ # Otherwise returns self.
111
115
  #
112
- # @return [ self ] Always returns self. Other message types should override this method.
116
+ # @param [ String ] command_name Command name extracted from the message.
117
+ # @param [ String | Symbol ] compressor The compressor to use.
118
+ # @param [ Integer ] zlib_compression_level Zlib compression level to use.
119
+ #
120
+ # @return [ Message ] A Protocol::Compressed message or self,
121
+ # depending on whether this message can be compressed.
122
+ #
123
+ # @since 2.5.0
124
+ private def compress_if_possible(command_name, compressor, zlib_compression_level)
125
+ if compressor && compression_allowed?(command_name)
126
+ Compressed.new(self, compressor, zlib_compression_level)
127
+ else
128
+ self
129
+ end
130
+ end
131
+
132
+ # Inflate a message if it is compressed.
133
+ #
134
+ # @return [ Protocol::Message ] Always returns self. Subclasses should
135
+ # override this method as necessary.
113
136
  #
114
137
  # @since 2.5.0
115
- def inflate!
138
+ # @api private
139
+ def maybe_inflate
140
+ self
141
+ end
142
+
143
+ def maybe_decrypt(client)
144
+ # TODO determine if we should be decrypting data coming from pre-4.2
145
+ # servers, potentially using legacy wire protocols. If so we need
146
+ # to implement decryption for those wire protocols as our current
147
+ # encryption/decryption code is OP_MSG-specific.
148
+ self
149
+ end
150
+
151
+ def maybe_encrypt(server, client)
152
+ # Do nothing if the Message subclass has not implemented this method
116
153
  self
117
154
  end
118
155
 
156
+ private def merge_sections
157
+ cmd = if @sections.length > 1
158
+ cmd = @sections.detect { |section| section[:type] == 0 }[:payload]
159
+ identifier = @sections.detect { |section| section[:type] == 1}[:payload][:identifier]
160
+ cmd.merge(identifier.to_sym =>
161
+ @sections.select { |section| section[:type] == 1 }.
162
+ map { |section| section[:payload][:sequence] }.
163
+ inject([]) { |arr, documents| arr + documents }
164
+ )
165
+ elsif @sections.first[:payload]
166
+ @sections.first[:payload]
167
+ else
168
+ @sections.first
169
+ end
170
+ if cmd.nil?
171
+ raise "The command should never be nil here"
172
+ end
173
+ cmd
174
+ end
175
+
119
176
  # Serializes message into bytes that can be sent on the wire
120
177
  #
121
178
  # @param buffer [String] buffer where the message should be inserted
@@ -129,13 +186,22 @@ module Mongo
129
186
 
130
187
  alias_method :to_s, :serialize
131
188
 
132
- # Deserializes messages from an IO stream
189
+ # Deserializes messages from an IO stream.
190
+ #
191
+ # This method returns decompressed messages (i.e. if the message on the
192
+ # wire was OP_COMPRESSED, this method would typically return the OP_MSG
193
+ # message that is the result of decompression).
133
194
  #
134
195
  # @param [ Integer ] max_message_size The max message size.
135
196
  # @param [ IO ] io Stream containing a message
197
+ # @param [ Hash ] options
198
+ #
199
+ # @option options [ Boolean ] :deserialize_as_bson Whether to deserialize
200
+ # this message using BSON types instead of native Ruby types wherever
201
+ # possible.
136
202
  #
137
203
  # @return [ Message ] Instance of a Message class
138
- def self.deserialize(io, max_message_size = MAX_MESSAGE_SIZE, expected_response_to = nil)
204
+ def self.deserialize(io, max_message_size = MAX_MESSAGE_SIZE, expected_response_to = nil, options = {})
139
205
  length, _request_id, response_to, _op_code = deserialize_header(BSON::ByteBuffer.new(io.read(16)))
140
206
 
141
207
  # Protection from potential DOS man-in-the-middle attacks. See
@@ -155,12 +221,15 @@ module Mongo
155
221
 
156
222
  message.send(:fields).each do |field|
157
223
  if field[:multi]
158
- deserialize_array(message, buffer, field)
224
+ deserialize_array(message, buffer, field, options)
159
225
  else
160
- deserialize_field(message, buffer, field)
226
+ deserialize_field(message, buffer, field, options)
161
227
  end
162
228
  end
163
- message.inflate!
229
+ if message.is_a?(Msg)
230
+ message.fix_after_deserialization
231
+ end
232
+ message.maybe_inflate
164
233
  end
165
234
 
166
235
  # Tests for equality between two wire protocol messages
@@ -299,11 +368,16 @@ module Mongo
299
368
  # @param message [Message] Message to contain the deserialized array.
300
369
  # @param io [IO] Stream containing the array to deserialize.
301
370
  # @param field [Hash] Hash representing a field.
371
+ # @param options [ Hash ]
372
+ #
373
+ # @option options [ Boolean ] :deserialize_as_bson Whether to deserialize
374
+ # each of the elements in this array using BSON types wherever possible.
375
+ #
302
376
  # @return [Message] Message with deserialized array.
303
- def self.deserialize_array(message, io, field)
377
+ def self.deserialize_array(message, io, field, options = {})
304
378
  elements = []
305
379
  count = message.instance_variable_get(field[:multi])
306
- count.times { elements << field[:type].deserialize(io) }
380
+ count.times { elements << field[:type].deserialize(io, options) }
307
381
  message.instance_variable_set(field[:name], elements)
308
382
  end
309
383
 
@@ -312,11 +386,16 @@ module Mongo
312
386
  # @param message [Message] Message to contain the deserialized field.
313
387
  # @param io [IO] Stream containing the field to deserialize.
314
388
  # @param field [Hash] Hash representing a field.
389
+ # @param options [ Hash ]
390
+ #
391
+ # @option options [ Boolean ] :deserialize_as_bson Whether to deserialize
392
+ # this field using BSON types wherever possible.
393
+ #
315
394
  # @return [Message] Message with deserialized field.
316
- def self.deserialize_field(message, io, field)
395
+ def self.deserialize_field(message, io, field, options = {})
317
396
  message.instance_variable_set(
318
397
  field[:name],
319
- field[:type].deserialize(io)
398
+ field[:type].deserialize(io, options)
320
399
  )
321
400
  end
322
401