mongo 2.11.6 → 2.12.0.rc0

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 (327) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -2
  3. data.tar.gz.sig +0 -0
  4. data/CONTRIBUTING.md +1 -1
  5. data/lib/mongo.rb +3 -0
  6. data/lib/mongo/address.rb +13 -2
  7. data/lib/mongo/auth.rb +1 -0
  8. data/lib/mongo/auth/credential_cache.rb +51 -0
  9. data/lib/mongo/auth/scram/conversation.rb +20 -16
  10. data/lib/mongo/auth/user.rb +0 -8
  11. data/lib/mongo/auth/user/view.rb +4 -4
  12. data/lib/mongo/background_thread.rb +1 -1
  13. data/lib/mongo/bulk_write.rb +5 -5
  14. data/lib/mongo/client.rb +126 -11
  15. data/lib/mongo/client_encryption.rb +103 -0
  16. data/lib/mongo/cluster.rb +2 -2
  17. data/lib/mongo/cluster/reapers/cursor_reaper.rb +18 -6
  18. data/lib/mongo/cluster/sdam_flow.rb +54 -58
  19. data/lib/mongo/cluster/srv_monitor.rb +1 -1
  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 +7 -9
  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 +42 -0
  30. data/lib/mongo/crypt/auto_encrypter.rb +169 -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 +1162 -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 +283 -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 +293 -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 +13 -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/crypt_error.rb +31 -0
  50. data/lib/mongo/error/{failed_stringprep_validation.rb → failed_string_prep_validation.rb} +0 -0
  51. data/lib/mongo/error/invalid_cursor_operation.rb +27 -0
  52. data/lib/mongo/error/kms_error.rb +22 -0
  53. data/lib/mongo/error/max_bson_size.rb +14 -3
  54. data/lib/mongo/error/mongocryptd_spawn_error.rb +22 -0
  55. data/lib/mongo/error/no_server_available.rb +8 -3
  56. data/lib/mongo/error/operation_failure.rb +1 -0
  57. data/lib/mongo/grid/file.rb +0 -5
  58. data/lib/mongo/grid/file/chunk.rb +0 -2
  59. data/lib/mongo/grid/file/info.rb +2 -1
  60. data/lib/mongo/grid/fs_bucket.rb +13 -15
  61. data/lib/mongo/grid/stream/write.rb +3 -9
  62. data/lib/mongo/index/view.rb +3 -3
  63. data/lib/mongo/monitoring/event/command_started.rb +6 -1
  64. data/lib/mongo/operation/collections_info.rb +6 -3
  65. data/lib/mongo/operation/delete/op_msg.rb +1 -1
  66. data/lib/mongo/operation/find/op_msg.rb +4 -1
  67. data/lib/mongo/operation/get_more/op_msg.rb +4 -1
  68. data/lib/mongo/operation/insert/command.rb +2 -2
  69. data/lib/mongo/operation/insert/legacy.rb +2 -2
  70. data/lib/mongo/operation/insert/op_msg.rb +3 -3
  71. data/lib/mongo/operation/result.rb +36 -27
  72. data/lib/mongo/operation/shared/executable.rb +10 -8
  73. data/lib/mongo/operation/shared/executable_no_validate.rb +2 -2
  74. data/lib/mongo/operation/shared/op_msg_or_command.rb +2 -2
  75. data/lib/mongo/operation/shared/op_msg_or_find_command.rb +2 -2
  76. data/lib/mongo/operation/shared/op_msg_or_list_indexes_command.rb +2 -2
  77. data/lib/mongo/operation/shared/write.rb +17 -10
  78. data/lib/mongo/operation/update/op_msg.rb +1 -1
  79. data/lib/mongo/protocol/compressed.rb +6 -5
  80. data/lib/mongo/protocol/insert.rb +3 -1
  81. data/lib/mongo/protocol/message.rb +72 -8
  82. data/lib/mongo/protocol/msg.rb +191 -37
  83. data/lib/mongo/protocol/query.rb +7 -9
  84. data/lib/mongo/protocol/serializers.rb +6 -2
  85. data/lib/mongo/server.rb +10 -4
  86. data/lib/mongo/server/connection.rb +20 -9
  87. data/lib/mongo/server/connection_base.rb +81 -12
  88. data/lib/mongo/server/connection_common.rb +61 -0
  89. data/lib/mongo/server/connection_pool.rb +37 -1
  90. data/lib/mongo/server/description.rb +9 -11
  91. data/lib/mongo/server/monitor.rb +2 -0
  92. data/lib/mongo/server/monitor/connection.rb +3 -18
  93. data/lib/mongo/server/pending_connection.rb +2 -1
  94. data/lib/mongo/session.rb +2 -2
  95. data/lib/mongo/session/session_pool.rb +8 -3
  96. data/lib/mongo/socket.rb +29 -16
  97. data/lib/mongo/socket/ssl.rb +23 -8
  98. data/lib/mongo/socket/tcp.rb +12 -3
  99. data/lib/mongo/timeout.rb +49 -0
  100. data/lib/mongo/uri.rb +30 -1
  101. data/lib/mongo/version.rb +1 -1
  102. data/mongo.gemspec +1 -1
  103. data/spec/README.md +134 -7
  104. data/spec/integration/auth_spec.rb +53 -0
  105. data/spec/integration/{client_options_spec.rb → client_authentication_options_spec.rb} +10 -10
  106. data/spec/integration/client_construction_spec.rb +76 -1
  107. data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +351 -0
  108. data/spec/integration/client_side_encryption/auto_encryption_command_monitoring_spec.rb +301 -0
  109. data/spec/integration/client_side_encryption/auto_encryption_mongocryptd_spawn_spec.rb +71 -0
  110. data/spec/integration/client_side_encryption/auto_encryption_old_wire_version_spec.rb +76 -0
  111. data/spec/integration/client_side_encryption/auto_encryption_reconnect_spec.rb +216 -0
  112. data/spec/integration/client_side_encryption/auto_encryption_spec.rb +600 -0
  113. data/spec/integration/client_side_encryption/bson_size_limit_spec.rb +183 -0
  114. data/spec/integration/client_side_encryption/bypass_mongocryptd_spawn_spec.rb +74 -0
  115. data/spec/integration/client_side_encryption/client_close_spec.rb +59 -0
  116. data/spec/integration/client_side_encryption/corpus_spec.rb +228 -0
  117. data/spec/integration/client_side_encryption/custom_endpoint_spec.rb +132 -0
  118. data/spec/integration/client_side_encryption/data_key_spec.rb +163 -0
  119. data/spec/integration/client_side_encryption/explicit_encryption_spec.rb +114 -0
  120. data/spec/integration/client_side_encryption/external_key_vault_spec.rb +137 -0
  121. data/spec/integration/client_side_encryption/views_spec.rb +42 -0
  122. data/spec/integration/client_update_spec.rb +120 -0
  123. data/spec/integration/command_monitoring_spec.rb +3 -1
  124. data/spec/integration/command_spec.rb +44 -10
  125. data/spec/integration/connection_spec.rb +57 -0
  126. data/spec/integration/reconnect_spec.rb +7 -6
  127. data/spec/integration/size_limit_spec.rb +94 -0
  128. data/spec/integration/srv_monitoring_spec.rb +14 -6
  129. data/spec/lite_spec_helper.rb +31 -22
  130. data/spec/mongo/auth/cr_spec.rb +8 -0
  131. data/spec/mongo/auth/ldap_spec.rb +5 -1
  132. data/spec/mongo/auth/scram/conversation_spec.rb +5 -6
  133. data/spec/mongo/auth/scram/negotiation_spec.rb +74 -75
  134. data/spec/mongo/auth/scram_spec.rb +45 -35
  135. data/spec/mongo/auth/x509_spec.rb +5 -1
  136. data/spec/mongo/client_construction_spec.rb +206 -3
  137. data/spec/mongo/client_encryption_spec.rb +408 -0
  138. data/spec/mongo/cluster/cursor_reaper_spec.rb +12 -8
  139. data/spec/mongo/cluster/socket_reaper_spec.rb +14 -3
  140. data/spec/mongo/collection/view/aggregation_spec.rb +0 -2
  141. data/spec/mongo/collection/view/change_stream_spec.rb +7 -7
  142. data/spec/mongo/collection/view/map_reduce_spec.rb +3 -3
  143. data/spec/mongo/collection/view_spec.rb +1 -1
  144. data/spec/mongo/collection_spec.rb +4 -33
  145. data/spec/mongo/crypt/auto_decryption_context_spec.rb +90 -0
  146. data/spec/mongo/crypt/auto_encrypter_spec.rb +182 -0
  147. data/spec/mongo/crypt/auto_encryption_context_spec.rb +107 -0
  148. data/spec/mongo/crypt/binary_spec.rb +115 -0
  149. data/spec/mongo/crypt/binding/binary_spec.rb +56 -0
  150. data/spec/mongo/crypt/binding/context_spec.rb +257 -0
  151. data/spec/mongo/crypt/binding/helpers_spec.rb +46 -0
  152. data/spec/mongo/crypt/binding/mongocrypt_spec.rb +144 -0
  153. data/spec/mongo/crypt/binding/status_spec.rb +99 -0
  154. data/spec/mongo/crypt/binding/version_spec.rb +22 -0
  155. data/spec/mongo/crypt/binding_unloaded_spec.rb +20 -0
  156. data/spec/mongo/crypt/data_key_context_spec.rb +213 -0
  157. data/spec/mongo/crypt/encryption_io_spec.rb +136 -0
  158. data/spec/mongo/crypt/explicit_decryption_context_spec.rb +72 -0
  159. data/spec/mongo/crypt/explicit_encryption_context_spec.rb +170 -0
  160. data/spec/mongo/crypt/handle_spec.rb +198 -0
  161. data/spec/mongo/crypt/helpers/mongo_crypt_spec_helper.rb +108 -0
  162. data/spec/mongo/crypt/status_spec.rb +152 -0
  163. data/spec/mongo/cursor_spec.rb +24 -4
  164. data/spec/mongo/database_spec.rb +20 -0
  165. data/spec/mongo/error/crypt_error_spec.rb +26 -0
  166. data/spec/mongo/error/max_bson_size_spec.rb +35 -0
  167. data/spec/mongo/error/no_server_available_spec.rb +11 -1
  168. data/spec/mongo/error/operation_failure_spec.rb +6 -6
  169. data/spec/mongo/operation/aggregate_spec.rb +1 -1
  170. data/spec/mongo/operation/collections_info_spec.rb +1 -1
  171. data/spec/mongo/operation/command_spec.rb +3 -3
  172. data/spec/mongo/operation/create_index_spec.rb +3 -3
  173. data/spec/mongo/operation/create_user_spec.rb +3 -3
  174. data/spec/mongo/operation/delete/bulk_spec.rb +6 -6
  175. data/spec/mongo/operation/delete/op_msg_spec.rb +1 -6
  176. data/spec/mongo/operation/delete_spec.rb +7 -7
  177. data/spec/mongo/operation/drop_index_spec.rb +2 -2
  178. data/spec/mongo/operation/find/legacy_spec.rb +1 -1
  179. data/spec/mongo/operation/get_more_spec.rb +1 -1
  180. data/spec/mongo/operation/indexes_spec.rb +1 -1
  181. data/spec/mongo/operation/insert/bulk_spec.rb +7 -7
  182. data/spec/mongo/operation/insert/op_msg_spec.rb +3 -6
  183. data/spec/mongo/operation/insert_spec.rb +12 -12
  184. data/spec/mongo/operation/map_reduce_spec.rb +2 -2
  185. data/spec/mongo/operation/remove_user_spec.rb +3 -3
  186. data/spec/mongo/operation/update/bulk_spec.rb +6 -6
  187. data/spec/mongo/operation/update/op_msg_spec.rb +3 -6
  188. data/spec/mongo/operation/update_spec.rb +7 -7
  189. data/spec/mongo/operation/update_user_spec.rb +1 -1
  190. data/spec/mongo/protocol/compressed_spec.rb +2 -3
  191. data/spec/mongo/protocol/delete_spec.rb +9 -8
  192. data/spec/mongo/protocol/get_more_spec.rb +9 -8
  193. data/spec/mongo/protocol/insert_spec.rb +9 -8
  194. data/spec/mongo/protocol/kill_cursors_spec.rb +6 -5
  195. data/spec/mongo/protocol/msg_spec.rb +57 -53
  196. data/spec/mongo/protocol/query_spec.rb +12 -12
  197. data/spec/mongo/protocol/registry_spec.rb +1 -1
  198. data/spec/mongo/protocol/reply_spec.rb +1 -1
  199. data/spec/mongo/protocol/update_spec.rb +10 -9
  200. data/spec/mongo/server/connection_pool_spec.rb +1 -1
  201. data/spec/mongo/server/connection_spec.rb +28 -7
  202. data/spec/mongo/socket_spec.rb +1 -1
  203. data/spec/mongo/timeout_spec.rb +85 -0
  204. data/spec/mongo/uri/srv_protocol_spec.rb +2 -2
  205. data/spec/mongo/uri_spec.rb +52 -5
  206. data/spec/mongo/write_concern_spec.rb +13 -1
  207. data/spec/{support → runners}/auth.rb +14 -1
  208. data/spec/{support → runners}/change_streams.rb +1 -1
  209. data/spec/{support → runners}/change_streams/operation.rb +0 -0
  210. data/spec/{support → runners}/cmap.rb +1 -1
  211. data/spec/{support → runners}/cmap/verifier.rb +0 -0
  212. data/spec/{support → runners}/command_monitoring.rb +0 -0
  213. data/spec/runners/connection_string.rb +358 -4
  214. data/spec/{support → runners}/crud.rb +9 -9
  215. data/spec/{support → runners}/crud/context.rb +0 -0
  216. data/spec/{support → runners}/crud/operation.rb +7 -3
  217. data/spec/{support → runners}/crud/outcome.rb +0 -0
  218. data/spec/{support → runners}/crud/requirement.rb +1 -1
  219. data/spec/{support → runners}/crud/spec.rb +12 -1
  220. data/spec/{support → runners}/crud/test.rb +0 -0
  221. data/spec/{support → runners}/crud/test_base.rb +0 -0
  222. data/spec/{support → runners}/crud/verifier.rb +10 -12
  223. data/spec/{support → runners}/gridfs.rb +0 -0
  224. data/spec/{support → runners}/sdam_monitoring.rb +0 -0
  225. data/spec/{support → runners}/server_discovery_and_monitoring.rb +0 -0
  226. data/spec/{support → runners}/server_selection.rb +0 -0
  227. data/spec/{support → runners}/server_selection_rtt.rb +0 -0
  228. data/spec/{support → runners}/transactions.rb +4 -4
  229. data/spec/{support → runners}/transactions/context.rb +0 -0
  230. data/spec/{support → runners}/transactions/operation.rb +0 -0
  231. data/spec/{support → runners}/transactions/spec.rb +0 -0
  232. data/spec/{support → runners}/transactions/test.rb +37 -5
  233. data/spec/spec_helper.rb +0 -5
  234. data/spec/spec_tests/auth_spec.rb +3 -3
  235. data/spec/spec_tests/client_side_encryption_spec.rb +13 -0
  236. data/spec/spec_tests/connection_string_spec.rb +1 -1
  237. data/spec/spec_tests/data/auth/connection-string.yml +13 -0
  238. data/spec/spec_tests/data/client_side_encryption/aggregate.yml +134 -0
  239. data/spec/spec_tests/data/client_side_encryption/badQueries.yml +526 -0
  240. data/spec/spec_tests/data/client_side_encryption/badSchema.yml +73 -0
  241. data/spec/spec_tests/data/client_side_encryption/basic.yml +116 -0
  242. data/spec/spec_tests/data/client_side_encryption/bulk.yml +85 -0
  243. data/spec/spec_tests/data/client_side_encryption/bypassAutoEncryption.yml +100 -0
  244. data/spec/spec_tests/data/client_side_encryption/bypassedCommand.yml +42 -0
  245. data/spec/spec_tests/data/client_side_encryption/count.yml +61 -0
  246. data/spec/spec_tests/data/client_side_encryption/countDocuments.yml +59 -0
  247. data/spec/spec_tests/data/client_side_encryption/delete.yml +105 -0
  248. data/spec/spec_tests/data/client_side_encryption/distinct.yml +73 -0
  249. data/spec/spec_tests/data/client_side_encryption/explain.yml +64 -0
  250. data/spec/spec_tests/data/client_side_encryption/find.yml +119 -0
  251. data/spec/spec_tests/data/client_side_encryption/findOneAndDelete.yml +57 -0
  252. data/spec/spec_tests/data/client_side_encryption/findOneAndReplace.yml +57 -0
  253. data/spec/spec_tests/data/client_side_encryption/findOneAndUpdate.yml +57 -0
  254. data/spec/spec_tests/data/client_side_encryption/getMore.yml +68 -0
  255. data/spec/spec_tests/data/client_side_encryption/insert.yml +102 -0
  256. data/spec/spec_tests/data/client_side_encryption/keyAltName.yml +71 -0
  257. data/spec/spec_tests/data/client_side_encryption/localKMS.yml +54 -0
  258. data/spec/spec_tests/data/client_side_encryption/localSchema.yml +72 -0
  259. data/spec/spec_tests/data/client_side_encryption/malformedCiphertext.yml +69 -0
  260. data/spec/spec_tests/data/client_side_encryption/maxWireVersion.yml +20 -0
  261. data/spec/spec_tests/data/client_side_encryption/missingKey.yml +49 -0
  262. data/spec/spec_tests/data/client_side_encryption/replaceOne.yml +61 -0
  263. data/spec/spec_tests/data/client_side_encryption/types.yml +527 -0
  264. data/spec/spec_tests/data/client_side_encryption/unsupportedCommand.yml +25 -0
  265. data/spec/spec_tests/data/client_side_encryption/updateMany.yml +77 -0
  266. data/spec/spec_tests/data/client_side_encryption/updateOne.yml +168 -0
  267. data/spec/spec_tests/data/read_write_concern/connection-string/write-concern.yml +1 -4
  268. data/spec/spec_tests/data/retryable_writes/insertOne-serverErrors.yml +21 -0
  269. data/spec/spec_tests/data/sdam/rs/incompatible_ghost.yml +2 -4
  270. data/spec/spec_tests/data/sdam/rs/incompatible_other.yml +1 -1
  271. data/spec/spec_tests/data/sdam/rs/primary_mismatched_me_not_removed.yml +73 -0
  272. data/spec/spec_tests/data/sdam/rs/primary_to_no_primary_mismatched_me.yml +1 -2
  273. data/spec/spec_tests/data/sdam/rs/repeated.yml +101 -0
  274. data/spec/spec_tests/data/sdam/rs/{primary_address_change.yml → ruby_primary_address_change.yml} +2 -0
  275. 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
  276. data/spec/spec_tests/data/sdam/sharded/ruby_discovered_single_mongos.yml +27 -0
  277. data/spec/spec_tests/data/sdam/sharded/{primary_address_change.yml → ruby_primary_different_address.yml} +1 -1
  278. data/spec/spec_tests/data/sdam/sharded/{primary_mismatched_me.yml → ruby_primary_mismatched_me.yml} +1 -1
  279. data/spec/spec_tests/data/sdam/single/{primary_address_change.yml → ruby_primary_different_address.yml} +1 -1
  280. data/spec/spec_tests/data/sdam/single/{primary_mismatched_me.yml → ruby_primary_mismatched_me.yml} +1 -1
  281. data/spec/spec_tests/data/sdam_monitoring/{replica_set_with_primary_change.yml → replica_set_primary_address_change.yml} +27 -5
  282. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_me_mismatch.yml +26 -74
  283. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_removal.yml +20 -16
  284. data/spec/spec_tests/data/sdam_monitoring/standalone_suppress_equal_description_changes.yml +73 -0
  285. data/spec/spec_tests/data/transactions/pin-mongos.yml +2 -3
  286. data/spec/spec_tests/data/uri_options/auth-options.yml +10 -0
  287. data/spec/spec_tests/data/uri_options/tls-options.yml +75 -4
  288. data/spec/spec_tests/read_write_concern_connection_string_spec.rb +1 -1
  289. data/spec/spec_tests/uri_options_spec.rb +6 -8
  290. data/spec/stress/connection_pool_timing_spec.rb +6 -3
  291. data/spec/support/certificates/README.md +4 -0
  292. data/spec/support/certificates/server-second-level-bundle.pem +77 -77
  293. data/spec/support/certificates/server-second-level.crt +52 -52
  294. data/spec/support/certificates/server-second-level.key +25 -25
  295. data/spec/support/certificates/server-second-level.pem +77 -77
  296. data/spec/support/client_registry.rb +19 -3
  297. data/spec/support/cluster_config.rb +9 -1
  298. data/spec/support/common_shortcuts.rb +12 -0
  299. data/spec/support/constraints.rb +16 -0
  300. data/spec/support/crypt.rb +140 -0
  301. data/spec/support/crypt/corpus/corpus-key-aws.json +33 -0
  302. data/spec/support/crypt/corpus/corpus-key-local.json +31 -0
  303. data/spec/support/crypt/corpus/corpus-schema.json +2057 -0
  304. data/spec/support/crypt/corpus/corpus.json +3657 -0
  305. data/spec/support/crypt/corpus/corpus_encrypted.json +4152 -0
  306. data/spec/support/crypt/data_keys/key_document_aws.json +34 -0
  307. data/spec/support/crypt/data_keys/key_document_local.json +31 -0
  308. data/spec/support/crypt/external/external-key.json +31 -0
  309. data/spec/support/crypt/external/external-schema.json +19 -0
  310. data/spec/support/crypt/limits/limits-doc.json +102 -0
  311. data/spec/support/crypt/limits/limits-key.json +31 -0
  312. data/spec/support/crypt/limits/limits-schema.json +1405 -0
  313. data/spec/support/crypt/schema_maps/schema_map_aws.json +17 -0
  314. data/spec/support/crypt/schema_maps/schema_map_aws_key_alt_names.json +12 -0
  315. data/spec/support/crypt/schema_maps/schema_map_local.json +18 -0
  316. data/spec/support/crypt/schema_maps/schema_map_local_key_alt_names.json +12 -0
  317. data/spec/support/lite_constraints.rb +17 -1
  318. data/spec/support/matchers.rb +19 -0
  319. data/spec/support/shared/protocol.rb +2 -0
  320. data/spec/support/spec_config.rb +43 -13
  321. data/spec/support/utils.rb +132 -10
  322. metadata +277 -81
  323. metadata.gz.sig +0 -0
  324. data/spec/integration/grid_fs_bucket_spec.rb +0 -48
  325. data/spec/integration/zlib_compression_spec.rb +0 -25
  326. data/spec/spec_tests/data/sdam/sharded/single_mongos.yml +0 -33
  327. data/spec/support/connection_string.rb +0 -354
