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
@@ -94,6 +94,8 @@ module Mongo
94
94
 
95
95
  # The compressor is determined during the handshake, so it must be an attribute
96
96
  # of the connection.
97
+ #
98
+ # @deprecated
97
99
  def_delegators :connection, :compressor
98
100
 
99
101
  # @return [ Monitoring ] monitoring The monitoring.
@@ -19,7 +19,7 @@ module Mongo
19
19
  # This class models the monitor connections and their behavior.
20
20
  #
21
21
  # @since 2.0.0
22
- class Connection
22
+ class Connection < Server::ConnectionCommon
23
23
  include Retryable
24
24
  include Connectable
25
25
  include Loggable
@@ -64,12 +64,14 @@ module Mongo
64
64
  # Key for compression algorithms in the response from the server during handshake.
65
65
  #
66
66
  # @since 2.5.0
67
+ # @deprecated
67
68
  COMPRESSION = 'compression'.freeze
68
69
 
69
70
  # Warning message that the server has no compression algorithms in common with those requested
70
71
  # by the client.
71
72
  #
72
73
  # @since 2.5.0
74
+ # @deprecated
73
75
  COMPRESSION_WARNING = 'The server has no compression algorithms in common with those requested. ' +
74
76
  'Compression will not be used.'.freeze
75
77
 
@@ -125,11 +127,6 @@ module Mongo
125
127
  # @return [ Mongo::Address ] address The address to connect to.
126
128
  attr_reader :address
127
129
 
128
- # The compressor, which is determined during the handshake.
129
- #
130
- # @since 2.5.0
131
- attr_reader :compressor
132
-
133
130
  # Send the preserialized ismaster call.
134
131
  #
135
132
  # @example Send a preserialized ismaster message.
@@ -209,18 +206,6 @@ module Mongo
209
206
 
210
207
  private
211
208
 
212
- def set_compressor!(reply)
213
- server_compressors = reply[COMPRESSION]
214
-
215
- if options[:compressors]
216
- if intersection = (server_compressors & options[:compressors])
217
- @compressor = intersection[0]
218
- else
219
- log_warn(COMPRESSION_WARNING)
220
- end
221
- end
222
- end
223
-
224
209
  def handshake!(socket)
225
210
  if @app_metadata
226
211
  socket.write(@app_metadata.ismaster_bytes)
@@ -21,8 +21,9 @@ module Mongo
21
21
  class PendingConnection < ConnectionBase
22
22
  extend Forwardable
23
23
 
24
- def initialize(socket, server, monitoring, options = {})
24
+ def initialize(socket, description, server, monitoring, options = {})
25
25
  @socket = socket
26
+ @description = description
26
27
  @options = options
27
28
  @server = server
28
29
  @monitoring = monitoring
@@ -578,7 +578,7 @@ module Mongo
578
578
  txn_num: txn_num,
579
579
  write_concern: write_concern,
580
580
  }
581
- Operation::Command.new(spec).execute(server)
581
+ Operation::Command.new(spec).execute(server, client: @client)
582
582
  end
583
583
  end
584
584
  ensure
@@ -622,7 +622,7 @@ module Mongo
622
622
  db_name: 'admin',
623
623
  session: self,
624
624
  txn_num: txn_num
625
- ).execute(server)
625
+ ).execute(server, client: @client)
626
626
  end
627
627
  end
628
628
 
@@ -113,9 +113,14 @@ module Mongo
113
113
  def end_sessions
114
114
  while !@queue.empty?
115
115
  server = ServerSelector.get(mode: :primary_preferred).select_server(@cluster)
116
- Operation::Command.new(
117
- :selector => {endSessions: @queue.shift(10_000).collect { |s| s.session_id }},
118
- :db_name => Database::ADMIN).execute(server)
116
+ op = Operation::Command.new(
117
+ selector: {
118
+ endSessions: @queue.shift(10_000).map(&:session_id),
119
+ },
120
+ db_name: Database::ADMIN,
121
+ )
122
+ # end_sessions does not take a client as an argument
123
+ op.execute(server, client: nil)
119
124
  end
