ibm_db 5.6.1 → 5.7.0

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 (592) hide show
  1. checksums.yaml +4 -4
  2. data/ext/Makefile +13 -9
  3. data/ext/extconf.rb +176 -110
  4. data/ext/ibm_db.c +60 -0
  5. data/ext/ibm_db.o +0 -0
  6. data/ext/ibm_db.so +0 -0
  7. data/ext/mkmf.log +6 -6
  8. data/ext/ruby_ibm_db_cli.c +14 -10
  9. data/ext/ruby_ibm_db_cli.h +4 -0
  10. data/ext/ruby_ibm_db_cli.o +0 -0
  11. data/lib/IBM_DB.rb +2 -2
  12. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +1254 -277
  13. data/test/active_record/connection_adapters/fake_legacy_adapter.rb +17 -0
  14. data/test/active_record/connection_adapters/fake_misleading_legacy_adapter.rb +8 -0
  15. data/test/activejob/destroy_association_async_job_test.rb +62 -0
  16. data/test/activejob/destroy_association_async_test.rb +147 -11
  17. data/test/activejob/job_runtime_test.rb +41 -0
  18. data/test/activejob/unloadable_base_job.rb +3 -0
  19. data/test/cases/active_record_schema_test.rb +196 -0
  20. data/test/cases/active_record_test.rb +21 -0
  21. data/test/cases/adapter_prevent_writes_test.rb +26 -202
  22. data/test/cases/adapter_test.rb +592 -82
  23. data/test/cases/adapters/abstract_mysql_adapter/active_schema_test.rb +210 -0
  24. data/test/cases/adapters/abstract_mysql_adapter/adapter_prevent_writes_test.rb +111 -0
  25. data/test/cases/adapters/abstract_mysql_adapter/auto_increment_test.rb +48 -0
  26. data/test/cases/adapters/abstract_mysql_adapter/bind_parameter_test.rb +91 -0
  27. data/test/cases/adapters/abstract_mysql_adapter/case_sensitivity_test.rb +65 -0
  28. data/test/cases/adapters/abstract_mysql_adapter/charset_collation_test.rb +85 -0
  29. data/test/cases/adapters/abstract_mysql_adapter/connection_test.rb +267 -0
  30. data/test/cases/adapters/abstract_mysql_adapter/count_deleted_rows_with_lock_test.rb +29 -0
  31. data/test/cases/adapters/abstract_mysql_adapter/json_test.rb +24 -0
  32. data/test/cases/adapters/abstract_mysql_adapter/mysql_boolean_test.rb +102 -0
  33. data/test/cases/adapters/abstract_mysql_adapter/mysql_enum_test.rb +47 -0
  34. data/test/cases/adapters/abstract_mysql_adapter/mysql_explain_test.rb +71 -0
  35. data/test/cases/adapters/abstract_mysql_adapter/nested_deadlock_test.rb +191 -0
  36. data/test/cases/adapters/abstract_mysql_adapter/optimizer_hints_test.rb +69 -0
  37. data/test/cases/adapters/abstract_mysql_adapter/quoting_test.rb +49 -0
  38. data/test/cases/adapters/abstract_mysql_adapter/schema_migrations_test.rb +68 -0
  39. data/test/cases/adapters/abstract_mysql_adapter/schema_test.rb +130 -0
  40. data/test/cases/adapters/abstract_mysql_adapter/set_test.rb +32 -0
  41. data/test/cases/adapters/abstract_mysql_adapter/sp_test.rb +39 -0
  42. data/test/cases/adapters/abstract_mysql_adapter/sql_types_test.rb +16 -0
  43. data/test/cases/adapters/abstract_mysql_adapter/table_options_test.rb +125 -0
  44. data/test/cases/adapters/abstract_mysql_adapter/transaction_test.rb +204 -0
  45. data/test/cases/adapters/abstract_mysql_adapter/unsigned_type_test.rb +77 -0
  46. data/test/cases/adapters/abstract_mysql_adapter/virtual_column_test.rb +69 -0
  47. data/test/cases/adapters/abstract_mysql_adapter/warnings_test.rb +109 -0
  48. data/test/cases/adapters/mysql2/check_constraint_quoting_test.rb +35 -0
  49. data/test/cases/adapters/mysql2/dbconsole_test.rb +87 -0
  50. data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +136 -10
  51. data/test/cases/adapters/mysql2/mysql2_rake_test.rb +433 -0
  52. data/test/cases/adapters/postgresql/active_schema_test.rb +8 -4
  53. data/test/cases/adapters/postgresql/array_test.rb +6 -6
  54. data/test/cases/adapters/postgresql/bind_parameter_test.rb +52 -0
  55. data/test/cases/adapters/postgresql/bit_string_test.rb +2 -2
  56. data/test/cases/adapters/postgresql/bytea_test.rb +3 -3
  57. data/test/cases/adapters/postgresql/case_insensitive_test.rb +1 -1
  58. data/test/cases/adapters/postgresql/change_schema_test.rb +32 -1
  59. data/test/cases/adapters/postgresql/cidr_test.rb +17 -0
  60. data/test/cases/adapters/postgresql/citext_test.rb +7 -1
  61. data/test/cases/adapters/postgresql/collation_test.rb +1 -1
  62. data/test/cases/adapters/postgresql/composite_test.rb +1 -1
  63. data/test/cases/adapters/postgresql/connection_test.rb +43 -36
  64. data/test/cases/adapters/postgresql/create_unlogged_tables_test.rb +3 -2
  65. data/test/cases/adapters/postgresql/datatype_test.rb +9 -4
  66. data/test/cases/adapters/postgresql/date_test.rb +2 -2
  67. data/test/cases/adapters/postgresql/dbconsole_test.rb +109 -0
  68. data/test/cases/adapters/postgresql/deferred_constraints_test.rb +55 -0
  69. data/test/cases/adapters/postgresql/domain_test.rb +1 -1
  70. data/test/cases/adapters/postgresql/enum_test.rb +208 -8
  71. data/test/cases/adapters/postgresql/explain_test.rb +25 -6
  72. data/test/cases/adapters/postgresql/extension_migration_test.rb +51 -9
  73. data/test/cases/adapters/postgresql/foreign_table_test.rb +3 -3
  74. data/test/cases/adapters/postgresql/full_text_test.rb +1 -1
  75. data/test/cases/adapters/postgresql/geometric_test.rb +13 -6
  76. data/test/cases/adapters/postgresql/hstore_test.rb +22 -32
  77. data/test/cases/adapters/postgresql/infinity_test.rb +13 -2
  78. data/test/cases/adapters/postgresql/integer_test.rb +1 -1
  79. data/test/cases/adapters/postgresql/interval_test.rb +9 -17
  80. data/test/cases/adapters/postgresql/invertible_migration_test.rb +139 -0
  81. data/test/cases/adapters/postgresql/json_test.rb +5 -0
  82. data/test/cases/adapters/postgresql/ltree_test.rb +1 -1
  83. data/test/cases/adapters/postgresql/money_test.rb +17 -9
  84. data/test/cases/adapters/postgresql/network_test.rb +13 -1
  85. data/test/cases/adapters/postgresql/numbers_test.rb +18 -2
  86. data/test/cases/adapters/postgresql/optimizer_hints_test.rb +9 -9
  87. data/test/cases/adapters/postgresql/partitions_test.rb +5 -2
  88. data/test/cases/adapters/postgresql/postgresql_adapter_prevent_writes_test.rb +7 -110
  89. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +403 -20
  90. data/test/cases/adapters/postgresql/postgresql_rake_test.rb +637 -0
  91. data/test/cases/adapters/postgresql/prepared_statements_disabled_test.rb +1 -1
  92. data/test/cases/adapters/postgresql/quoting_test.rb +60 -1
  93. data/test/cases/adapters/postgresql/range_test.rb +185 -21
  94. data/test/cases/adapters/postgresql/referential_integrity_test.rb +29 -5
  95. data/test/cases/adapters/postgresql/rename_table_test.rb +35 -8
  96. data/test/cases/adapters/postgresql/schema_authorization_test.rb +2 -2
  97. data/test/cases/adapters/postgresql/schema_test.rb +270 -20
  98. data/test/cases/adapters/postgresql/serial_test.rb +5 -5
  99. data/test/cases/adapters/postgresql/statement_pool_test.rb +6 -2
  100. data/test/cases/adapters/postgresql/timestamp_test.rb +122 -5
  101. data/test/cases/adapters/postgresql/transaction_nested_test.rb +130 -6
  102. data/test/cases/adapters/postgresql/transaction_test.rb +37 -11
  103. data/test/cases/adapters/postgresql/type_lookup_test.rb +1 -1
  104. data/test/cases/adapters/postgresql/uuid_test.rb +77 -9
  105. data/test/cases/adapters/postgresql/virtual_column_test.rb +114 -0
  106. data/test/cases/adapters/postgresql/xml_test.rb +1 -1
  107. data/test/cases/adapters/sqlite3/bind_parameter_test.rb +52 -0
  108. data/test/cases/adapters/sqlite3/collation_test.rb +1 -1
  109. data/test/cases/adapters/sqlite3/copy_table_test.rb +28 -7
  110. data/test/cases/adapters/sqlite3/dbconsole_test.rb +81 -0
  111. data/test/cases/adapters/sqlite3/explain_test.rb +3 -3
  112. data/test/cases/adapters/sqlite3/quoting_test.rb +34 -3
  113. data/test/cases/adapters/sqlite3/sqlite3_adapter_prevent_writes_test.rb +9 -102
  114. data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +727 -72
  115. data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +6 -3
  116. data/test/cases/adapters/sqlite3/sqlite_rake_test.rb +264 -0
  117. data/test/cases/adapters/sqlite3/statement_pool_test.rb +1 -1
  118. data/test/cases/adapters/sqlite3/transaction_test.rb +6 -3
  119. data/test/cases/adapters/sqlite3/virtual_column_test.rb +138 -0
  120. data/test/cases/adapters/sqlite3/virtual_table_test.rb +51 -0
  121. data/test/cases/adapters/trilogy/dbconsole_test.rb +76 -0
  122. data/test/cases/adapters/trilogy/trilogy_adapter_test.rb +473 -0
  123. data/test/cases/adapters/trilogy/trilogy_rake_test.rb +433 -0
  124. data/test/cases/aggregations_test.rb +16 -0
  125. data/test/cases/annotate_test.rb +14 -12
  126. data/test/cases/arel/attributes/attribute_test.rb +86 -47
  127. data/test/cases/arel/collectors/bind_test.rb +1 -1
  128. data/test/cases/arel/collectors/composite_test.rb +11 -1
  129. data/test/cases/arel/collectors/sql_string_test.rb +1 -1
  130. data/test/cases/arel/collectors/substitute_bind_collector_test.rb +1 -1
  131. data/test/cases/arel/delete_manager_test.rb +0 -6
  132. data/test/cases/arel/factory_methods_test.rb +45 -0
  133. data/test/cases/arel/insert_manager_test.rb +1 -7
  134. data/test/cases/arel/nodes/as_test.rb +12 -0
  135. data/test/cases/arel/nodes/ascending_test.rb +1 -1
  136. data/test/cases/arel/nodes/bin_test.rb +1 -1
  137. data/test/cases/arel/nodes/bound_sql_literal_test.rb +31 -0
  138. data/test/cases/arel/nodes/cte_test.rb +46 -0
  139. data/test/cases/arel/nodes/descending_test.rb +1 -1
  140. data/test/cases/arel/nodes/equality_test.rb +3 -3
  141. data/test/cases/arel/nodes/filter_test.rb +37 -0
  142. data/test/cases/arel/nodes/fragments_test.rb +38 -0
  143. data/test/cases/arel/nodes/homogeneous_in_test.rb +52 -0
  144. data/test/cases/arel/nodes/infix_operation_test.rb +1 -1
  145. data/test/cases/arel/nodes/node_test.rb +1 -1
  146. data/test/cases/arel/nodes/or_test.rb +2 -2
  147. data/test/cases/arel/nodes/sql_literal_test.rb +18 -1
  148. data/test/cases/arel/nodes/table_alias_test.rb +12 -0
  149. data/test/cases/arel/nodes/unary_operation_test.rb +1 -1
  150. data/test/cases/arel/nodes/update_statement_test.rb +4 -0
  151. data/test/cases/arel/nodes_test.rb +3 -2
  152. data/test/cases/arel/select_manager_test.rb +12 -12
  153. data/test/cases/arel/support/fake_record.rb +22 -17
  154. data/test/cases/arel/table_test.rb +15 -25
  155. data/test/cases/arel/update_manager_test.rb +51 -6
  156. data/test/cases/arel/visitors/dispatch_contamination_test.rb +1 -1
  157. data/test/cases/arel/visitors/dot_test.rb +177 -2
  158. data/test/cases/arel/visitors/mysql_test.rb +49 -1
  159. data/test/cases/arel/visitors/postgres_test.rb +1 -31
  160. data/test/cases/arel/visitors/sqlite_test.rb +1 -1
  161. data/test/cases/arel/visitors/to_sql_test.rb +330 -20
  162. data/test/cases/assertions/query_assertions_test.rb +136 -0
  163. data/test/cases/associations/belongs_to_associations_test.rb +502 -41
  164. data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +1 -1
  165. data/test/cases/associations/cascaded_eager_loading_test.rb +26 -15
  166. data/test/cases/associations/eager_load_nested_include_test.rb +1 -1
  167. data/test/cases/associations/eager_singularization_test.rb +1 -1
  168. data/test/cases/associations/eager_test.rb +255 -93
  169. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +25 -53
  170. data/test/cases/associations/has_many_associations_test.rb +282 -72
  171. data/test/cases/associations/has_many_through_associations_test.rb +172 -45
  172. data/test/cases/associations/has_many_through_disable_joins_associations_test.rb +197 -0
  173. data/test/cases/associations/has_one_associations_test.rb +160 -29
  174. data/test/cases/associations/has_one_through_associations_test.rb +64 -15
  175. data/test/cases/associations/has_one_through_disable_joins_associations_test.rb +82 -0
  176. data/test/cases/associations/inner_join_association_test.rb +36 -6
  177. data/test/cases/associations/inverse_associations_test.rb +177 -40
  178. data/test/cases/associations/join_model_test.rb +17 -12
  179. data/test/cases/associations/left_outer_join_association_test.rb +14 -3
  180. data/test/cases/associations/nested_error_test.rb +116 -0
  181. data/test/cases/associations/nested_through_associations_test.rb +54 -19
  182. data/test/cases/associations/required_test.rb +1 -1
  183. data/test/cases/associations_test.rb +1278 -21
  184. data/test/cases/asynchronous_queries_test.rb +310 -0
  185. data/test/cases/attribute_methods/read_test.rb +6 -0
  186. data/test/cases/attribute_methods/time_zone_converter_test.rb +21 -0
  187. data/test/cases/attribute_methods_test.rb +565 -46
  188. data/test/cases/attributes_test.rb +42 -1
  189. data/test/cases/autosave_association_test.rb +645 -92
  190. data/test/cases/base_prevent_writes_test.rb +28 -159
  191. data/test/cases/base_test.rb +434 -209
  192. data/test/cases/batches_test.rb +441 -57
  193. data/test/cases/binary_test.rb +31 -0
  194. data/test/cases/bind_parameter_test.rb +107 -16
  195. data/test/cases/cache_key_test.rb +7 -7
  196. data/test/cases/calculations_test.rb +541 -110
  197. data/test/cases/callbacks_test.rb +0 -1
  198. data/test/cases/clone_test.rb +5 -4
  199. data/test/cases/coders/yaml_column_test.rb +97 -2
  200. data/test/cases/collection_cache_key_test.rb +24 -16
  201. data/test/cases/column_alias_test.rb +2 -8
  202. data/test/cases/column_definition_test.rb +12 -3
  203. data/test/cases/comment_test.rb +23 -26
  204. data/test/cases/connection_adapters/adapter_leasing_test.rb +9 -9
  205. data/test/cases/connection_adapters/connection_handler_test.rb +145 -99
  206. data/test/cases/connection_adapters/connection_handlers_multi_db_test.rb +79 -55
  207. data/test/cases/connection_adapters/connection_handlers_multi_pool_config_test.rb +17 -20
  208. data/test/cases/connection_adapters/connection_handlers_sharding_db_test.rb +146 -55
  209. data/test/cases/connection_adapters/connection_swapping_nested_test.rb +136 -23
  210. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +96 -27
  211. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +5 -5
  212. data/test/cases/connection_adapters/registration_test.rb +98 -0
  213. data/test/cases/connection_adapters/schema_cache_test.rb +288 -135
  214. data/test/cases/connection_adapters/standalone_connection_test.rb +38 -0
  215. data/test/cases/connection_adapters/statement_pool_test.rb +29 -0
  216. data/test/cases/connection_adapters/type_lookup_test.rb +12 -24
  217. data/test/cases/connection_handling_test.rb +210 -0
  218. data/test/cases/connection_management_test.rb +44 -7
  219. data/test/cases/connection_pool_test.rb +466 -99
  220. data/test/cases/core_test.rb +167 -9
  221. data/test/cases/counter_cache_test.rb +129 -2
  222. data/test/cases/custom_locking_test.rb +3 -3
  223. data/test/cases/database_configurations/hash_config_test.rb +149 -13
  224. data/test/cases/database_configurations/resolver_test.rb +14 -10
  225. data/test/cases/database_configurations/url_config_test.rb +53 -0
  226. data/test/cases/database_configurations_test.rb +86 -43
  227. data/test/cases/database_selector_test.rb +30 -8
  228. data/test/cases/database_statements_test.rb +10 -14
  229. data/test/cases/date_time_precision_test.rb +141 -11
  230. data/test/cases/date_time_test.rb +19 -1
  231. data/test/cases/defaults_test.rb +107 -41
  232. data/test/cases/delegated_type_test.rb +69 -9
  233. data/test/cases/dirty_test.rb +82 -25
  234. data/test/cases/disconnected_test.rb +10 -9
  235. data/test/cases/dup_test.rb +26 -6
  236. data/test/cases/encryption/cipher/aes256_gcm_test.rb +50 -0
  237. data/test/cases/encryption/cipher_test.rb +65 -0
  238. data/test/cases/encryption/concurrency_test.rb +27 -0
  239. data/test/cases/encryption/config_test.rb +21 -0
  240. data/test/cases/encryption/configurable_test.rb +93 -0
  241. data/test/cases/encryption/contexts_test.rb +105 -0
  242. data/test/cases/encryption/derived_secret_key_provider_test.rb +31 -0
  243. data/test/cases/encryption/deterministic_key_provider_test.rb +11 -0
  244. data/test/cases/encryption/encryptable_record_api_test.rb +175 -0
  245. data/test/cases/encryption/encryptable_record_message_pack_serialized_test.rb +42 -0
  246. data/test/cases/encryption/encryptable_record_test.rb +470 -0
  247. data/test/cases/encryption/encrypted_fixtures_test.rb +22 -0
  248. data/test/cases/encryption/encrypting_only_encryptor_test.rb +20 -0
  249. data/test/cases/encryption/encryption_schemes_test.rb +240 -0
  250. data/test/cases/encryption/encryptor_test.rb +113 -0
  251. data/test/cases/encryption/envelope_encryption_key_provider_test.rb +49 -0
  252. data/test/cases/encryption/extended_deterministic_queries_test.rb +81 -0
  253. data/test/cases/encryption/helper.rb +152 -0
  254. data/test/cases/encryption/key_generator_test.rb +55 -0
  255. data/test/cases/encryption/key_provider_test.rb +57 -0
  256. data/test/cases/encryption/key_test.rb +17 -0
  257. data/test/cases/encryption/message_pack_message_serializer_test.rb +70 -0
  258. data/test/cases/encryption/message_serializer_test.rb +82 -0
  259. data/test/cases/encryption/message_test.rb +43 -0
  260. data/test/cases/encryption/null_encryptor_test.rb +21 -0
  261. data/test/cases/encryption/properties_test.rb +69 -0
  262. data/test/cases/encryption/read_only_null_encryptor_test.rb +19 -0
  263. data/test/cases/encryption/scheme_test.rb +58 -0
  264. data/test/cases/encryption/unencrypted_attributes_test.rb +27 -0
  265. data/test/cases/encryption/uniqueness_validations_test.rb +65 -0
  266. data/test/cases/enum_test.rb +374 -72
  267. data/test/cases/errors_test.rb +7 -4
  268. data/test/cases/excluding_test.rb +116 -0
  269. data/test/cases/explain_subscriber_test.rb +6 -1
  270. data/test/cases/explain_test.rb +119 -10
  271. data/test/cases/filter_attributes_test.rb +7 -14
  272. data/test/cases/finder_respond_to_test.rb +3 -3
  273. data/test/cases/finder_test.rb +357 -72
  274. data/test/cases/fixture_set/file_test.rb +9 -0
  275. data/test/cases/fixtures_test.rb +426 -190
  276. data/test/cases/helper.rb +66 -192
  277. data/test/cases/hot_compatibility_test.rb +10 -10
  278. data/test/cases/inheritance_test.rb +51 -61
  279. data/test/cases/inherited_test.rb +40 -0
  280. data/test/cases/insert_all_test.rb +419 -9
  281. data/test/cases/instrumentation_test.rb +202 -30
  282. data/test/cases/integration_test.rb +25 -7
  283. data/test/cases/invalid_connection_test.rb +5 -5
  284. data/test/cases/invertible_migration_test.rb +108 -24
  285. data/test/cases/json_attribute_test.rb +1 -0
  286. data/test/cases/json_serialization_test.rb +5 -5
  287. data/test/cases/json_shared_test_cases.rb +5 -9
  288. data/test/cases/locking_test.rb +67 -31
  289. data/test/cases/log_subscriber_test.rb +17 -15
  290. data/test/cases/marshal_serialization_test.rb +78 -5
  291. data/test/cases/message_pack_test.rb +91 -0
  292. data/test/cases/migration/change_schema_test.rb +77 -46
  293. data/test/cases/migration/change_table_test.rb +129 -114
  294. data/test/cases/migration/check_constraint_test.rb +192 -10
  295. data/test/cases/migration/column_attributes_test.rb +4 -9
  296. data/test/cases/migration/column_positioning_test.rb +2 -2
  297. data/test/cases/migration/columns_test.rb +118 -4
  298. data/test/cases/migration/command_recorder_test.rb +181 -14
  299. data/test/cases/migration/compatibility_test.rb +883 -196
  300. data/test/cases/migration/create_join_table_test.rb +8 -1
  301. data/test/cases/migration/exclusion_constraint_test.rb +192 -0
  302. data/test/cases/migration/foreign_key_test.rb +356 -14
  303. data/test/cases/migration/helper.rb +4 -1
  304. data/test/cases/migration/index_test.rb +67 -2
  305. data/test/cases/migration/invalid_options_test.rb +129 -0
  306. data/test/cases/migration/logger_test.rb +7 -4
  307. data/test/cases/migration/pending_migrations_test.rb +103 -60
  308. data/test/cases/migration/references_foreign_key_test.rb +73 -4
  309. data/test/cases/migration/references_index_test.rb +25 -27
  310. data/test/cases/migration/references_statements_test.rb +27 -3
  311. data/test/cases/migration/rename_table_test.rb +39 -54
  312. data/test/cases/migration/schema_definitions_test.rb +109 -0
  313. data/test/cases/migration/unique_constraint_test.rb +248 -0
  314. data/test/cases/migration_test.rb +677 -220
  315. data/test/cases/migrator_test.rb +102 -75
  316. data/test/cases/multi_db_migrator_test.rb +55 -34
  317. data/test/cases/multiparameter_attributes_test.rb +26 -29
  318. data/test/cases/multiple_db_test.rb +42 -19
  319. data/test/cases/nested_attributes_test.rb +124 -6
  320. data/test/cases/nested_attributes_with_callbacks_test.rb +2 -2
  321. data/test/cases/normalized_attribute_test.rb +117 -0
  322. data/test/cases/null_relation_test.rb +35 -2
  323. data/test/cases/persistence/reload_association_cache_test.rb +20 -0
  324. data/test/cases/persistence_test.rb +629 -22
  325. data/test/cases/pooled_connections_test.rb +57 -56
  326. data/test/cases/prepared_statement_status_test.rb +8 -3
  327. data/test/cases/primary_class_test.rb +134 -0
  328. data/test/cases/primary_keys_test.rb +171 -55
  329. data/test/cases/query_cache_test.rb +558 -263
  330. data/test/cases/query_logs_test.rb +293 -0
  331. data/test/cases/quoting_test.rb +39 -72
  332. data/test/cases/readonly_test.rb +50 -12
  333. data/test/cases/reaper_test.rb +22 -6
  334. data/test/cases/reflection_test.rb +207 -9
  335. data/test/cases/relation/and_test.rb +43 -0
  336. data/test/cases/relation/delegation_test.rb +32 -5
  337. data/test/cases/relation/delete_all_test.rb +27 -6
  338. data/test/cases/relation/field_ordered_values_test.rb +128 -0
  339. data/test/cases/relation/load_async_test.rb +650 -0
  340. data/test/cases/relation/merging_test.rb +80 -109
  341. data/test/cases/relation/mutation_test.rb +12 -7
  342. data/test/cases/relation/or_test.rb +11 -8
  343. data/test/cases/relation/order_test.rb +90 -0
  344. data/test/cases/relation/predicate_builder_test.rb +21 -6
  345. data/test/cases/relation/select_test.rb +162 -3
  346. data/test/cases/relation/structural_compatibility_test.rb +38 -0
  347. data/test/cases/relation/update_all_test.rb +81 -27
  348. data/test/cases/relation/where_chain_test.rb +190 -3
  349. data/test/cases/relation/where_clause_test.rb +43 -1
  350. data/test/cases/relation/where_test.rb +95 -7
  351. data/test/cases/relation/with_test.rb +165 -0
  352. data/test/cases/relation_test.rb +42 -37
  353. data/test/cases/relations_test.rb +436 -138
  354. data/test/cases/reload_models_test.rb +18 -14
  355. data/test/cases/reserved_word_test.rb +2 -1
  356. data/test/cases/result_test.rb +14 -22
  357. data/test/cases/sanitize_test.rb +89 -27
  358. data/test/cases/schema_dumper_test.rb +535 -62
  359. data/test/cases/scoping/default_scoping_test.rb +219 -35
  360. data/test/cases/scoping/named_scoping_test.rb +25 -46
  361. data/test/cases/scoping/relation_scoping_test.rb +112 -4
  362. data/test/cases/secure_password_test.rb +108 -0
  363. data/test/cases/secure_token_test.rb +72 -0
  364. data/test/cases/serialization_test.rb +1 -1
  365. data/test/cases/serialized_attribute_test.rb +305 -60
  366. data/test/cases/shard_keys_test.rb +125 -0
  367. data/test/cases/shard_selector_test.rb +45 -0
  368. data/test/cases/signed_id_test.rb +57 -5
  369. data/test/cases/statement_cache_test.rb +31 -30
  370. data/test/cases/statement_invalid_test.rb +8 -4
  371. data/test/cases/store_test.rb +73 -9
  372. data/test/cases/strict_loading_test.rb +327 -13
  373. data/test/cases/table_metadata_test.rb +16 -0
  374. data/test/cases/tasks/database_tasks_test.rb +517 -244
  375. data/test/cases/test_case.rb +254 -60
  376. data/test/cases/test_case_test.rb +69 -0
  377. data/test/cases/test_databases_test.rb +7 -3
  378. data/test/cases/test_fixtures_test.rb +19 -40
  379. data/test/cases/time_precision_test.rb +17 -5
  380. data/test/cases/timestamp_test.rb +124 -16
  381. data/test/cases/token_for_test.rb +165 -0
  382. data/test/cases/touch_later_test.rb +43 -1
  383. data/test/cases/transaction_callbacks_test.rb +325 -8
  384. data/test/cases/transaction_instrumentation_test.rb +453 -0
  385. data/test/cases/transaction_isolation_test.rb +12 -8
  386. data/test/cases/transactions_test.rb +629 -112
  387. data/test/cases/type/date_time_test.rb +7 -1
  388. data/test/cases/type/time_test.rb +9 -0
  389. data/test/cases/type/type_map_test.rb +108 -73
  390. data/test/cases/type/unsigned_integer_test.rb +12 -0
  391. data/test/cases/type_caster/connection_test.rb +19 -0
  392. data/test/cases/type_test.rb +1 -1
  393. data/test/cases/unconnected_test.rb +7 -7
  394. data/test/cases/unsafe_raw_sql_test.rb +39 -8
  395. data/test/cases/validations/absence_validation_test.rb +1 -1
  396. data/test/cases/validations/association_validation_test.rb +25 -3
  397. data/test/cases/validations/numericality_validation_test.rb +3 -9
  398. data/test/cases/validations/presence_validation_test.rb +1 -1
  399. data/test/cases/validations/uniqueness_validation_test.rb +280 -40
  400. data/test/cases/validations_test.rb +2 -2
  401. data/test/cases/view_test.rb +33 -22
  402. data/test/cases/yaml_serialization_test.rb +23 -17
  403. data/test/config.example.yml +58 -56
  404. data/test/config.rb +1 -0
  405. data/test/fixtures/1_need_quoting.yml +2 -0
  406. data/test/fixtures/accounts.yml +5 -0
  407. data/test/fixtures/aircrafts.yml +7 -0
  408. data/test/fixtures/book_identifiers.yml +11 -0
  409. data/test/fixtures/books.yml +5 -4
  410. data/test/fixtures/cake_designers.yml +5 -0
  411. data/test/fixtures/cars.yml +6 -0
  412. data/test/fixtures/chefs.yml +5 -0
  413. data/test/fixtures/clothing_items.yml +23 -0
  414. data/test/fixtures/clubs.yml +1 -1
  415. data/test/fixtures/comments.yml +2 -1
  416. data/test/fixtures/cpk_authors.yml +8 -0
  417. data/test/fixtures/cpk_books.yml +21 -0
  418. data/test/fixtures/cpk_order_agreements.yml +13 -0
  419. data/test/fixtures/cpk_order_tags.yml +15 -0
  420. data/test/fixtures/cpk_orders.yml +11 -0
  421. data/test/fixtures/cpk_posts.yml +12 -0
  422. data/test/fixtures/cpk_reviews.yml +13 -0
  423. data/test/fixtures/cpk_tags.yml +11 -0
  424. data/test/fixtures/drink_designers.yml +5 -0
  425. data/test/fixtures/encrypted_book_that_ignores_cases.yml +4 -0
  426. data/test/fixtures/encrypted_books.yml +4 -0
  427. data/test/fixtures/fk_object_to_point_to.yml +2 -0
  428. data/test/fixtures/memberships.yml +15 -15
  429. data/test/fixtures/paragraphs.yml +5 -0
  430. data/test/fixtures/parrots.yml +4 -0
  431. data/test/fixtures/people.yml +2 -0
  432. data/test/fixtures/pirates.yml +2 -2
  433. data/test/fixtures/primary_key_error/primary_key_error.yml +6 -0
  434. data/test/fixtures/references.yml +3 -3
  435. data/test/fixtures/sharded_blog_posts.yml +14 -0
  436. data/test/fixtures/sharded_blog_posts_tags.yml +27 -0
  437. data/test/fixtures/sharded_blogs.yml +8 -0
  438. data/test/fixtures/sharded_comments.yml +22 -0
  439. data/test/fixtures/sharded_tags.yml +34 -0
  440. data/test/fixtures/sponsors.yml +2 -2
  441. data/test/fixtures/topics.yml +1 -0
  442. data/test/fixtures/treasures.yml +4 -0
  443. data/test/fixtures/virtual_columns.yml +5 -0
  444. data/test/fixtures/warehouse_things.yml +1 -1
  445. data/test/migrations/old_and_new_versions/20210716122844_add_people_description.rb +5 -0
  446. data/test/migrations/old_and_new_versions/20210716123013_add_people_number_of_legs.rb +5 -0
  447. data/test/migrations/old_and_new_versions/230_add_people_hobby.rb +5 -0
  448. data/test/migrations/old_and_new_versions/231_add_people_last_name.rb +5 -0
  449. data/test/migrations/scope/1_unscoped.rb +7 -0
  450. data/test/migrations/scope/2_mysql_only.mysql.rb +7 -0
  451. data/test/models/admin/user.rb +2 -0
  452. data/test/models/admin/user_json.rb +48 -0
  453. data/test/models/attachment.rb +7 -0
  454. data/test/models/author.rb +70 -3
  455. data/test/models/author_encrypted.rb +16 -0
  456. data/test/models/bird.rb +1 -1
  457. data/test/models/book.rb +18 -11
  458. data/test/models/book_destroy_async.rb +1 -1
  459. data/test/models/book_encrypted.rb +106 -0
  460. data/test/models/book_identifier.rb +5 -0
  461. data/test/models/branch.rb +11 -0
  462. data/test/models/bulb.rb +1 -1
  463. data/test/models/car.rb +8 -1
  464. data/test/models/cat.rb +1 -1
  465. data/test/models/category.rb +3 -1
  466. data/test/models/chat_message.rb +8 -0
  467. data/test/models/chef.rb +52 -0
  468. data/test/models/clothing_item.rb +12 -0
  469. data/test/models/club.rb +4 -1
  470. data/test/models/comment.rb +7 -4
  471. data/test/models/comment_overlapping_counter_cache.rb +15 -0
  472. data/test/models/company.rb +16 -2
  473. data/test/models/computer.rb +1 -0
  474. data/test/models/contact.rb +3 -3
  475. data/test/models/contract.rb +5 -1
  476. data/test/models/cpk/author.rb +9 -0
  477. data/test/models/cpk/book.rb +55 -0
  478. data/test/models/cpk/book_destroy_async.rb +9 -0
  479. data/test/models/cpk/car.rb +9 -0
  480. data/test/models/cpk/car_review.rb +9 -0
  481. data/test/models/cpk/chapter.rb +16 -0
  482. data/test/models/cpk/chapter_destroy_async.rb +10 -0
  483. data/test/models/cpk/comment.rb +9 -0
  484. data/test/models/cpk/order.rb +55 -0
  485. data/test/models/cpk/order_agreement.rb +10 -0
  486. data/test/models/cpk/order_tag.rb +10 -0
  487. data/test/models/cpk/post.rb +10 -0
  488. data/test/models/cpk/posts_tag.rb +10 -0
  489. data/test/models/cpk/review.rb +9 -0
  490. data/test/models/cpk/tag.rb +10 -0
  491. data/test/models/cpk.rb +15 -0
  492. data/test/models/customer.rb +3 -1
  493. data/test/models/destroy_async_parent.rb +1 -1
  494. data/test/models/developer.rb +44 -3
  495. data/test/models/discount.rb +4 -0
  496. data/test/models/drink_designer.rb +1 -0
  497. data/test/models/editor.rb +8 -0
  498. data/test/models/editorship.rb +6 -0
  499. data/test/models/entry.rb +5 -0
  500. data/test/models/essay.rb +6 -1
  501. data/test/models/essay_destroy_async.rb +1 -0
  502. data/test/models/eye.rb +87 -21
  503. data/test/models/face.rb +1 -1
  504. data/test/models/friendship.rb +3 -0
  505. data/test/models/hardback.rb +7 -0
  506. data/test/models/hotel.rb +2 -0
  507. data/test/models/human.rb +2 -2
  508. data/test/models/invoice.rb +2 -1
  509. data/test/models/invokes_an_undefined_method.rb +5 -0
  510. data/test/models/line_item.rb +6 -0
  511. data/test/models/member.rb +9 -4
  512. data/test/models/membership.rb +2 -2
  513. data/test/models/message.rb +2 -1
  514. data/test/models/need_quoting.rb +5 -0
  515. data/test/models/paragraph.rb +5 -0
  516. data/test/models/parrot.rb +6 -3
  517. data/test/models/person.rb +7 -4
  518. data/test/models/pirate.rb +4 -1
  519. data/test/models/pk_autopopulated_by_a_trigger_record.rb +5 -0
  520. data/test/models/post.rb +65 -2
  521. data/test/models/post_encrypted.rb +15 -0
  522. data/test/models/post_with_prefetched_pk.rb +15 -0
  523. data/test/models/project.rb +1 -0
  524. data/test/models/publication.rb +16 -0
  525. data/test/models/raises_argument_error.rb +5 -0
  526. data/test/models/raises_no_method_error.rb +5 -0
  527. data/test/models/recipient.rb +5 -0
  528. data/test/models/reference.rb +1 -1
  529. data/test/models/reply.rb +1 -1
  530. data/test/models/room.rb +3 -0
  531. data/test/models/sharded/blog.rb +12 -0
  532. data/test/models/sharded/blog_post.rb +17 -0
  533. data/test/models/sharded/blog_post_destroy_async.rb +14 -0
  534. data/test/models/sharded/blog_post_tag.rb +11 -0
  535. data/test/models/sharded/blog_post_with_revision.rb +11 -0
  536. data/test/models/sharded/comment.rb +12 -0
  537. data/test/models/sharded/comment_destroy_async.rb +12 -0
  538. data/test/models/sharded/tag.rb +11 -0
  539. data/test/models/sharded.rb +8 -0
  540. data/test/models/ship.rb +1 -1
  541. data/test/models/shipping_line.rb +11 -0
  542. data/test/models/subscriber.rb +1 -0
  543. data/test/models/subscription.rb +3 -1
  544. data/test/models/too_long_table_name.rb +5 -0
  545. data/test/models/topic.rb +3 -1
  546. data/test/models/traffic_light.rb +2 -2
  547. data/test/models/traffic_light_encrypted.rb +21 -0
  548. data/test/models/translation.rb +9 -0
  549. data/test/models/treasure.rb +1 -1
  550. data/test/models/tyre.rb +1 -1
  551. data/test/models/user.rb +16 -0
  552. data/test/models/user_with_invalid_relation.rb +28 -0
  553. data/test/models/uuid_comment.rb +5 -0
  554. data/test/models/uuid_entry.rb +5 -0
  555. data/test/models/uuid_message.rb +5 -0
  556. data/test/models/zine.rb +2 -1
  557. data/test/schema/mysql2_specific_schema.rb +26 -12
  558. data/test/schema/postgresql_specific_schema.rb +121 -13
  559. data/test/schema/schema.rb +361 -103
  560. data/test/schema/sqlite_specific_schema.rb +17 -6
  561. data/test/schema/trilogy_specific_schema.rb +96 -0
  562. data/test/support/adapter_helper.rb +104 -0
  563. data/test/support/async_helper.rb +15 -0
  564. data/test/support/config.rb +1 -1
  565. data/test/support/connection.rb +14 -2
  566. data/test/support/ddl_helper.rb +1 -1
  567. data/test/support/fake_adapter.rb +42 -0
  568. data/test/support/load_schema_helper.rb +22 -0
  569. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_1_topic.dump +0 -0
  570. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_1_topic_associations.dump +0 -0
  571. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_7_1_topic.dump +0 -0
  572. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_7_1_topic_associations.dump +0 -0
  573. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_1_topic.dump +0 -0
  574. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_1_topic_associations.dump +0 -0
  575. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_7_1_topic.dump +0 -0
  576. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_7_1_topic_associations.dump +0 -0
  577. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_1_topic.dump +0 -0
  578. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_1_topic_associations.dump +0 -0
  579. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_7_1_topic.dump +0 -0
  580. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_7_1_topic_associations.dump +0 -0
  581. data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_1_topic.dump +0 -0
  582. data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_1_topic_associations.dump +0 -0
  583. data/test/support/marshal_compatibility_fixtures/SQLite/rails_7_1_topic.dump +0 -0
  584. data/test/support/marshal_compatibility_fixtures/SQLite/rails_7_1_topic_associations.dump +0 -0
  585. data/test/support/marshal_compatibility_fixtures/Trilogy/rails_6_1_topic.dump +0 -0
  586. data/test/support/marshal_compatibility_fixtures/Trilogy/rails_6_1_topic_associations.dump +0 -0
  587. data/test/support/marshal_compatibility_fixtures/Trilogy/rails_7_1_topic.dump +0 -0
  588. data/test/support/marshal_compatibility_fixtures/Trilogy/rails_7_1_topic_associations.dump +0 -0
  589. data/test/support/schema_dumping_helper.rb +15 -9
  590. data/test/support/tools.rb +37 -0
  591. data/test/support/yaml_compatibility_fixtures/rails_4_1_no_symbol.yml +22 -0
  592. metadata +247 -15