@@ -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.
116
148
  self
117
149
  end
118
150
 
151
+ def maybe_encrypt(server, client)
152
+ # Do nothing if the Message subclass has not implemented this method
153
+ self
154
+ end
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,7 +186,11 @@ 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
@@ -160,7 +221,10 @@ module Mongo
160
221
  deserialize_field(message, buffer, field)
161
222
  end
162
223
  end
163
- message.inflate!
224
+ if message.is_a?(Msg)
225
+ message.fix_after_deserialization
226
+ end
227
+ message.maybe_inflate
164
228
  end
165
229
 
166
230
  # Tests for equality between two wire protocol messages
@@ -35,7 +35,7 @@ module Mongo
35
35
  # moved to the end of the hash for better logging.
36
36
  #
37
37
  # @api private
38
- INTERNAL_KEYS = Set.new(%w($clusterTime lsid signature txnNumber)).freeze
38
+ INTERNAL_KEYS = Set.new(%w($clusterTime $db lsid signature txnNumber)).freeze
39
39
 
40
40
  # Creates a new OP_MSG protocol message
41
41
  #
@@ -44,25 +44,42 @@ module Mongo
44
44
  # { type: 1, payload: { identifier: 'documents', sequence: [..] } })
45
45
  #
46
46
  # @param [ Array<Symbol> ] flags The flag bits. Current supported values