120
125
  rescue Mongo::Error, Error::AuthError
121
126
  end
@@ -40,6 +40,11 @@ module Mongo
40
40
  # @since 2.0.0
41
41
  TIMEOUT_PACK = 'l_2'.freeze
42
42
 
43
+ # Write data to the socket in chunks of this size.
44
+ #
45
+ # @api private
46
+ WRITE_CHUNK_SIZE = 65536
47
+
43
48
  # @return [ Integer ] family The type of host family.
44
49
  attr_reader :family
45
50
 
@@ -87,7 +92,7 @@ module Mongo
87
92
  #
88
93
  # @since 2.0.0
89
94
  def close
90
- @socket.close rescue true
95
+ @socket.close rescue nil
91
96
  true
92
97
  end
93
98
 
@@ -105,20 +110,6 @@ module Mongo
105
110
  handle_errors { @socket.gets(*args) }
106
111
  end
107
112
 
108
- # Create the new socket for the provided family - ipv4, piv6, or unix.
109
- #
110
- # @example Create a new ipv4 socket.
111
- # Socket.new(Socket::PF_INET)
112
- #
113
- # @param [ Integer ] family The socket domain.
114
- #
115
- # @since 2.0.0
116
- def initialize(family)
117
- @family = family
118
- @socket = ::Socket.new(family, SOCK_STREAM, 0)
119
- set_socket_options(@socket)
120
- end
121
-
122
113
  # Will read all data from the socket for the provided number of bytes.
123
114
  # If no data is returned, an exception will be raised.
124
115
  #
@@ -172,7 +163,29 @@ module Mongo
172
163
  #
173
164
  # @since 2.0.0
174
165
  def write(*args)
175
- handle_errors { @socket.write(*args) }
166
+ handle_errors do
167
+ # This method used to forward arguments to @socket.write in a
168
+ # single call like so:
169
+ #
170
+ # @socket.write(*args)
171
+ #
172
+ # Turns out, when each buffer to be written is large (e.g. 32 MiB),
173
+ # this write call would take an extremely long time (20+ seconds)
174
+ # while using 100% CPU. Splitting the writes into chunks produced
175
+ # massively better performance (0.05 seconds to write the 32 MiB of
176
+ # data on the same hardware). Unfortunately splitting the data,
177
+ # one would assume, results in it being copied, but this seems to be
178
+ # a much more minor issue compared to CPU cost of writing large buffers.
179
+ args.each do |buf|
180
+ buf = buf.to_s
181
+ i = 0
182
+ while i < buf.length
183
+ chunk = buf[i...i+WRITE_CHUNK_SIZE]
184
+ @socket.write(chunk)
185
+ i += WRITE_CHUNK_SIZE
186
+ end
187
+ end
188
+ end
176
189
  end
177
190
 
178
191
  # Tests if this socket has reached EOF. Primarily used for liveness checks.
@@ -46,12 +46,22 @@ module Mongo
46
46
  # @since 2.0.0
47
47
  def connect!
48
48
  Timeout.timeout(options[:connect_timeout], Error::SocketTimeoutError) do
49
- handle_errors { @tcp_socket.connect(::Socket.pack_sockaddr_in(port, host)) }
49
+ handle_errors do
50
+ @tcp_socket.connect(::Socket.pack_sockaddr_in(port, host))
51
+ end
50
52
  @socket = OpenSSL::SSL::SSLSocket.new(@tcp_socket, context)
51
- @socket.hostname = @host_name
52
- @socket.sync_close = true
53
- handle_errors { @socket.connect }
54
- verify_certificate!(@socket)
53
+ begin
54
+ @socket.hostname = @host_name
55
+ @socket.sync_close = true
56
+ handle_errors do
57
+ @socket.connect
58
+ end
59
+ verify_certificate!(@socket)
60
+ rescue
61
+ @socket.close
62
+ @socket = nil
63
+ raise
64
+ end
55
65
  self
56
66
  end
57
67
  end
@@ -76,9 +86,14 @@ module Mongo
76
86
  @context = create_context(options)
