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
@@ -109,8 +109,7 @@ describe Mongo::Auth::User::View do
109
109
  min_server_fcv '3.6'
110
110
 
111
111
  it 'does not compress the message' do
112
- # The dropUser command message will be compressed, so expect instantiation once.
113
- expect(Mongo::Protocol::Compressed).to receive(:new).once.and_call_original
112
+ expect(Mongo::Protocol::Compressed).not_to receive(:new)
114
113
  expect(response).to be_successful
115
114
  end
116
115
  end
@@ -197,8 +196,7 @@ describe Mongo::Auth::User::View do
197
196
  min_server_fcv '3.6'
198
197
 
199
198
  it 'does not compress the message' do
200
- # The dropUser command message will be compressed, so expect instantiation once.
201
- expect(Mongo::Protocol::Compressed).to receive(:new).once.and_call_original
199
+ expect(Mongo::Protocol::Compressed).not_to receive(:new)
202
200
  expect(response).to be_successful
203
201
  end
204
202
  end
@@ -247,8 +245,7 @@ describe Mongo::Auth::User::View do
247
245
  min_server_fcv '3.6'
248
246
 
249
247
  it 'does not compress the message' do
250
- # The dropUser command message will be compressed, so expect instantiation once.
251
- expect(Mongo::Protocol::Compressed).to receive(:new).once.and_call_original
248
+ expect(Mongo::Protocol::Compressed).not_to receive(:new)
252
249
  expect(response).to be_successful
253
250
  end
254
251
  end
@@ -48,6 +48,10 @@ describe Mongo::Auth::X509 do
48
48
 
49
49
  context 'when the user is not authorized for the database' do
50
50
 
51
+ before do
52
+ connection.connect!
53
+ end
54
+
51
55
  let(:x509) do
52
56
  described_class.new(user)
53
57
  end
@@ -56,7 +60,7 @@ describe Mongo::Auth::X509 do
56
60
  x509.login(connection).documents[0]
57
61
  end
58
62
 
59
- it 'logs the user into the connection' do
63
+ it 'attempts to log the user into the connection' do
60
64
  expect {
61
65
  x509.login(connection)
62
66
  }.to raise_error(Mongo::Auth::Unauthorized)
@@ -84,19 +84,23 @@ describe Mongo::BulkWrite::Result do
84
84
 
85
85
  context 'with top level error' do
86
86
  let(:results_document) do
87
- {'writeErrors' => {
88
- 'ok' => 0,
89
- 'errmsg' => 'not master',
90
- 'code' => 10107,
91
- 'codeName' => 'NotMaster',
92
- }}
87
+ {
88
+ 'writeErrors' => [
89
+ {
90
+ 'ok' => 0,
91
+ 'errmsg' => 'not master',
92
+ 'code' => 10107,
93
+ 'codeName' => 'NotMaster',
94
+ }
95
+ ]
96
+ }
93
97
  end
94
98
 
95
99
  it 'raises BulkWriteError' do
96
100
  expect do
97
101
  subject.validate!
98
102
  # BulkWriteErrors don't have any messages on them
99
- end.to raise_error(Mongo::Error::BulkWriteError, nil)
103
+ end.to raise_error(Mongo::Error::BulkWriteError, /not master/)
100
104
  end
101
105
  end
102
106
 
@@ -167,8 +167,212 @@ describe Mongo::Client do
167
167
  end
168
168
 
169
169
  describe '#initialize' do
170
-
171
170
  context 'when providing options' do