47
- # are :more_to_come and :checksum_present.
48
- # @param [ Hash ] options The options. There are currently no supported
49
- # options, this is a placeholder for the future.
50
- # @param [ BSON::Document, Hash ] global_args The global arguments,
51
- # becomes a section of payload type 0.
52
- # @param [ BSON::Document, Hash ] sections Zero or more sections, in the format
53
- # { type: 1, payload: { identifier: <String>, sequence: <Array<BSON::Document, Hash>> } } or
54
- # { type: 0, payload: <BSON::Document, Hash> }
47
+ # are :more_to_come and :checksum_present.
48
+ # @param [ Hash ] options The options.
49
+ # @param [ BSON::Document, Hash ] main_document The document that will
50
+ # become the payload type 0 section. Can contain global args as they
51
+ # are defined in the OP_MSG specification.
52
+ # @param [ Protocol::Msg::Section1 ] sequences Zero or more payload type 1
53
+ # sections.
55
54
  #
56
- # @option options [ true, false ] validating_keys Whether keys should be validated.
55
+ # @option options [ true, false ] validating_keys Whether keys should be
56
+ # validated for being valid document keys (i.e. not begin with $ and
57
+ # not contain dots).
57
58
  #
58
59
  # @api private
59
60
  #
60
61
  # @since 2.5.0