@@ -4,10 +4,11 @@ require "cases/helper"
4
4
  require "models/reply"
5
5
  require "models/topic"
6
6
  require "models/movie"
7
+ require "models/car"
7
8
 
8
9
  module ActiveRecord
9
10
  class DupTest < ActiveRecord::TestCase
10
- fixtures :topics
11
+ fixtures :topics, :cars
11
12
 
12
13
  def test_dup
13
14
  assert_not_predicate Topic.new.freeze.dup, :frozen?
@@ -25,7 +26,7 @@ module ActiveRecord
25
26
  topic.readonly!
26
27
 
27
28
  duped = topic.dup
28
- assert duped.readonly?, "should be readonly"
29
+ assert_predicate duped, :readonly?, "should be readonly"
29
30
  end
30
31
 
31
32
  def test_dup_not_persisted
@@ -33,7 +34,7 @@ module ActiveRecord
33
34
  duped = topic.dup
34
35
 
35
36
  assert_not duped.persisted?, "topic not persisted"
36
- assert duped.new_record?, "topic is new"
37
+ assert_predicate duped, :new_record?, "topic is new"
37
38
  end
38
39
 
39
40
  def test_dup_not_previously_new_record
@@ -118,6 +119,27 @@ module ActiveRecord
118
119
  assert_not_nil new_topic.created_at