77
87
  @family = family
78
88
  @tcp_socket = ::Socket.new(family, SOCK_STREAM, 0)
79
- @tcp_socket.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
80
- set_socket_options(@tcp_socket)
81
- connect!
89
+ begin
90
+ @tcp_socket.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
91
+ set_socket_options(@tcp_socket)
92
+ connect!
93
+ rescue
94
+ @tcp_socket.close
95
+ raise
96
+ end
82
97
  end
83
98
 
84
99
  # Read a single byte from the socket.
@@ -40,7 +40,9 @@ module Mongo
40
40
  def connect!
41
41
  Timeout.timeout(options[:connect_timeout], Error::SocketTimeoutError) do
42
42
  socket.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
43
- handle_errors { socket.connect(::Socket.pack_sockaddr_in(port, host)) }
43
+ handle_errors do
44
+ socket.connect(::Socket.pack_sockaddr_in(port, host))
45
+ end
44
46
  self
45
47
  end
46
48
  end
@@ -63,8 +65,15 @@ module Mongo
63
65
  # @since 2.0.0
64
66
  def initialize(host, port, timeout, family, options = {})
65
67
  @host, @port, @timeout, @options = host, port, timeout, options
66
- super(family)
67
- connect!
68
+ @family = family
69
+ @socket = ::Socket.new(family, SOCK_STREAM, 0)
70
+ begin
71
+ set_socket_options(@socket)
72
+ connect!
73
+ rescue
74
+ @socket.close
75
+ raise
76
+ end
68
77
  end
69
78
 
70
79
  private
@@ -0,0 +1,49 @@
1
+ # Copyright (C) 2020 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+ module Timeout
17
+
18
+ # A wrapper around Ruby core's Timeout::timeout method that provides
19
+ # a standardized API for Ruby versions older and newer than 2.4.0,
20
+ # which is when the third argument was introduced.
21
+ #
22
+ # @param [ Numeric ] sec The number of seconds before timeout.
23
+ # @param [ Class ] klass The exception class to raise on timeout, optional.
24
+ # When no error exception is provided, Timeout::Error is raised.
25
+ # @param [ String ] message The error message passed to the exception raised
26
+ # on timeout, optional. When no error message is provided, the default
27
+ # error message is "execution expired".
28
+ #
29
+ # @note Ruby versions older than 2.4.0 do not support specifying a custom
30
+ # error message, and any error message passed in as an argument will be
31
+ # ignored.
32
+ def timeout(sec, klass=nil, message=nil)
33
+ if RUBY_VERSION < '2.4.0'
34
+ ::Timeout.timeout(sec, klass) do
35
+ yield
36
+ end
37
+ else
38
+ # Jruby Timeout::timeout method does not support passing nil arguments.
39
+ # Remove the nil arguments before passing them along to the core
40
+ # Timeout::timeout method.
41
+ optional_args = [klass, message].compact
42
+ ::Timeout.timeout(sec, *optional_args) do
43
+ yield
44
+ end
45
+ end
46
+ end
47
+ module_function :timeout
48
+ end
49
+ end
@@ -215,10 +215,22 @@ module Mongo
215
215
  # @example Get the uri object.
216
216
  # URI.get(string)
217
217
  #
218
+ # @param [ String ] string The URI to parse.
219
+ # @param [ Hash ] options The options.
220
+ #
221
+ # @option options [ Logger ] :logger A custom logger to use.
222
+ #
218
223
  # @return [URI, URI::SRVProtocol] The uri object.
219
224
  #
220
225
  # @since 2.5.0
221
226
  def self.get(string, opts = {})
227
+ unless string
228
+ raise Error::InvalidURI.new(string, 'URI must be a string, not nil.')
229
+ end
230
+ if string.empty?
231
+ raise Error::InvalidURI.new(string, 'Cannot parse an empty URI.')
232
+ end
233
+
222
234
  scheme, _, remaining = string.partition(SCHEME_DELIM)
223
235
  case scheme
224
236
  when MONGODB_SCHEME