61
- def initialize(flags, options, global_args, *sections)
62
+ def initialize(flags, options, main_document, *sequences)
62
63
  @flags = flags || []
63
64
  @options = options
64
- @global_args = global_args
65
- @sections = [ { type: 0, payload: global_args } ] + sections
65
+ unless main_document.is_a?(Hash)
66
+ raise ArgumentError, "Main document must be a Hash, given: #{main_document.class}"
67
+ end
68
+ @main_document = main_document
69
+ sequences.each_with_index do |section, index|
70
+ unless section.is_a?(Section1)
71
+ raise ArgumentError, "All sequences must be Section1 instances, got: #{section} at index #{index}"
72
+ end
73
+ end
74
+ @sequences = sequences
75
+ @sections = [
76
+ {type: 0, payload: @main_document}
77
+ ] + @sequences.map do |section|
78
+ {type: 1, payload: {
79
+ identifier: section.identifier,
80
+ sequence: section.documents,
81
+ }}
82
+ end
66
83
  @request_id = nil
67
84
  super
68
85
  end
@@ -88,11 +105,11 @@ module Mongo
88
105
  #
89
106
  # @since 2.5.0
90
107
  def payload
91
- # Reorder keys in global_args for better logging - see
108
+ # Reorder keys in main_document for better logging - see
92
109
  # https://jira.mongodb.org/browse/RUBY-1591.