119
120
  end
120
121
 
122
+ def test_dup_locking_column_is_cleared
123
+ car = Car.first
124
+ car.touch
125
+ assert_not_equal 0, car.lock_version
126
+
127
+ car.lock_version = 1000
128
+
129
+ new_car = car.dup
130
+ assert_equal 0, new_car.lock_version
131
+ end
132
+
133
+ def test_dup_locking_column_is_not_dirty
134
+ car = Car.first
135
+ car.touch
136
+ assert_not_equal 0, car.lock_version
137
+
138
+ car.lock_version += 1
139
+ new_car = car.dup
140
+ assert_not_predicate new_car, :lock_version_changed?
141
+ end
142
+
121
143
  def test_dup_after_initialize_callbacks
122
144
  topic = Topic.new
123
145
  assert Topic.after_initialize_called
@@ -145,7 +167,7 @@ module ActiveRecord
145
167
 
146
168
  def test_dup_with_default_scope
147
169
  prev_default_scopes = Topic.default_scopes
148
- Topic.default_scopes = [proc { Topic.where(approved: true) }]
170
+ Topic.default_scopes = [ActiveRecord::Scoping::DefaultScope.new(proc { Topic.where(approved: true) })]
149
171
  topic = Topic.new(approved: false)
150
172
  assert_not topic.dup.approved?, "should not be overridden by default scopes"