@@ -257,13 +269,22 @@ module Mongo
257
269
  # @example Create the new URI.
258
270
  # URI.new('mongodb://localhost:27017')
259
271
  #
260
- # @param [ String ] string The uri string.
272
+ # @param [ String ] string The URI to parse.
261
273
  # @param [ Hash ] options The options.
262
274
  #
275
+ # @option options [ Logger ] :logger A custom logger to use.
276
+ #
263
277
  # @raise [ Error::InvalidURI ] If the uri does not match the spec.
264
278
  #
265
279
  # @since 2.0.0
266
280
  def initialize(string, options = {})
281
+ unless string
282
+ raise Error::InvalidURI.new(string, 'URI must be a string, not nil.')
283
+ end
284
+ if string.empty?
285
+ raise Error::InvalidURI.new(string, 'Cannot parse an empty URI.')
286
+ end
287
+
267
288
  @string = string
268
289
  @options = options
269
290
  parsed_scheme, _, remaining = string.partition(SCHEME_DELIM)
@@ -302,6 +323,14 @@ module Mongo
302
323
  if @uri_options[:ssl_cert]
303
324
  @uri_options[:ssl_key] = @uri_options[:ssl_cert]
304
325
  end
326
+
327
+ if uri_options[:write_concern] && !uri_options[:write_concern].empty?
328
+ begin
329
+ WriteConcern.get(uri_options[:write_concern])
330
+ rescue Error::InvalidWriteConcern => e
331
+ raise_invalid_error_no_fmt!("#{e.class}: #{e}")
332
+ end
333
+ end
305
334
  end
306
335
 
307
336
  # Get the credentials provided in the URI.
@@ -17,5 +17,5 @@ module Mongo
17
17
  # The current version of the driver.
18
18
  #
19
19
  # @since 2.0.0
20
- VERSION = '2.11.6'.freeze
20
+ VERSION = '2.12.0.rc0'.freeze
21
21
  end
@@ -40,5 +40,5 @@ Gem::Specification.new do |s|
40
40
 
41
41
  s.required_ruby_version = ">= 2.3"
42
42
 
43
- s.add_dependency 'bson', '>=4.4.2', '<5.0.0'
43
+ s.add_dependency 'bson', '>=4.8.2', '<5.0.0'
44
44
  end
@@ -20,8 +20,13 @@ configuration are given later in this document.
20
20
  ## MongoDB Server Deployment
21
21
 
22
22
  The tests require a running MongoDB deployment, configured and started
23
- externally to the test suite. Tests that are not appropriate for the running
24
- deployment will be skipped.
23
+ externally to the test suite.
24
+
25
+ Tests that are not appropriate for the running deployment will be skipped,
26
+ with one exception: the test suite assumes that fail points are enabled in
27
+ the deployment (see the Fail Points section below). Not every test uses fail
28
+ points, therefore it is possible to launch the server without fail points
29
+ being enabled and still pass many of the tests in the test suite.
25
30
 
26
31
  ## Starting MongoDB Deployment
27
32
 
@@ -41,7 +46,7 @@ launched as follows:
41
46
 
42
47
  # Launch mongod in one terminal
43
48
  mkdir /tmp/mdb
44
- mongod --dbpath /tmp/mdb
49
+ mongod --dbpath /tmp/mdb --setParameter enableTestCommands=1
45
50
 
46
51
  # Run tests in another terminal
47
52
  rake
@@ -133,7 +138,7 @@ the top of the driver source tree:
133
138
 
134
139
  mlaunch init --single --dir /tmp/mdb-ssl --sslMode requireSSL \
135
140
  --sslPEMKeyFile `pwd`/spec/support/certificates/server.pem \
136
- --sslCAFile `pwd`/spec/support/certificates/ca.pem \
141
+ --sslCAFile `pwd`/spec/support/certificates/ca.crt \
137
142
  --sslClientCertificate `pwd`/spec/support/certificates/client.pem
138
143
 
139
144
  To test that the driver works when the server's certificate is signed by an
@@ -142,7 +147,7 @@ server certificate bundle:
142
147
 