93
110
  # Note that even without the reordering, the payload is not an exact
94
111
  # match to what is sent over the wire because the command as used in
95
- # the published eent combines keys from multiple sections of the
112
+ # the published event combines keys from multiple sections of the
96
113
  # payload sent over the wire.
97
114
  ordered_command = {}
98
115
  skipped_command = {}
@@ -107,10 +124,10 @@ module Mongo
107
124
 
108
125
  BSON::Document.new(
109
126
  command_name: ordered_command.keys.first.to_s,
110
- database_name: global_args[DATABASE_IDENTIFIER],
127
+ database_name: @main_document[DATABASE_IDENTIFIER],
111
128
  command: ordered_command,
112
129
  request_id: request_id,
113
- reply: sections[0]
130
+ reply: @main_document,
114
131
  )
115
132
  end
116
133
 
@@ -128,35 +145,142 @@ module Mongo
128
145
  buffer
129
146
  end
130
147
 
131
- # Compress this message.
148
+ # Compress the message, if the command being sent permits compression.
149
+ # Otherwise returns self.
132
150
  #
133
151
  # @param [ String, Symbol ] compressor The compressor to use.
134
152
  # @param [ Integer ] zlib_compression_level The zlib compression level to use.
135
153
  #
136
- # @return [ Compressed, self ] A Protocol::Compressed message or self, depending on whether
137
- # this message can be compressed.
154
+ # @return [ Message ] A Protocol::Compressed message or self,
155
+ # depending on whether this message can be compressed.
138
156
  #