151
173
  ensure
@@ -153,8 +175,6 @@ module ActiveRecord
153
175
  end
154
176
 
155
177
  def test_dup_without_primary_key
156
- skip if current_adapter?(:OracleAdapter) or current_adapter?(:IBM_DBAdapter)
157
-
158
178
  klass = Class.new(ActiveRecord::Base) do
159
179
  self.table_name = "parrots_pirates"
160
180
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/encryption/helper"
4
+
5
+ class ActiveRecord::Encryption::Aes256GcmTest < ActiveRecord::EncryptionTestCase
6
+ setup do
7
+ @key = ActiveRecord::Encryption.key_generator.generate_random_key length: ActiveRecord::Encryption::Cipher::Aes256Gcm.key_length
8
+ @cipher = ActiveRecord::Encryption::Cipher::Aes256Gcm.new(@key)
9
+ end
10
+
11
+ test "encrypts strings" do
12
+ assert_cipher_encrypts(@cipher, "Some clear text")
13
+ end
14
+
15
+ test "works with empty strings" do
16
+ assert_cipher_encrypts(@cipher, "")
17
+ end
18
+
19
+ test "uses non-deterministic encryption by default" do
20
+ assert_not_equal @cipher.encrypt("Some text").payload, @cipher.encrypt("Some text").payload
21
+ end
22
+
23
+ test "in deterministic mode, it generates the same ciphertext for the same inputs" do
24
+ cipher = ActiveRecord::Encryption::Cipher::Aes256Gcm.new(@key, deterministic: true)
25
+
26
+ assert_cipher_encrypts(cipher, "Some clear text")
27
+
28
+ assert_equal cipher.encrypt("Some text").payload, cipher.encrypt("Some text").payload
29
+ assert_not_equal cipher.encrypt("Some text").payload, cipher.encrypt("Some other text").payload
30
+ end
31
+
32
+ test "it generates different ivs for different ciphertexts" do
33
+ cipher = ActiveRecord::Encryption::Cipher::Aes256Gcm.new(@key, deterministic: true)
34
+
35
+ assert_equal cipher.encrypt("Some text").headers.iv, cipher.encrypt("Some text").headers.iv
36
+ assert_not_equal cipher.encrypt("Some text").headers.iv, cipher.encrypt("Some other text").headers.iv
37
+ end
38
+
39
+ test "inspect_does not show secrets" do
40
+ cipher = ActiveRecord::Encryption::Cipher::Aes256Gcm.new(@key)
41
+ assert_match(/\A#<ActiveRecord::Encryption::Cipher::Aes256Gcm:0x[0-9a-f]+>\z/, cipher.inspect)
42
+ end
43
+
44
+ private
45
+ def assert_cipher_encrypts(cipher, content_to_encrypt)
46
+ encrypted_content = cipher.encrypt(content_to_encrypt)
47
+ assert_not_equal content_to_encrypt, encrypted_content
48
+ assert_equal content_to_encrypt, cipher.decrypt(encrypted_content)
49
+ end
50
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/encryption/helper"
4
+
5
+ class ActiveRecord::Encryption::CipherTest < ActiveRecord::EncryptionTestCase
6
+ setup do
7
+ @cipher = ActiveRecord::Encryption::Cipher.new
8
+ @key = ActiveRecord::Encryption.key_generator.generate_random_key
9
+ end
10
+
11
+ test "encrypts returns a encrypted test that can be decrypted with the same key" do
12
+ encrypted_text = @cipher.encrypt("clean text", key: @key)
13
+ assert_equal "clean text", @cipher.decrypt(encrypted_text, key: @key)
14
+ end
15
+
16
+ test "by default, encrypts uses random initialization vectors for each encryption operation" do
17
+ assert_not_equal @cipher.encrypt("clean text", key: @key), @cipher.encrypt("clean text", key: @key)
18
+ end
19
+
20
+ test "deterministic encryption with :deterministic param" do
21
+ assert_equal @cipher.encrypt("clean text", key: @key, deterministic: true).payload, @cipher.encrypt("clean text", key: @key, deterministic: true).payload
22
+ end
23
+
24
+ test "raises an ArgumentError when provided a key with the wrong length" do
25
+ assert_raises ArgumentError do
26
+ @cipher.encrypt("clean text", key: "invalid key")
27
+ end
28
+ end
29
+
30
+ test "iv_length returns the iv length of the cipher" do
31
+ assert_equal OpenSSL::Cipher.new("aes-256-gcm").iv_len, @cipher.iv_length
32
+ end
33
+
34
+ test "generates different ciphertexts on different invocations with the same key (not deterministic)" do
35
+ key = SecureRandom.bytes(32)
36
+ assert_not_equal @cipher.encrypt("clean text", key: key), @cipher.encrypt("clean text", key: key)
37
+ end
38
+
39
+ test "decrypt can work with multiple keys" do
40
+ encrypted_text = @cipher.encrypt("clean text", key: @key)
41
+
42
+ assert_equal "clean text", @cipher.decrypt(encrypted_text, key: [ "some wrong key", @key ])
43
+ assert_equal "clean text", @cipher.decrypt(encrypted_text, key: [ "some wrong key", @key, "some other wrong key" ])
44
+ assert_equal "clean text", @cipher.decrypt(encrypted_text, key: [ @key, "some wrong key", "some other wrong key" ])
45
+ end
46
+
47
+ test "decrypt will raise an ActiveRecord::Encryption::Errors::Decryption error when none of the keys works" do
48
+ encrypted_text = @cipher.encrypt("clean text", key: @key)
49
+
50
+ assert_raises ActiveRecord::Encryption::Errors::Decryption do
51
+ @cipher.decrypt(encrypted_text, key: [ "some wrong key", "other wrong key" ])
52
+ end
53
+ end
54
+
55
+ test "keep encoding from the source string" do
56
+ encrypted_text = @cipher.encrypt("some string".dup.force_encoding(Encoding::ISO_8859_1), key: @key)
57
+ decrypted_text = @cipher.decrypt(encrypted_text, key: @key)
58
+ assert_equal Encoding::ISO_8859_1, decrypted_text.encoding
59
+ end
60
+
61
+ test "can encode unicode strings with emojis" do
62
+ encrypted_text = @cipher.encrypt("Getting around with the ⚡️Go Menu", key: @key)
63
+ assert_equal "Getting around with the ⚡️Go Menu", @cipher.decrypt(encrypted_text, key: @key)
64
+ end
65
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/encryption/helper"
4
+ require "models/post_encrypted"
5
+
6
+ class ActiveRecord::Encryption::ConcurrencyTest < ActiveRecord::EncryptionTestCase
7
+ setup do
8
+ ActiveRecord::Encryption.config.support_unencrypted_data = true
9
+ end
10
+
11
+ test "models can be encrypted and decrypted in different threads concurrently" do
12
+ 4.times.collect { |index| thread_encrypting_and_decrypting("thread #{index}") }.each(&:join)
13
+ end
14
+
15
+ def thread_encrypting_and_decrypting(thread_label)
16
+ EncryptedPost.insert_all! 100.times.collect { |index| { title: "Article #{index} (#{thread_label})", body: "Body #{index} (#{thread_label})" } }
17
+ posts = EncryptedPost.last(100)
18
+
19
+ Thread.new do
20
+ posts.each.with_index do |article, index|
21
+ assert_encrypted_attribute article, :title, "Article #{index} (#{thread_label})"
22
+ article.decrypt
23
+ assert_not_encrypted_attribute article, :title, "Article #{index} (#{thread_label})"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/encryption/helper"
4
+
5
+ class ActiveRecord::Encryption::ConfigTest < ActiveRecord::EncryptionTestCase
6
+ setup do
7
+ @config = ActiveRecord::Encryption::Config.new
8
+ end
9
+
10
+ test "required keys will raise a config error when accessed but not set" do
11
+ @config.primary_key = nil
12
+ assert_raises ActiveRecord::Encryption::Errors::Configuration do
13
+ @config.primary_key
14
+ end
15
+
16
+ @config.primary_key = "some key"
17
+ assert_nothing_raised do
18
+ @config.primary_key
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/encryption/helper"
4
+ require "models/pirate"
5
+ require "models/book"
6
+
7
+ class ActiveRecord::Encryption::ConfigurableTest < ActiveRecord::EncryptionTestCase
8
+ test "can access context properties with top level getters" do
9
+ assert_equal ActiveRecord::Encryption.key_provider, ActiveRecord::Encryption.context.key_provider
10
+ end
11
+
12
+ test ".configure configures initial config properties" do
13
+ previous_key_provider = ActiveRecord::Encryption::DerivedSecretKeyProvider.new("some secret")
14
+
15
+ ActiveRecord::Encryption.configure \
16
+ primary_key: "the primary key",
17
+ deterministic_key: "the deterministic key",
18
+ key_derivation_salt: "the salt",
19
+ previous: [{ key_provider: previous_key_provider }]
20
+
21
+ config = ActiveRecord::Encryption.config
22
+
23
+ assert_equal "the primary key", config.primary_key
24
+ assert_equal "the deterministic key", config.deterministic_key
25
+ assert_equal "the salt", config.key_derivation_salt
26
+ assert_equal previous_key_provider, config.previous_schemes.first.key_provider
27
+ end
28
+
29
+ test "can add listeners that will get invoked when declaring encrypted attributes" do
30
+ @klass, @attribute_name = nil
31
+ ActiveRecord::Encryption.on_encrypted_attribute_declared do |declared_klass, declared_attribute_name|
32
+ @klass = declared_klass
33
+ @attribute_name = declared_attribute_name
34
+ end
35
+
36
+ klass = Class.new(Book) do
37
+ encrypts :isbn
38
+ end
39
+
40
+ assert_equal klass, @klass
41
+ assert_equal :isbn, @attribute_name
42
+ end
43
+
44
+ test "installing autofiltered parameters will add the encrypted attribute as a filter parameter using the dot notation" do
45
+ application = Struct.new(:config).new(Struct.new(:filter_parameters).new([]))
46
+
47
+ with_auto_filtered_parameters(application) do
48
+ NamedPirate = Class.new(Pirate) do
49
+ self.table_name = "pirates"
50
+ end
51
+ NamedPirate.encrypts :catchphrase
52
+ end
53
+
54
+ assert_includes application.config.filter_parameters, "named_pirate.catchphrase"
55
+ end
56
+
57
+ test "installing autofiltered parameters will work with unnamed classes" do
58
+ application = Struct.new(:config).new(Struct.new(:filter_parameters).new([]))
59
+
60
+ with_auto_filtered_parameters(application) do
61
+ Class.new(Pirate) do
62
+ self.table_name = "pirates"
63
+ encrypts :catchphrase
64
+ end
65
+ end
66
+
67
+ assert_includes application.config.filter_parameters, "catchphrase"
68
+ end
69
+
70
+ test "exclude the installation of autofiltered params" do
71
+ ActiveRecord::Encryption.config.excluded_from_filter_parameters = [:catchphrase]
72
+
73
+ application = Struct.new(:config).new(Struct.new(:filter_parameters).new([]))
74
+
75
+ with_auto_filtered_parameters(application) do
76
+ Class.new(Pirate) do
77
+ self.table_name = "pirates"
78
+ encrypts :catchphrase
79
+ end
80
+ end
81
+
82
+ assert_equal [], application.config.filter_parameters
83
+
84
+ ActiveRecord::Encryption.config.excluded_from_filter_parameters = []
85
+ end
86
+
87
+ private
88
+ def with_auto_filtered_parameters(application)
89
+ auto_filtered_parameters = ActiveRecord::Encryption::AutoFilteredParameters.new(application)
90
+ yield
91
+ auto_filtered_parameters.enable
92
+ end
93
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/encryption/helper"
4
+ require "models/book_encrypted"
5
+ require "models/post_encrypted"
6
+
7
+ class ActiveRecord::Encryption::ContextsTest < ActiveRecord::EncryptionTestCase
8
+ fixtures :posts
9
+
10
+ setup do
11
+ ActiveRecord::Encryption.config.support_unencrypted_data = true
12
+
13
+ @post = EncryptedPost.create!(title: "Some encrypted post title", body: "Some body")
14
+ @title_cleartext = @post.title
15
+ @title_ciphertext = @post.ciphertext_for(:title)
16
+ end
17
+
18
+ test ".with_encryption_context lets you override properties" do
19
+ ActiveRecord::Encryption.with_encryption_context(encryptor: ActiveRecord::Encryption::NullEncryptor.new) do
20
+ assert_equal @title_ciphertext, @post.reload.title
21
+
22
+ @post.update!(title: "Some new title")
23
+ end
24
+
25
+ assert_equal "Some new title", @post.title_before_type_cast
26
+ end
27
+
28
+ test ".with_encryption_context will restore previous context properties when there is an error" do
29
+ ActiveRecord::Encryption.with_encryption_context(encryptor: ActiveRecord::Encryption::NullEncryptor.new) do
30
+ raise "Some error"
31
+ end
32
+ rescue
33
+ assert_encrypted_attribute @post.reload, :title, @title_cleartext
34
+ end
35
+
36
+ test ".with_encryption_context can be nested multiple times" do
37
+ ActiveRecord::Encryption.with_encryption_context(encryptor: encryptor_1 = ActiveRecord::Encryption::NullEncryptor.new) do
38
+ assert_equal encryptor_1, ActiveRecord::Encryption.encryptor
39
+
40
+ ActiveRecord::Encryption.with_encryption_context(encryptor: encryptor_2 = ActiveRecord::Encryption::NullEncryptor.new) do
41
+ assert_equal encryptor_2, ActiveRecord::Encryption.encryptor
42
+
43
+ ActiveRecord::Encryption.with_encryption_context(encryptor: encryptor_3 = ActiveRecord::Encryption::NullEncryptor.new) do
44
+ assert_equal encryptor_3, ActiveRecord::Encryption.encryptor
45
+ end
46
+
47
+ assert_equal encryptor_2, ActiveRecord::Encryption.encryptor
48
+ end
49
+
50
+ assert_equal encryptor_1, ActiveRecord::Encryption.encryptor
51
+ end
52
+ end
53
+
54
+ test ".without_encryption won't decrypt or encrypt data automatically" do
55
+ ActiveRecord::Encryption.without_encryption do
56
+ assert_equal @title_ciphertext, @post.reload.title
57
+
58
+ @post.update!(title: "Some new title")
59
+ end
60
+
61
+ assert_not_encrypted_attribute @post, :title, "Some new title"
62
+ end
63
+
64
+ test ".without_encryption doesn't raise on binary encoded data" do
65
+ assert_nothing_raised do
66
+ ActiveRecord::Encryption.without_encryption do
67
+ EncryptedBook.create!(name: "Dune".encode(Encoding::BINARY))
68
+ end
69
+ end
70
+ end
71
+
72
+ test ".protecting_encrypted_data don't decrypt attributes automatically" do
73
+ ActiveRecord::Encryption.protecting_encrypted_data do
74
+ assert_equal @title_ciphertext, @post.reload.title
75
+ end
76
+ end
77
+
78
+ test ".protecting_encrypted_data allows db-queries on deterministic attributes" do
79
+ book = EncryptedBook.create! name: "Dune"
80
+
81
+ ActiveRecord::Encryption.protecting_encrypted_data do
82
+ assert_equal book, EncryptedBook.find_by(name: "Dune")
83
+ end
84
+ end
85
+
86
+ test "can't encrypt or decrypt in protected mode" do
87
+ ActiveRecord::Encryption.protecting_encrypted_data do
88
+ assert_raises ActiveRecord::Encryption::Errors::Configuration do
89
+ @post.encrypt
90
+ end
91
+
92
+ assert_raises ActiveRecord::Encryption::Errors::Configuration do
93
+ @post.decrypt
94
+ end
95
+ end
96
+ end
97
+
98
+ test ".protecting_encrypted_data will raise a validation error when modifying encrypting attributes" do
99
+ ActiveRecord::Encryption.protecting_encrypted_data do
100
+ assert_raises ActiveRecord::RecordInvalid do
101
+ @post.update!(title: "Some new title")
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/encryption/helper"
4
+
5
+ class ActiveRecord::Encryption::DerivedSecretKeyProviderTest < ActiveRecord::EncryptionTestCase
6
+ setup do
7
+ @message ||= ActiveRecord::Encryption::Message.new(payload: "some secret")
8
+ @keys = build_keys(3)
9
+ @key_provider = ActiveRecord::Encryption::KeyProvider.new(@keys)
10
+ end
11
+
12
+ test "will derive a key with the right length from the given password" do
13
+ key_provider = ActiveRecord::Encryption::DerivedSecretKeyProvider.new("some password")
14
+ key = key_provider.encryption_key
15
+
16
+ assert_equal [ key ], key_provider.decryption_keys(ActiveRecord::Encryption::Message.new(payload: "some secret"))
17
+ assert_equal ActiveRecord::Encryption.cipher.key_length, key.secret.bytesize
18
+ end
19
+
20
+ test "work with multiple keys when config.store_key_references is false" do
21
+ ActiveRecord::Encryption.config.store_key_references = false
22
+
23
+ assert_encryptor_works_with @key_provider
24
+ end
25
+
26
+ test "work with multiple keys when config.store_key_references is true" do
27
+ ActiveRecord::Encryption.config.store_key_references = true
28
+
29
+ assert_encryptor_works_with @key_provider
30
+ end
31
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/encryption/helper"
4
+
5
+ class ActiveRecord::Encryption::DeterministicKeyProviderTest < ActiveRecord::EncryptionTestCase
6
+ test "will raise a configuration error when trying to configure multiple keys" do
7
+ assert_raise ActiveRecord::Encryption::Errors::Configuration do
8
+ ActiveRecord::Encryption::DeterministicKeyProvider.new([ "secret 1", "secret 2" ])
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,175 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/encryption/helper"
4
+ require "models/author_encrypted"
5
+ require "models/book_encrypted"
6
+ require "models/post_encrypted"
7
+
8
+ class ActiveRecord::Encryption::EncryptableRecordApiTest < ActiveRecord::EncryptionTestCase
9
+ fixtures :posts
10
+
11
+ setup do
12
+ ActiveRecord::Encryption.config.support_unencrypted_data = true
13
+ end
14
+
15
+ test "encrypt encrypts all the encryptable attributes" do
16
+ title = "The Starfleet is here!"
17
+ body = "<p>the Starfleet is here, we are safe now!</p>"
18
+
19
+ post = ActiveRecord::Encryption.without_encryption do
20
+ EncryptedPost.create! title: title, body: body
21
+ end
22
+
23
+ post.encrypt
24
+
25
+ assert_encrypted_attribute(post, :title, title)
26
+ assert_encrypted_attribute(post, :body, body)
27
+ end
28
+
29
+ test "encrypt won't fail for classes without attributes to encrypt" do
30
+ assert_nothing_raised do
31
+ posts(:welcome).encrypt
32
+ end
33
+ end
34
+
35
+ test "decrypt decrypts encrypted attributes" do
36
+ title = "the Starfleet is here!"
37
+ body = "<p>the Starfleet is here, we are safe now!</p>"
38
+ post = EncryptedPost.create! title: title, body: body
39
+ assert_encrypted_attribute(post, :title, title)
40
+ assert_encrypted_attribute(post, :body, body)
41
+
42
+ post.decrypt
43
+
44
+ assert_not_encrypted_attribute post.reload, :title, title
45
+ assert_not_encrypted_attribute post, :body, body
46
+ end
47
+
48
+ test "decrypt can be invoked multiple times" do
49
+ post = EncryptedPost.create! title: "the Starfleet is here", body: "<p>the Starfleet is here, we are safe now!</p>"
50
+
51
+ 3.times { post.decrypt }
52
+
53
+ assert_not_encrypted_attribute post.reload, :title, "the Starfleet is here"
54
+ assert_not_encrypted_attribute post, :body, "<p>the Starfleet is here, we are safe now!</p>"
55
+ end
56
+
57
+ test "encrypt can be invoked multiple times" do
58
+ post = EncryptedPost.create! title: "the Starfleet is here", body: "<p>the Starfleet is here, we are safe now!</p>"
59
+
60
+ 3.times { post.encrypt }
61
+
62
+ assert_encrypted_attribute post.reload, :title, "the Starfleet is here"
63
+ assert_encrypted_attribute post, :body, "<p>the Starfleet is here, we are safe now!</p>"
64
+ end
65
+
66
+ test "encrypted_attribute? returns false for regular attributes" do
67
+ book = EncryptedBook.new(created_at: 1.day.ago)
68
+ assert_not book.encrypted_attribute?(:created_at)
69
+ end
70
+
71
+ test "encrypted_attribute? returns true for encrypted attributes which content is encrypted" do
72
+ book = EncryptedBook.create!(name: "Dune")
73
+ assert book.encrypted_attribute?(:name)
74
+ end
75
+
76
+ test "encrypted_attribute? returns false for encrypted attributes which content is not encrypted" do
77
+ book = ActiveRecord::Encryption.without_encryption { EncryptedBook.create!(name: "Dune") }
78
+ assert_not book.encrypted_attribute?(:name)
79
+ end
80
+
81
+ test "ciphertext_for returns the ciphertext for a given attribute" do
82
+ book = EncryptedBook.create!(name: "Dune")
83
+
84
+ assert_ciphertext_decrypts_to book, :name, book.ciphertext_for(:name)
85
+ end
86
+
87
+ test "ciphertext_for returns the persisted ciphertext for a non-deterministically encrypted attribute" do
88
+ post = EncryptedPost.create!(title: "Fear is the mind-killer", body: "Fear is the little-death...")
89
+
90
+ assert_equal post.title_before_type_cast, post.ciphertext_for(:title)
91
+ assert_ciphertext_decrypts_to post, :title, post.ciphertext_for(:title)
92
+ end
93
+
94
+ test "ciphertext_for returns the ciphertext of a new value" do
95
+ book = EncryptedBook.create!(name: "Dune")
96
+ book.name = "Arrakis"
97
+
98
+ assert_ciphertext_decrypts_to book, :name, book.ciphertext_for(:name)
99
+ end
100
+
101
+ test "ciphertext_for returns the ciphertext of a decrypted value" do
102
+ book = EncryptedBook.create!(name: "Dune")
103
+ book.decrypt
104
+
105
+ assert_ciphertext_decrypts_to book, :name, book.ciphertext_for(:name)
106
+ end
107
+
108
+ test "ciphertext_for returns the ciphertext of a value when the record is new" do
109
+ book = EncryptedBook.new(name: "Dune")
110
+
111
+ assert_ciphertext_decrypts_to book, :name, book.ciphertext_for(:name)
112
+ end
113
+
114
+ test "encrypt won't change the encoding of strings even when compression is used" do
115
+ title = "The Starfleet is here #{'OMG👌' * 50}!"
116
+ encoding = title.encoding
117
+ post = ActiveRecord::Encryption.without_encryption { EncryptedPost.create!(title: title, body: "some body") }
118
+ post.encrypt
119
+ assert_equal encoding, post.reload.title.encoding
120
+ end
121
+
122
+ test "encrypt will honor forced encoding for deterministic attributes" do
123
+ ActiveRecord::Encryption.config.forced_encoding_for_deterministic_encryption = Encoding::UTF_8
124
+
125
+ book = ActiveRecord::Encryption.without_encryption { EncryptedBook.create!(name: "Dune".encode("US-ASCII")) }
126
+ book.encrypt
127
+ assert_equal Encoding::UTF_8, book.reload.name.encoding
128
+ end
129
+
130
+ test "encrypt won't force encoding for deterministic attributes when option is nil" do
131
+ ActiveRecord::Encryption.config.forced_encoding_for_deterministic_encryption = nil
132
+
133
+ book = ActiveRecord::Encryption.without_encryption { EncryptedBook.create!(name: "Dune".encode("US-ASCII")) }
134
+ book.encrypt
135
+ assert_equal Encoding::US_ASCII, book.reload.name.encoding
136
+ end
137
+
138
+ test "encrypt will preserve case when :ignore_case option is used" do
139
+ ActiveRecord::Encryption.config.support_unencrypted_data = true
140
+
141
+ book = create_unencrypted_book_ignoring_case name: "Dune"
142
+
143
+ ActiveRecord::Encryption.without_encryption { assert_equal "Dune", book.reload.name }
144
+ assert_equal "Dune", book.name
145
+
146
+ book.encrypt
147
+
148
+ assert_equal "Dune", book.reload.name
149
+ end
150
+
151
+ test "re-encrypting will preserve case when :ignore_case option is used" do
152
+ ActiveRecord::Encryption.config.support_unencrypted_data = true
153
+
154
+ book = create_unencrypted_book_ignoring_case name: "Dune"
155
+
156
+ ActiveRecord::Encryption.without_encryption { assert_equal "Dune", book.reload.name }
157
+ assert_equal "Dune", book.name
158
+
159
+ 2.times { book.encrypt }
160
+
161
+ assert_equal "Dune", book.reload.name
162
+ end
163
+
164
+ test "encrypt attributes encrypted with a previous encryption scheme" do
165
+ author = EncryptedAuthor.create!(name: "david")
166
+ old_type = EncryptedAuthor.type_for_attribute(:name).previous_types.first
167
+ value_encrypted_with_old_type = old_type.serialize("dhh")
168
+ ActiveRecord::Encryption.without_encryption do
169
+ author.update!(name: value_encrypted_with_old_type)
170
+ end
171
+
172
+ author.reload.encrypt
173
+ assert_equal "dhh", author.reload.name
174
+ end
175
+ end