143
148
  mlaunch init --single --dir /tmp/mdb-ssl --sslMode requireSSL \
144
149
  --sslPEMKeyFile `pwd`/spec/support/certificates/server-second-level-bundle.pem \
145
- --sslCAFile `pwd`/spec/support/certificates/ca.pem \
150
+ --sslCAFile `pwd`/spec/support/certificates/ca.crt \
146
151
  --sslClientCertificate `pwd`/spec/support/certificates/client.pem
147
152
 
148
153
  The driver's test suite is configured to verify certificates by default.
@@ -168,7 +173,7 @@ case a standalone server can be started as follows:
168
173
 
169
174
  mlaunch init --single --dir /tmp/mdb-ssl --sslMode requireSSL \
170
175
  --sslPEMKeyFile `pwd`/spec/support/certificates/server.pem \
171
- --sslCAFile `pwd`/spec/support/certificates/ca.pem \
176
+ --sslCAFile `pwd`/spec/support/certificates/ca.crt \
172
177
  --sslAllowConnectionsWithoutCertificates \
173
178
  --sslAllowInvalidCertificates
174
179
 
@@ -264,9 +269,123 @@ To run the test suite against such a server, run:
264
269
 
265
270
  MONGODB_URI="mongodb://localhost:27017/?authMechanism=MONGODB-X509&tls=true&tlsCAFile=spec/support/certificates/ca.crt&tlsCertificateKeyFile=spec/support/certificates/client-x509.pem" rake
266
271
 