139
157
  # @since 2.5.0
140
- def compress!(compressor, zlib_compression_level = nil)
141
- if compressor && compression_allowed?(command.keys.first)
142
- Compressed.new(self, compressor, zlib_compression_level)
158
+ # @api private
159
+ def maybe_compress(compressor, zlib_compression_level = nil)
160
+ compress_if_possible(command.keys.first, compressor, zlib_compression_level)
161
+ end
162
+
163
+ # Reverse-populates the instance variables after deserialization sets
164
+ # @sections to the list of documents.
165
+ #
166
+ # TODO fix deserialization so that this method is not needed.
167
+ #
168
+ # @api private
169
+ def fix_after_deserialization
170
+ if @sections.nil?
171
+ raise NotImplementedError, "After deserializations @sections should have been initialized"
172
+ end
173
+ if @sections.length != 1
174
+ raise NotImplementedError, "Deserialization must have produced exactly one section, but it produced #{sections.length} sections"
175
+ end
176
+ @main_document = @sections.first
177
+ @sequences = []
178
+ @sections = [{type: 0, payload: @main_document}]
179
+ end
180
+
181
+ def documents
182
+ [@main_document]
183
+ end
184
+
185
+ # Possibly encrypt this message with libmongocrypt. Message will only be
186
+ # encrypted if the specified client exists, that client has been given
187
+ # auto-encryption options, the client has not been instructed to bypass
188
+ # auto-encryption, and mongocryptd determines that this message is
189
+ # eligible for encryption. A message is eligible for encryption if it
190
+ # represents one of the command types whitelisted by libmongocrypt and it
191
+ # contains data that is required to be encrypted by a local or remote json schema.
192
+ #
193
+ # @param [ Mongo::Client | nil ] client The client used to make the original
194
+ # command. This client may have auto-encryption options specified.
195
+ #
196
+ # @return [ Mongo::Protocol::Msg ] The encrypted message, or the original
197
+ # message if encryption was not possible or necessary.
198
+ def maybe_encrypt(server, client)
199
+ # TODO verify compression happens later, i.e. when this method runs
200
+ # the message is not compressed.
201
+ if client && client.encrypter && client.encrypter.encrypt?
202
+ if server.max_wire_version < 8
203
+ raise Error::CryptError.new(
204
+ "Cannot perform encryption against a MongoDB server older than " +
205
+ "4.2 (wire version less than 8). Currently connected to server " +
206
+ "with max wire version #{server.max_wire_version}} " +
207
+ "(Auto-encryption requires a minimum MongoDB version of 4.2)"
208
+ )
209
+ end
210
+
211
+ db_name = @main_document[DATABASE_IDENTIFIER]
212
+ cmd = merge_sections
213
+ enc_cmd = client.encrypter.encrypt(db_name, cmd)
214
+ if cmd.key?('$db') && !enc_cmd.key?('$db')
215
+ enc_cmd['$db'] = cmd['$db']
216
+ end
217
+ # This will be investigtated in RUBY-2119
218
+ if enc_cmd['txnNumber'].is_a?(Integer) && cmd[:txnNumber].is_a?(BSON::Int64)
219
+ enc_cmd['txnNumber'] = BSON::Int64.new(enc_cmd[:txnNumber])
220
+ end
221
+ Msg.new(@flags, @options, enc_cmd)
143
222
  else