171
+ context 'with auto_encryption_options' do
172
+ require_libmongocrypt
173
+
174
+ include_context 'define shared FLE helpers'
175
+
176
+ let(:client) do
177
+ new_local_client_nmio(
178
+ SpecConfig.instance.addresses,
179
+ SpecConfig.instance.test_options.merge(client_opts)
180
+ )
181
+ end
182
+
183
+ let(:client_opts) { { auto_encryption_options: auto_encryption_options } }
184
+
185
+ let(:auto_encryption_options) do
186
+ {
187
+ key_vault_client: key_vault_client,
188
+ key_vault_namespace: key_vault_namespace,
189
+ kms_providers: kms_providers,
190
+ schema_map: schema_map,
191
+ bypass_auto_encryption: bypass_auto_encryption,
192
+ extra_options: extra_options,
193
+ }
194
+ end
195
+
196
+ let(:key_vault_client) { new_local_client_nmio(SpecConfig.instance.addresses) }
197
+
198
+ let(:bypass_auto_encryption) { true }
199
+
200
+ let(:extra_options) do
201
+ {
202
+ mongocryptd_uri: mongocryptd_uri,
203
+ mongocryptd_bypass_spawn: mongocryptd_bypass_spawn,
204
+ mongocryptd_spawn_path: mongocryptd_spawn_path,
205
+ mongocryptd_spawn_args: mongocryptd_spawn_args,
206
+ }
207
+ end
208
+
209
+ let(:mongocryptd_uri) { 'mongodb://localhost:27021' }
210
+ let(:mongocryptd_bypass_spawn) { true }
211
+ let(:mongocryptd_spawn_path) { '/spawn/path' }
212
+ let(:mongocryptd_spawn_args) { ['--idleShutdownTimeoutSecs=100'] }
213
+
214
+ shared_examples 'a functioning auto encryption client' do
215
+ let(:encryption_options) { client.encrypter.options }
216
+
217
+ context 'when auto_encrypt_opts are nil' do
218
+ let(:auto_encryption_options) { nil }
219
+
220
+ it 'does not raise an exception' do
221
+ expect { client }.not_to raise_error
222
+ end
223
+ end
224
+
225
+ context 'when key_vault_namespace is nil' do
226
+ let(:key_vault_namespace) { nil }
227
+
228
+ it 'raises an exception' do
229
+ expect { client }.to raise_error(ArgumentError, /key_vault_namespace option cannot be nil/)
230
+ end
231
+ end
232
+
233
+ context 'when key_vault_namespace is incorrectly formatted' do
234
+ let(:key_vault_namespace) { 'not.good.formatting' }
235
+
236
+ it 'raises an exception' do
237
+ expect { client }.to raise_error(ArgumentError, /key_vault_namespace option must be in the format database.collection/)
238
+ end
239
+ end
240
+
241
+ context 'when kms_providers is nil' do
242
+ let(:kms_providers) { nil }
243
+
244
+ it 'raises an exception' do
245
+ expect { client }.to raise_error(ArgumentError, /kms_providers option must not be nil/)
246
+ end
247
+ end
248
+
249
+ context 'when kms_providers doesn\'t have local or aws keys' do
250
+ let(:kms_providers) { { random_key: 'hello' } }
251
+
252
+ it 'raises an exception' do
253
+ expect { client }.to raise_error(ArgumentError, /kms_providers option must have one of the following keys: :aws, :local/)
254
+ end
255
+ end
256
+
257
+ context 'when local kms_provider is incorrectly formatted' do
258
+ let(:kms_providers) { { local: { wrong_key: 'hello' } } }
259
+
260
+ it 'raises an exception' do
261
+ expect { client }.to raise_error(ArgumentError, /kms_providers with :local key must be in the format: { local: { key: 'MASTER-KEY' } }/)
262
+ end
263
+ end
264
+
265
+ context 'when aws kms_provider is incorrectly formatted' do
266
+ let(:kms_providers) { { aws: { wrong_key: 'hello' } } }
267
+
268
+ it 'raises an exception' do
269
+ expect { client }.to raise_error(ArgumentError, /kms_providers with :aws key must be in the format: { aws: { access_key_id: 'YOUR-ACCESS-KEY-ID', secret_access_key: 'SECRET-ACCESS-KEY' } }/)
270
+ end
271
+ end
272
+
273
+ context 'with an invalid schema map' do
274
+ let(:schema_map) { '' }
275
+
276
+ it 'raises an exception' do
277
+ expect { client }.to raise_error(ArgumentError, /schema_map must be a Hash or nil/)
278
+ end
279
+ end
280
+
281
+ context 'with valid options' do
282
+ it 'does not raise an exception' do
283
+ expect { client }.not_to raise_error
284
+ end
285
+
286
+ context 'with a nil schema_map' do
287
+ let(:schema_map) { nil }
288
+
289
+ it 'does not raise an exception' do
290
+ expect { client }.not_to raise_error
291
+ end
292
+ end
293
+
294
+ it 'sets options on the client' do
295
+ expect(encryption_options[:key_vault_client]).to eq(key_vault_client)
296
+ expect(encryption_options[:key_vault_namespace]).to eq(key_vault_namespace)
297
+ # Don't explicitly expect kms_providers to avoid accidentally exposing
298
+ # sensitive data in evergreen logs
299
+ expect(encryption_options[:kms_providers]).to be_a_kind_of(Hash)
300
+ expect(encryption_options[:schema_map]).to eq(schema_map)
301
+ expect(encryption_options[:bypass_auto_encryption]).to eq(bypass_auto_encryption)
302
+ expect(encryption_options[:extra_options][:mongocryptd_uri]).to eq(mongocryptd_uri)
303
+ expect(encryption_options[:extra_options][:mongocryptd_bypass_spawn]).to eq(mongocryptd_bypass_spawn)
304
+ expect(encryption_options[:extra_options][:mongocryptd_spawn_path]).to eq(mongocryptd_spawn_path)
305
+ expect(encryption_options[:extra_options][:mongocryptd_spawn_args]).to eq(mongocryptd_spawn_args)
306
+
307
+ expect(client.encrypter.mongocryptd_client.options[:monitoring_io]).to be false
308
+ end
309
+
310
+ context 'with default extra options' do
311
+ let(:auto_encryption_options) do
312
+ {
313
+ key_vault_namespace: key_vault_namespace,
314
+ kms_providers: kms_providers,
315
+ schema_map: schema_map,
316
+ }
317
+ end
318
+
319
+ it 'sets key_vault_client as a clone of self with no encryption options' do
320
+ key_vault_client = client.encrypter.key_vault_client
321
+ expect(key_vault_client).to eq(client)
322
+ end
323
+
324
+ it 'sets bypass_auto_encryption to false' do
325
+ expect(encryption_options[:bypass_auto_encryption]).to be false
326
+ end
327
+
328
+ it 'sets extra options to defaults' do
329
+ expect(encryption_options[:extra_options][:mongocryptd_uri]).to eq('mongodb://localhost:27020')
330
+ expect(encryption_options[:extra_options][:mongocryptd_bypass_spawn]).to be false
331
+ expect(encryption_options[:extra_options][:mongocryptd_spawn_path]).to eq('mongocryptd')
332
+ expect(encryption_options[:extra_options][:mongocryptd_spawn_args]).to eq(['--idleShutdownTimeoutSecs=60'])
333
+ end
334
+ end
335
+
336
+ context 'with mongocryptd_spawn_args that don\'t include idleShutdownTimeoutSecs' do
337
+ let(:mongocryptd_spawn_args) { ['--otherArgument=true'] }
338
+
339
+ it 'adds a default value to mongocryptd_spawn_args' do
340
+ expect(encryption_options[:extra_options][:mongocryptd_spawn_args]).to eq(mongocryptd_spawn_args + ['--idleShutdownTimeoutSecs=60'])
341
+ end
342
+ end
343
+
344
+ context 'with mongocryptd_spawn_args that has idleShutdownTimeoutSecs as two arguments' do
345
+ let(:mongocryptd_spawn_args) { ['--idleShutdownTimeoutSecs', 100] }
346
+
347
+ it 'does not modify mongocryptd_spawn_args' do
348
+ expect(encryption_options[:extra_options][:mongocryptd_spawn_args]).to eq(mongocryptd_spawn_args)
349
+ end
350
+ end
351
+
352
+ context 'with default key_vault_client' do
353
+ let(:key_vault_client) { nil }
354
+
355
+ it 'creates a key_vault_client' do
356
+ key_vault_client = encryption_options[:key_vault_client]
357
+
358
+ expect(key_vault_client).to be_a_kind_of(Mongo::Client)
359
+ end
360
+ end
361
+ end
362
+ end
363
+
364
+ context 'with AWS KMS providers' do
365
+ include_context 'with AWS kms_providers' do
366
+ it_behaves_like 'a functioning auto encryption client'
367
+ end
368
+ end
369
+
370
+ context 'with local KMS providers' do
371
+ include_context 'with local kms_providers' do
372
+ it_behaves_like 'a functioning auto encryption client'
373
+ end
374
+ end
375
+ end
172
376
 