272
+ ## Kerberos
273
+
274
+ The Kerberos-related functionality is packaged in a separate gem,
275
+ `mongo_kerberos`. The driver test suite includes a number of unit tests that
276
+ are skipped by default. To run them as part of the test suite, use the
277
+ provided gemfile as follows:
278
+
279
+ export BUNDLE_GEMFILE=gemfiles/mongo_kerberos.gemfile
280
+ bundle install
281
+ export KERBEROS=1
282
+ rake
283
+
284
+ Note that running the full test suite requires a MongoDB deployment. It is
285
+ possible to run just the Kerberos-related unit tests without provisioning a
286
+ MongoDB deployment; consult .evergreen/run-tests-kerberos-unit.sh for the
287
+ full list of relevant test files.
288
+
289
+ ## Client-Side Encryption
290
+
291
+ Install libmongocrypt on your machine:
292
+
293
+ Option 1: Download a pre-built binary
294
+ - Download a tarball of all libmongocrypt variations from this link:
295
+ https://s3.amazonaws.com/mciuploads/libmongocrypt/all/master/latest/libmongocrypt-all.tar.gz
296
+ - Unzip the file you downloaded. You will see a list of folders, each
297
+ corresponding to an operating system. Find the folder that matches
298
+ your operating system and open it.
299
+ - Inside that folder, open the folder called "nocrypto." In either the
300
+ lib or lb64 folder, you will find the libmongocrypt.so or
301
+ libmongocrypt.dylib or libmongocrypt.dll file, depending on your OS.
302
+ - Move that file to wherever you want to keep it on your machine.
303
+
304
+ Option 2: Build from source
305
+ - To build libmongocrypt from source, follow the instructions in the README on the libmongocrypt GitHub repo: https://github.com/mongodb/libmongocrypt
306
+
307
+ Create AWS KMS keys
308
+ Many of the Client-Side Encryption tests require that you have an encryption
309
+ master key hosted on AWS's Key Management Service. Set up a master key by following
310
+ these steps:
311
+
312
+ 1. Sign up for an AWS account at this link if you don't already have one: https://aws.amazon.com/resources/create-account/
313
+
314
+ 2. Create a new IAM user that you want to have permissions to access your new
315
+ master key by following this guide: the "Creating an Administrator IAM User and Group (Console)"
316
+ section of this guide: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user.html
317
+
318
+ 3. Create an access key for your new IAM user and store the access key credentials
319
+ in environment variables on your local machine. Create an access key by following the
320
+ "Managing Access Keys (Console)" instructions in this guide:
321
+ https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_CreateAccessKey
322
+ Once an access key has been created, store the access key id and the access key
323
+ secret in environment variables. If you plan to frequently run Client-Side
324
+ Encryption tests, it may be a good idea to put these lines in your .bash_profile
325
+ or .bashrc file. Otherwise, you can run them in the terminal window where you
326
+ plan to run your tests.
327
+
328
+ ```
329
+ export MONGO_RUBY_DRIVER_AWS_KEY="YOUR-ACCESS-KEY-ID"
330
+ export MONGO_RUBY_DRIVER_AWS_SECRET="YOUR-ACCESS-KEY-SECRET"
331
+ ```
332
+
333
+ 4. Create a new symmetric Customer Master Key (CMK) by following the "Creating Symmetric CMKs (Console)"
334
+ section of this guide: https://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html
335
+
336
+ 5. Store information about your CMK in the following environment variables:
337
+
338
+ a. **Region:** Find your AWS region by following this guide: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#using-regions-availability-zones-describe
339
+ (for example, your region might be "us-east-1" or "ap-south-2").
340
+
341
+ b. **Amazon Resource Name (ARN):** Read the following guide to learn more about ARNs
342
+ and how to view your key's ARN: https://docs.aws.amazon.com/kms/latest/developerguide/viewing-keys-console.html
343
+
344
+ Store these two pieces of information in environment variables. If you plan
345
+ to frequently run Client-Side Encryption tests, it may be a good idea to put
346
+ these lines in your .bash_profile or .bashrc file. Otherwise, you can run
347
+ them in the terminal window where you plan to run your tests.
348
+
349
+ ```
350
+ export MONGO_RUBY_DRIVER_AWS_REGION="YOUR-AWS-REGION"
351
+ export MONGO_RUBY_DRIVER_AWS_ARN="YOUR-AWS-ARN"
352
+ ```
353
+
354
+ 6. Give your IAM user "Key administrator" and "Key user" privileges on your new CMK
355
+ by following the "Using the AWS Management Console Default View" section of this guide:
356
+ https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-modifying.html
357
+
358
+ In one terminal, launch MongoDB:
359
+
360
+ NOTE: You must be running MongoDB 4.2 or higher. All auto-encryption features
361
+ require an enterprise build of MongoDB, but you can still run
362
+ explicit encryption tests using the community edition of MongoDB.
363
+
364
+ Download different versions of MongoDB here: https://www.mongodb.com/download-center/enterprise
365
+
366
+ ```
367
+ mkdir /tmp/mdb
368
+ mongod --dbpath /tmp/mdb --setParameter enableTestCommands=1
369
+ ```
370
+
371
+ In another terminal run the tests, making sure to set the `LIBMONGOCRYPT_PATH`
372
+ environment variable to the full path to the .so/.dll/.dylib
373
+ ```
374
+ LIBMONGOCRYPT_PATH=/path/to/your/libmongocrypt/nocrypto/libmongocrypt.so bundle exec rake
375
+ ```
376
+
267
377
  ## Compression
268
378
 
269
- To be written.
379
+ To test compression, set the `compressors` URI option:
380
+
381
+ MONGODB_URI="mongodb://localhost:27017/?compressors=zlib" rake
382
+
383
+ Note that as of this writing, the driver only supports zlib compression.
384
+ Servers 4.2+ enable zlib by default; to test older servers, explicitly enable
385
+ zlib compression when launching the server:
386
+
387
+ mongod --dbpath /tmp/mdb --setParameter enableTestCommands=1 \
388
+ --networkMessageCompressors snappy,zlib
270
389
 
271
390
  ## Other Options
272
391
 
@@ -360,3 +479,11 @@ Then, any of the standard RSpec invocations will work:
360
479
  To have the test suite report its current configuration, run:
361
480
 
362
481
  rake spec:config
482
+
483
+ ## Color Output
484
+
485
+ The test suite uses color output by default. To view the output in `less`
486
+ with color, use the `-R` option:
487
+
488
+ rake 2>&1 | tee rake.log
489
+ less -R rake.log