144
223
  self
145
224
  end
146
225
  end
147
226
 
227
+ # Possibly decrypt this message with libmongocrypt. Message will only be
228
+ # decrypted if the specified client exists, that client has been given
229
+ # auto-encryption options, and this message is eligible for decryption.
230
+ # A message is eligible for decryption if it represents one of the command
231
+ # types whitelisted by libmongocrypt and it contains data that is required
232
+ # to be encrypted by a local or remote json schema.
233
+ #
234
+ # @param [ Mongo::Client | nil ] client The client used to make the original
235
+ # command. This client may have auto-encryption options specified.
236
+ #
237
+ # @return [ Mongo::Protocol::Msg ] The decryption message, or the original
238
+ # message if decryption was not possible or necessary.
239
+ def maybe_decrypt(client)
240
+ if client && client.encrypter
241
+ cmd = merge_sections
242
+ enc_cmd = client.encrypter.decrypt(cmd)
243
+ Msg.new(@flags, @options, enc_cmd)
244
+ else
245
+ self
246
+ end
247
+ end
248
+
249
+ # Whether this message represents a bulk write. A bulk write is an insert,
250
+ # update, or delete operation that encompasses multiple operations of
251
+ # the same type.
252
+ #
253
+ # @return [ Boolean ] Whether this message represents a bulk write.
254
+ #
255
+ # @note This method was written to support client-side encryption
256
+ # functionality. It is not recommended that this method be used in
257
+ # service of any other feature or behavior.
258
+ #
259
+ # @api private
260
+ def bulk_write?
261
+ inserts = @main_document['documents']
262
+ updates = @main_document['updates']
263
+ deletes = @main_document['deletes']
264
+
265
+ num_inserts = inserts && inserts.length || 0
266
+ num_updates = updates && updates.length || 0
267
+ num_deletes = deletes && deletes.length || 0
268
+
269
+ num_inserts > 1 || num_updates > 1 || num_deletes > 1
270
+ end
271
+
148
272
  private