173
377
  context 'retry_writes option' do
174
378
  let(:client) do
@@ -235,7 +439,7 @@ describe Mongo::Client do
235
439
  min_server_fcv '3.6'
236
440
 
237
441
  it 'uses compression for messages' do
238
- expect(Mongo::Protocol::Compressed).to receive(:new).and_call_original
442
+ expect(Mongo::Protocol::Compressed).to receive(:new).at_least(:once).and_call_original
239
443
  client[TEST_COLL].find({}, limit: 1).first
240
444
  end
241
445
  end
@@ -0,0 +1,405 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::ClientEncryption do
4
+ require_libmongocrypt
5
+ include_context 'define shared FLE helpers'
6
+
7
+ let(:client) do
8
+ ClientRegistry.instance.new_local_client(
9
+ SpecConfig.instance.addresses,
10
+ SpecConfig.instance.test_options
11
+ )
12
+ end
13
+
14
+ let(:client_encryption) do
15
+ described_class.new(client, {
16
+ key_vault_namespace: key_vault_namespace,
17
+ kms_providers: kms_providers
18
+ })
19
+ end
20
+
21
+ describe '#initialize' do
22
+ shared_examples 'a functioning ClientEncryption' do
23
+ context 'with nil key_vault_namespace' do
24
+ let(:key_vault_namespace) { nil }
25
+
26
+ it 'raises an exception' do
27
+ expect do
28
+ client_encryption
29
+ end.to raise_error(ArgumentError, /:key_vault_namespace option cannot be nil/)
30
+ end
31
+ end
32
+
33
+ context 'with invalid key_vault_namespace' do
34
+ let(:key_vault_namespace) { 'three.word.namespace' }
35
+
36
+ it 'raises an exception' do
37
+ expect do
38
+ client_encryption
39
+ end.to raise_error(ArgumentError, /invalid key vault namespace/)
40
+ end
41
+ end
42
+
43
+ context 'with valid options' do
44
+ it 'creates a ClientEncryption object' do
45
+ expect do
46
+ client_encryption
47
+ end.not_to raise_error
48
+ end
49
+ end
50
+ end
51
+
52
+ context 'with local KMS providers' do
53
+ include_context 'with local kms_providers'
54
+ it_behaves_like 'a functioning ClientEncryption'
55
+ end
56
+
57
+ context 'with AWS KMS providers' do
58
+ include_context 'with AWS kms_providers'
59
+ it_behaves_like 'a functioning ClientEncryption'
60
+ end
61
+
62
+ context 'with invalid KMS provider information' do
63
+ let(:kms_providers) { { random_key: {} } }
64
+
65
+ it 'raises an exception' do
66
+ expect do
67
+ client_encryption
68
+ end.to raise_error(ArgumentError, /kms_providers option must have one of the following keys/)
69
+ end
70
+ end
71
+ end
72
+
73
+ describe '#create_data_key' do
74
+ let(:data_key_id) { client_encryption.create_data_key(kms_provider_name, options) }
75
+ let(:key_alt_names) { nil }
76
+
77
+ shared_examples 'it creates a data key' do |with_key_alt_names: false|
78
+ it 'returns the data key id and inserts it into the key vault collection' do
79
+ expect(data_key_id).to be_uuid
80
+
81
+ documents = client.use(key_vault_db)[key_vault_coll].find(_id: data_key_id)
82
+
83
+ expect(documents.count).to eq(1)
84
+
85
+ if with_key_alt_names
86
+ expect(documents.first['keyAltNames']).to match_array(key_alt_names)
87
+ else
88
+ expect(documents.first['keyAltNames']).to be_nil
89
+ end
90
+ end
91
+ end
92
+
93
+ shared_examples 'it supports key_alt_names' do
94
+ let(:options) { base_options.merge(key_alt_names: key_alt_names) }
95
+
96
+ context 'with one value in key_alt_names' do
97
+ let(:key_alt_names) { ['keyAltName1'] }
98
+ it_behaves_like 'it creates a data key', **{ with_key_alt_names: true }
99
+ end
100
+
101
+ context 'with multiple values in key_alt_names' do
102
+ let(:key_alt_names) { ['keyAltName1', 'keyAltName2'] }
103
+ it_behaves_like 'it creates a data key', **{ with_key_alt_names: true }
104
+ end
105
+
106
+ context 'with empty key_alt_names' do
107
+ let(:key_alt_names) { [] }
108
+ it_behaves_like 'it creates a data key'
109
+ end
110
+
111
+ context 'with invalid key_alt_names option' do
112
+ let(:key_alt_names) { 'keyAltName1' }
113
+
114
+ it 'raises an exception' do
115
+ expect do
116
+ data_key_id
117
+ end.to raise_error(ArgumentError, /key_alt_names option must be an Array/)
118
+ end
119
+ end
120
+
121
+ context 'with invalid key_alt_names values' do
122
+ let(:key_alt_names) { ['keyAltNames1', 3] }
123
+
124
+ it 'raises an exception' do
125
+ expect do
126
+ data_key_id
127
+ end.to raise_error(ArgumentError, /values of the :key_alt_names option Array must be Strings/)
128
+ end
129
+ end
130
+ end
131
+
132
+ context 'with AWS KMS provider' do
133
+ include_context 'with AWS kms_providers'
134
+
135
+ let(:base_options) { { master_key: { region: aws_region, key: aws_arn } } }
136
+ it_behaves_like 'it supports key_alt_names'
137
+
138
+ context 'with nil options' do
139
+ let(:options) { nil }
140
+
141
+ it 'raises an exception' do
142
+ expect do
143
+ data_key_id
144
+ end.to raise_error(ArgumentError, /options cannot be nil/)
145
+ end
146
+ end
147
+
148
+ context 'with empty options' do
149
+ let(:options) { {} }
150
+
151
+ it 'raises an exception' do
152
+ expect do
153
+ data_key_id
154
+ end.to raise_error(ArgumentError, /options Hash must contain a key named :master_key/)
155
+ end
156
+ end
157
+
158
+ context 'with nil master key' do
159
+ let(:options) { { master_key: nil } }
160
+
161
+ it 'raises an exception' do
162
+ expect do
163
+ data_key_id
164
+ end.to raise_error(ArgumentError, /The :master_key option cannot be nil/)
165
+ end
166
+ end
167
+
168
+ context 'with invalid master key' do
169
+ let(:options) { { master_key: 'master-key' } }
170
+
171
+ it 'raises an exception' do
172
+ expect do
173
+ data_key_id
174
+ end.to raise_error(ArgumentError, /master-key is an invalid :master_key option/)
175
+ end
176
+ end
177
+
178
+ context 'with empty master key' do
179
+ let(:options) { { master_key: {} } }
180
+
181
+ it 'raises an exception' do
182
+ expect do
183
+ data_key_id
184
+ end.to raise_error(ArgumentError, /The value of :region option of the :master_key options hash cannot be nil/)
185
+ end
186
+ end
187
+
188
+ context 'with nil region' do
189
+ let(:options) { { master_key: { region: nil, key: aws_arn } } }
190
+
191
+ it 'raises an exception' do
192
+ expect do
193
+ data_key_id
194
+ end.to raise_error(ArgumentError, /The value of :region option of the :master_key options hash cannot be nil/)
195
+ end
196
+ end
197
+
198
+ context 'with invalid region' do
199
+ let(:options) { { master_key: { region: 5, key: aws_arn } } }
200
+
201
+ it 'raises an exception' do
202
+ expect do
203
+ data_key_id
204
+ end.to raise_error(ArgumentError, /5 is an invalid AWS master_key region. The value of :region option of the :master_key options hash must be a String/)
205
+ end
206
+ end
207
+
208
+ context 'with nil key' do
209
+ let(:options) { { master_key: { key: nil, region: aws_region } } }
210
+
211
+ it 'raises an exception' do
212
+ expect do
213
+ data_key_id
214
+ end.to raise_error(ArgumentError, /The value of :key option of the :master_key options hash cannot be nil/)
215
+ end
216
+ end
217
+
218
+ context 'with invalid key' do
219
+ let(:options) { { master_key: { key: 5, region: aws_region } } }
220
+
221
+ it 'raises an exception' do
222
+ expect do
223
+ data_key_id
224
+ end.to raise_error(ArgumentError, /5 is an invalid AWS master_key key. The value of :key option of the :master_key options hash must be a String/)
225
+ end
226
+ end
227
+
228
+ context 'with invalid endpoint' do
229
+ let(:options) { { master_key: { key: aws_arn, region: aws_region, endpoint: 5 } } }
230
+
231
+ it 'raises an exception' do
232
+ expect do
233
+ data_key_id
234
+ end.to raise_error(ArgumentError, /5 is an invalid AWS master_key endpoint. The value of :endpoint option of the :master_key options hash must be a String/)
235
+ end
236
+ end
237
+
238
+ context 'with nil endpoint' do
239
+ let(:options) do
240
+ {
241
+ master_key: {
242
+ key: aws_arn,
243
+ region: aws_region,
244
+ endpoint: nil
245
+ }
246
+ }
247
+ end
248
+
249
+ it_behaves_like 'it creates a data key'
250
+ end
251
+
252
+ context 'with valid endpoint, no port' do
253
+ let(:options) do
254
+ {
255
+ master_key: {
256
+ key: aws_arn,
257
+ region: aws_region,
258
+ endpoint: aws_endpoint_host
259
+ }
260
+ }
261
+ end
262
+
263
+ it_behaves_like 'it creates a data key'
264
+ end
265
+
266
+ context 'with valid endpoint' do
267
+ let(:options) { data_key_options }
268
+ it_behaves_like 'it creates a data key'
269
+ end
270
+
271
+ context 'with invalid endpoint' do
272
+ let(:options) do
273
+ {
274
+ master_key: {
275
+ key: aws_arn,
276
+ region: aws_region,
277
+ endpoint: "https://#{aws_endpoint_host}:#{aws_endpoint_port}"
278
+ }
279
+ }
280
+ end
281
+
282
+ let(:expected_message) do
283
+ # RUBY-2129: This error message could be more specific and inform the user
284
+ # that there is a problem with their KMS endpoint
285
+ if BSON::Environment.jruby?
286
+ /getservbyname.* failed/
287
+ else
288
+ /SocketError/
289
+ end
290
+ end
291
+
292
+ it 'raises an exception' do
293
+ expect do
294
+ data_key_id
295
+ end.to raise_error(Mongo::Error::KmsError, expected_message)
296
+ end
297
+ end
298
+
299
+ context 'when socket connect errors out' do
300
+ let(:options) { data_key_options }
301
+
302
+ before do
303
+ allow_any_instance_of(OpenSSL::SSL::SSLSocket)
304
+ .to receive(:connect)
305
+ .and_raise('Error while connecting to socket')
306
+ end
307
+
308
+ it 'raises a KmsError' do
309
+ expect do
310
+ data_key_id
311
+ end.to raise_error(Mongo::Error::KmsError, /Error while connecting to socket/)
312
+ end
313
+ end
314
+
315
+ context 'when socket connect errors out' do
316
+ let(:options) { data_key_options }
317
+
318
+ before do
319
+ allow_any_instance_of(OpenSSL::SSL::SSLSocket)
320
+ .to receive(:sysclose)
321
+ .and_raise('Error while closing socket')
322
+ end
323
+
324
+ it 'does not raise an exception' do
325
+ expect do
326
+ data_key_id
327
+ end.not_to raise_error
328
+ end
329
+ end
330
+ end
331
+
332
+ context 'with local KMS provider' do
333
+ include_context 'with local kms_providers'
334
+ let(:options) { {} }
335
+ let(:base_options) { {} }
336
+
337
+ it_behaves_like 'it supports key_alt_names'
338
+ it_behaves_like 'it creates a data key'
339
+ end
340
+ end
341
+
342
+ describe '#encrypt/decrypt' do
343
+ let(:value) { ssn }
344
+ let(:encrypted_value) { encrypted_ssn }
345
+
346
+ before do
347
+ key_vault_collection.drop
348
+ key_vault_collection.insert_one(data_key)
349
+ end
350
+
351
+ shared_examples 'an encrypter' do
352
+ let(:encrypted) do
353
+ client_encryption.encrypt(
354
+ value,
355
+ {
356
+ key_id: key_id,
357
+ key_alt_name: key_alt_name,
358
+ algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'
359
+ }
360
+ )
361
+ end
362
+
363
+ context 'with key_id option' do
364
+ let(:key_alt_name) { nil }
365
+
366
+ it 'correctly encrypts a string' do
367
+ expect(encrypted).to be_ciphertext
368
+ expect(encrypted.data).to eq(Base64.decode64(encrypted_value))
369
+ end
370
+ end
371
+
372
+ context 'with key_alt_name option' do
373
+ let(:key_id) { nil }
374
+
375
+ it 'correctly encrypts a string' do
376
+ expect(encrypted).to be_ciphertext
377
+ expect(encrypted.data).to eq(Base64.decode64(encrypted_value))
378
+ end
379
+ end
380
+ end
381
+
382
+ shared_examples 'a decrypter' do
383
+ it 'correctly decrypts a string' do
384
+ encrypted = BSON::Binary.new(Base64.decode64(encrypted_value), :ciphertext)
385
+
386
+ result = client_encryption.decrypt(encrypted)
387
+ expect(result).to eq(value)
388
+ end
389
+ end
390
+
391
+ context 'with local KMS providers' do
392
+ include_context 'with local kms_providers'
393
+
394
+ it_behaves_like 'an encrypter'
395
+ it_behaves_like 'a decrypter'
396
+ end
397
+
398
+ context 'with AWS KMS providers' do
399
+ include_context 'with AWS kms_providers'
400
+
401
+ it_behaves_like 'an encrypter'
402
+ it_behaves_like 'a decrypter'
403
+ end
404
+ end
405
+ end