149
273
 
150
274
  def command
151
- @command ||= global_args.dup.tap do |cmd|
152
- cmd.delete(DATABASE_IDENTIFIER)
153
- sections.each do |section|
154
- if section[:type] == 1
155
- identifier = section[:payload][:identifier]
156
- cmd[identifier] ||= []
157
- cmd[identifier] += section[:payload][:sequence]
275
+ @command ||= if @main_document
276
+ @main_document.dup.tap do |cmd|
277
+ @sequences.each do |section|
278
+ cmd[section.identifier] ||= []
279
+ cmd[section.identifier] += section.documents
158
280
  end
159
281
  end
282
+ else
283
+ documents.first
160
284
  end
161
285
  end
162
286
 
@@ -166,8 +290,24 @@ module Mongo
166
290
  end
167
291
  end
168
292
 
169
- def global_args
170
- @global_args ||= (sections[0] || {})
293
+ # Encapsulates a type 1 OP_MSG section.
294
+ #
295
+ # @see https://github.com/mongodb/specifications/blob/master/source/message/OP_MSG.rst#sections
296
+ #
297
+ # @api private
298
+ class Section1
299
+ def initialize(identifier, documents)
300
+ @identifier, @documents = identifier, documents
301
+ end
302
+
303
+ attr_reader :identifier, :documents
304
+
305
+ def ==(other)
306
+ other.is_a?(Section1) &&
307
+ identifier == other.identifier && documents == other.documents
308
+ end
309
+
310
+ alias :eql? :==
171
311
  end
172
312
 
173
313
  # The operation code required to specify a OP_MSG message.
@@ -177,19 +317,33 @@ module Mongo
177
317
  OP_CODE = 2013
178
318
 
179
319
  # Available flags for a OP_MSG message.
180
- FLAGS = Array.new(16).tap { |arr|
320
+ FLAGS = Array.new(16).tap do |arr|
181
321
  arr[0] = :checksum_present
182
322
  arr[1] = :more_to_come
183
- }
323
+ end.freeze
184
324
 
185
325
  # @!attribute
186
326
  # @return [Array<Symbol>] The flags for this message.
187
327
  field :flags, BitVector.new(FLAGS)
188
328
 
189
- # @!attribute
190
- # @return [Hash] The sections of payload type 1 or 0.
329
+ # The sections that will be serialized, or the documents have been
330
+ # deserialized.
331
+ #
332
+ # Usually the sections contain OP_MSG-compliant sections derived
333
+ # from @main_document and @sequences. The information in @main_document
334
+ # and @sequences is duplicated in the sections.
335
+ #
336
+ # When deserializing Msg instances, sections temporarily is an array
337
+ # of documents returned in the type 0 section of the OP_MSG wire
338
+ # protocol message. #fix_after_deserialization method mutates this
339
+ # object to have sections, @main_document and @sequences be what
340
+ # they would have been had the Msg instance been constructed using
341
+ # the constructor (rather than having been deserialized).
342
+ #
343
+ # @return [ Array<Hash> | Array<BSON::Document> ] The sections of
344
+ # payload type 1 or 0.
345
+ # @api private
191
346
  field :sections, Sections
192
- alias :documents :sections
193
347
 
194
348
  Registry.register(OP_CODE, self)
195
349
  end
@@ -100,21 +100,19 @@ module Mongo
100
100
  true
101
101
  end
102
102
 
103
- # Compress this message.
103
+ # Compress the message, if the command being sent permits compression.
104
+ # Otherwise returns self.
104
105
  #
105
106
  # @param [ String, Symbol ] compressor The compressor to use.
106
107
  # @param [ Integer ] zlib_compression_level The zlib compression level to use.
107
108
  #
108
- # @return [ Compressed, self ] A Protocol::Compressed message or self, depending on whether
109
- # this message can be compressed.
109
+ # @return [ Message ] A Protocol::Compressed message or self,
110
+ # depending on whether this message can be compressed.
110
111
  #
111
112
  # @since 2.5.0
112
- def compress!(compressor, zlib_compression_level = nil)
113
- if compressor && compression_allowed?(selector.keys.first)
114
- Compressed.new(self, compressor, zlib_compression_level)
115
- else
116
- self
117
- end
113
+ # @api private
114
+ def maybe_compress(compressor, zlib_compression_level = nil)
115
+ compress_if_possible(selector.keys.first, compressor, zlib_compression_level)
118
116
  end
119
117
 
120
118
  protected