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
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/encryption/helper"
4
+ require "models/author_encrypted"
5
+ require "models/book_encrypted"
6
+ require "active_record/encryption/message_pack_message_serializer"
7
+
8
+ class ActiveRecord::Encryption::EncryptableRecordMessagePackSerializedTest < ActiveRecord::EncryptionTestCase
9
+ fixtures :encrypted_books
10
+
11
+ test "binary data can be serialized with message pack" do
12
+ all_bytes = (0..255).map(&:chr).join
13
+ book = EncryptedBookWithBinaryMessagePackSerialized.create!(logo: all_bytes)
14
+ assert_encrypted_attribute(book, :logo, all_bytes)
15
+ end
16
+
17
+ test "binary data can be encrypted uncompressed and serialized with message pack" do
18
+ # Strings below 140 bytes are not compressed
19
+ low_bytes = (0..127).map(&:chr).join
20
+ high_bytes = (128..255).map(&:chr).join
21
+
22
+ assert_encrypted_attribute(EncryptedBookWithBinaryMessagePackSerialized.create!(logo: low_bytes), :logo, low_bytes)
23
+ assert_encrypted_attribute(EncryptedBookWithBinaryMessagePackSerialized.create!(logo: high_bytes), :logo, high_bytes)
24
+ end
25
+
26
+ test "text columns cannot be serialized with message pack" do
27
+ assert_raises(ActiveRecord::Encryption::Errors::Encoding) do
28
+ message_pack_serialized_text_class = Class.new(ActiveRecord::Base) do
29
+ self.table_name = "encrypted_books"
30
+
31
+ encrypts :name, message_serializer: ActiveRecord::Encryption::MessagePackMessageSerializer.new
32
+ end
33
+ message_pack_serialized_text_class.create(name: "Dune")
34
+ end
35
+ end
36
+
37
+ class EncryptedBookWithBinaryMessagePackSerialized < ActiveRecord::Base
38
+ self.table_name = "encrypted_books"
39
+
40
+ encrypts :logo, message_serializer: ActiveRecord::Encryption::MessagePackMessageSerializer.new
41
+ end
42
+ end
@@ -0,0 +1,470 @@
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
+ require "models/traffic_light_encrypted"
8
+
9
+ class ActiveRecord::Encryption::EncryptableRecordTest < ActiveRecord::EncryptionTestCase
10
+ fixtures :encrypted_books, :posts
11
+
12
+ test "encrypts the attribute seamlessly when creating and updating records" do
13
+ post = EncryptedPost.create!(title: "The Starfleet is here!", body: "take cover!")
14
+ assert_encrypted_attribute(post, :title, "The Starfleet is here!")
15
+
16
+ post.update!(title: "The Klingons are coming!")
17
+ assert_encrypted_attribute(post, :title, "The Klingons are coming!")
18
+
19
+ post.title = "You sure?"
20
+ post.save!
21
+ assert_encrypted_attribute(post, :title, "You sure?")
22
+
23
+ post[:title] = "The Klingons are leaving!"
24
+ post.save!
25
+ assert_encrypted_attribute(post, :title, "The Klingons are leaving!")
26
+ end
27
+
28
+ test "attribute is not accessible with the wrong key" do
29
+ ActiveRecord::Encryption.config.support_unencrypted_data = false
30
+
31
+ post = EncryptedPost.create!(title: "The Starfleet is here!", body: "take cover!")
32
+ post.reload.tags_count # accessing regular attributes works
33
+ assert_invalid_key_cant_read_attribute(post, :body)
34
+ end
35
+
36
+ test "swapping key_providers via with_encryption_context" do
37
+ key_provider1 = ActiveRecord::Encryption::DerivedSecretKeyProvider.new(SecureRandom.base64(32))
38
+ key_provider2 = ActiveRecord::Encryption::DerivedSecretKeyProvider.new(SecureRandom.base64(32))
39
+
40
+ post1 = post2 = nil
41
+
42
+ ActiveRecord::Encryption.with_encryption_context key_provider: key_provider1 do
43
+ post1 = EncryptedPost.create!(title: "post1!", body: "first post!")
44
+ end
45
+
46
+ ActiveRecord::Encryption.with_encryption_context key_provider: key_provider2 do
47
+ post2 = EncryptedPost.create!(title: "post2!", body: "second post!")
48
+ end
49
+
50
+ post1.reload
51
+ assert_raises ActiveRecord::Encryption::Errors::Decryption do
52
+ post1.title
53
+ end
54
+
55
+ post2.reload
56
+ assert_raises ActiveRecord::Encryption::Errors::Decryption do
57
+ post2.title
58
+ end
59
+
60
+ ActiveRecord::Encryption.with_encryption_context key_provider: key_provider1 do
61
+ post1.reload
62
+ assert_equal "post1!", post1.title
63
+
64
+ post2.reload
65
+ assert_raises ActiveRecord::Encryption::Errors::Decryption do
66
+ post2.title
67
+ end
68
+ end
69
+
70
+ ActiveRecord::Encryption.with_encryption_context key_provider: key_provider2 do
71
+ post2.reload
72
+ assert_equal "post2!", post2.title
73
+
74
+ post1.reload
75
+ assert_raises ActiveRecord::Encryption::Errors::Decryption do
76
+ post1.title
77
+ end
78
+ end
79
+ end
80
+
81
+ test "ignores nil values" do
82
+ assert_nil EncryptedBook.create!(name: nil).name
83
+ end
84
+
85
+ test "ignores empty values" do
86
+ assert_equal "", EncryptedBook.create!(name: "").name
87
+ end
88
+
89
+ test "encrypts serialized attributes" do
90
+ states = ["green", "red"]
91
+ traffic_light = EncryptedTrafficLight.create!(state: states, long_state: states)
92
+ assert_encrypted_attribute(traffic_light, :state, states)
93
+ end
94
+
95
+ test "encrypts serialized attributes where encrypts is declared first" do
96
+ states = ["green", "red"]
97
+ traffic_light = EncryptedFirstTrafficLight.create!(state: states, long_state: states)
98
+ assert_encrypted_attribute(traffic_light, :state, states)
99
+ end
100
+
101
+ test "encrypts store attributes with accessors" do
102
+ traffic_light = EncryptedTrafficLightWithStoreState.create!(color: "red", long_state: ["green", "red"])
103
+ assert_equal "red", traffic_light.color
104
+ assert_encrypted_attribute(traffic_light, :state, { "color" => "red" })
105
+ end
106
+
107
+ test "can configure a custom key provider on a per-record-class basis through the :key_provider option" do
108
+ post = EncryptedPost.create!(title: "The Starfleet is here!", body: "take cover!")
109
+ assert_encrypted_attribute(post, :body, "take cover!")
110
+ end
111
+
112
+ test "can configure a custom key on a per-record-class basis through the :key option" do
113
+ author = EncryptedAuthorWithKey.create!(name: "Stephen King")
114
+ assert_encrypted_attribute(author, :name, "Stephen King")
115
+ end
116
+
117
+ test "encrypts multiple attributes with different options at the same time" do
118
+ post = EncryptedPost.create! \
119
+ title: title = "The Starfleet is here!",
120
+ body: body = "<p>the Starfleet is here, we are safe now!</p>"
121
+
122
+ assert_encrypted_attribute(post, :title, title)
123
+ assert_encrypted_attribute(post, :body, body)
124
+ end
125
+
126
+ test "encrypted_attributes returns the list of encrypted attributes in a model (each record class holds their own list)" do
127
+ assert_equal Set.new([:title, :body]), EncryptedPost.encrypted_attributes
128
+ assert_not_equal EncryptedAuthor.encrypted_attributes, EncryptedPost.encrypted_attributes
129
+ end
130
+
131
+ test "deterministic_encrypted_attributes returns the list of deterministic encrypted attributes in a model (each record class holds their own list)" do
132
+ assert_equal [:name], EncryptedBook.deterministic_encrypted_attributes
133
+ assert_not_equal EncryptedPost.deterministic_encrypted_attributes, EncryptedBook.deterministic_encrypted_attributes
134
+ end
135
+
136
+ test "by default, encryption is not deterministic" do
137
+ post_1 = EncryptedPost.create!(title: "the same title", body: "some body")
138
+ post_2 = EncryptedPost.create!(title: "the same title", body: "some body")
139
+
140
+ assert_not_equal post_1.ciphertext_for(:title), post_2.ciphertext_for(:title)
141
+ end
142
+
143
+ test "deterministic attributes can be searched with Active Record queries" do
144
+ EncryptedBook.create!(name: "Dune")
145
+
146
+ assert EncryptedBook.find_by(name: "Dune")
147
+ assert_not EncryptedBook.find_by(name: "not Dune")
148
+
149
+ assert_equal 1, EncryptedBook.where(name: "Dune").count
150
+ end
151
+
152
+ test "deterministic attributes can be created by passing deterministic: true" do
153
+ book_1 = EncryptedBook.create!(name: "Dune")
154
+ book_2 = EncryptedBook.create!(name: "Dune")
155
+
156
+ assert_equal book_1.ciphertext_for(:name), book_2.ciphertext_for(:name)
157
+ end
158
+
159
+ test "deterministic ciphertexts remain constant" do
160
+ # We need to make sure these don't change or existing apps will stop working
161
+ ciphertext = "{\"p\":\"DIohhw==\",\"h\":{\"iv\":\"wEPaDcJP3VNIxaiz\",\"at\":\"X7+2xvvcu1k1if6Dy28Esw==\"}}"
162
+ book = UnencryptedBook.create name: ciphertext
163
+
164
+ book = EncryptedBook.find(book.id)
165
+ assert_equal "Dune", book.name
166
+ end
167
+
168
+ test "encryption errors when saving records will raise the error and don't save anything" do
169
+ assert_no_changes -> { BookThatWillFailToEncryptName.count } do
170
+ assert_raises ActiveRecord::Encryption::Errors::Encryption do
171
+ BookThatWillFailToEncryptName.create!(name: "Dune")
172
+ end
173
+ end
174
+ end
175
+
176
+ test "can work with pre-encryption nil values" do
177
+ ActiveRecord::Encryption.config.support_unencrypted_data = true
178
+ book = ActiveRecord::Encryption.without_encryption { EncryptedBook.create!(name: nil) }
179
+ assert_nil book.name
180
+ end
181
+
182
+ test "can work with pre-encryption empty values" do
183
+ ActiveRecord::Encryption.config.support_unencrypted_data = true
184
+ book = ActiveRecord::Encryption.without_encryption { EncryptedBook.create!(name: "") }
185
+ assert_equal "", book.name
186
+ end
187
+
188
+ test "can't modify encrypted attributes when frozen_encryption is true" do
189
+ post = posts(:welcome).becomes(EncryptedPost)
190
+ post.title = "Some new title"
191
+ assert_predicate post, :valid?
192
+
193
+ ActiveRecord::Encryption.with_encryption_context frozen_encryption: true do
194
+ assert_not post.valid?
195
+ end
196
+ end
197
+
198
+ test "can only save unencrypted attributes when frozen encryption is true" do
199
+ book = encrypted_books(:awdr)
200
+
201
+ ActiveRecord::Encryption.with_encryption_context frozen_encryption: true do
202
+ book.update! updated_at: Time.now
203
+ end
204
+
205
+ ActiveRecord::Encryption.with_encryption_context frozen_encryption: true do
206
+ assert_raises ActiveRecord::RecordInvalid do
207
+ book.update! name: "Some new title"
208
+ end
209
+ end
210
+ end
211
+
212
+ test "won't change the encoding of strings" do
213
+ author_name = "Jorge"
214
+ encoding = author_name.encoding
215
+ author = EncryptedAuthor.create!(name: author_name)
216
+ assert_equal encoding, author.reload.name.encoding
217
+ end
218
+
219
+ test "by default, it's case sensitive" do
220
+ EncryptedBook.create!(name: "Dune")
221
+ assert EncryptedBook.find_by(name: "Dune")
222
+ assert_not EncryptedBook.find_by(name: "dune")
223
+ end
224
+
225
+ test "when using downcase: true it ignores case since everything will be downcase" do
226
+ EncryptedBookWithDowncaseName.create!(name: "Dune")
227
+ assert EncryptedBookWithDowncaseName.find_by(name: "Dune")
228
+ assert EncryptedBookWithDowncaseName.find_by(name: "dune")
229
+ assert EncryptedBookWithDowncaseName.find_by(name: "DUNE")
230
+ end
231
+
232
+ test "when downcase: true it creates content downcased" do
233
+ EncryptedBookWithDowncaseName.create!(name: "Dune")
234
+ assert EncryptedBookWithDowncaseName.find_by_name("dune")
235
+ end
236
+
237
+ test "when ignore_case: true, it ignores case in queries but keep it when reading the attribute" do
238
+ EncryptedBookThatIgnoresCase.create!(name: "Dune")
239
+ book = EncryptedBookThatIgnoresCase.find_by_name("dune")
240
+ assert book
241
+ assert_equal "Dune", book.name
242
+ end
243
+
244
+ test "when ignore_case: true, it keeps both the attribute and the _original counterpart encrypted" do
245
+ book = EncryptedBookThatIgnoresCase.create!(name: "Dune")
246
+ assert_encrypted_attribute book, :name, "Dune"
247
+ assert_encrypted_attribute book, :original_name, "Dune"
248
+ end
249
+
250
+ test "when ignore_case: true, it lets you update attributes normally" do
251
+ book = EncryptedBookThatIgnoresCase.create!(name: "Dune")
252
+ book.update!(name: "Dune II")
253
+ assert_equal "Dune II", book.name
254
+ end
255
+
256
+ test "when ignore_case: true, it returns the actual value when not encrypted" do
257
+ ActiveRecord::Encryption.config.support_unencrypted_data = true
258
+
259
+ book = create_unencrypted_book_ignoring_case name: "Dune"
260
+ assert_equal "Dune", book.name
261
+ end
262
+
263
+ test "when ignore_case: true, users can override accessors and call super" do
264
+ overriding_class = Class.new(EncryptedBookThatIgnoresCase) do
265
+ self.table_name = "books"
266
+
267
+ def name
268
+ "#{super}-overridden"
269
+ end
270
+ end
271
+
272
+ overriding_class.create!(name: "Dune")
273
+ book = overriding_class.find_by_name("dune")
274
+ assert book
275
+ assert_equal "Dune-overridden", book.reload.name
276
+ end
277
+
278
+ test "reading a not encrypted value will raise a Decryption error when :support_unencrypted_data is false" do
279
+ ActiveRecord::Encryption.config.support_unencrypted_data = false
280
+
281
+ book = ActiveRecord::Encryption.without_encryption do
282
+ EncryptedBookThatIgnoresCase.create!(name: "dune")
283
+ end
284
+
285
+ assert_raises(ActiveRecord::Encryption::Errors::Decryption) do
286
+ book.name
287
+ end
288
+ end
289
+
290
+ test "reading a not encrypted value won't raise a Decryption error when :support_unencrypted_data is true" do
291
+ ActiveRecord::Encryption.config.support_unencrypted_data = true
292
+
293
+ author = ActiveRecord::Encryption.without_encryption do
294
+ EncryptedAuthor.create!(name: "Stephen King")
295
+ end
296
+
297
+ assert_equal "Stephen King", author.name
298
+ end
299
+
300
+ # Only run for adapters that add a default string limit when not provided (MySQL, 255)
301
+ if author_name_limit = EncryptedAuthor.columns_hash["name"].limit
302
+ # No column limits in SQLite
303
+ test "validate column sizes" do
304
+ assert_predicate EncryptedAuthor.new(name: "jorge"), :valid?
305
+ assert_not EncryptedAuthor.new(name: "a" * (author_name_limit + 1)).valid?
306
+ author = EncryptedAuthor.create(name: "a" * (author_name_limit + 1))
307
+ assert_not author.valid?
308
+ end
309
+ end
310
+
311
+ test "track previous changes properly for encrypted attributes" do
312
+ ActiveRecord::Encryption.config.support_unencrypted_data = true
313
+
314
+ book = EncryptedBook.create!(name: "Dune")
315
+ book.update!(created_at: 1.hour.ago)
316
+ assert_not book.name_previously_changed?
317
+
318
+ book.update!(name: "A new title!")
319
+ assert_predicate book, :name_previously_changed?
320
+ end
321
+
322
+ test "forces UTF-8 encoding for deterministic attributes by default" do
323
+ book = EncryptedBook.create!(name: "Dune".encode("ASCII-8BIT"))
324
+ assert_equal Encoding::UTF_8, book.reload.name.encoding
325
+ end
326
+
327
+ test "forces encoding for deterministic attributes based on the configured option" do
328
+ ActiveRecord::Encryption.config.forced_encoding_for_deterministic_encryption = Encoding::US_ASCII
329
+
330
+ book = EncryptedBook.create!(name: "Dune".encode("ASCII-8BIT"))
331
+ assert_equal Encoding::US_ASCII, book.reload.name.encoding
332
+ end
333
+
334
+ test "forced encoding for deterministic attributes will replace invalid characters" do
335
+ book = EncryptedBook.create!(name: "Hello \x93\xfa".b)
336
+ assert_equal "Hello ��", book.reload.name
337
+ end
338
+
339
+ test "forced encoding for deterministic attributes can be disabled" do
340
+ ActiveRecord::Encryption.config.forced_encoding_for_deterministic_encryption = nil
341
+
342
+ book = EncryptedBook.create!(name: "Dune".encode("US-ASCII"))
343
+ assert_equal Encoding::US_ASCII, book.reload.name.encoding
344
+ end
345
+
346
+ test "support encrypted attributes defined on columns with default values" do
347
+ book = EncryptedBook.create!
348
+ assert_encrypted_attribute(book, :name, "<untitled>")
349
+ end
350
+
351
+ test "loading records with encrypted attributes defined on columns with default values" do
352
+ skip unless supports_insert_on_duplicate_update?
353
+
354
+ EncryptedBook.insert({ format: "ebook" })
355
+ book = EncryptedBook.last
356
+ assert_equal "<untitled>", book.name
357
+ end
358
+
359
+ test "can dump and load records that use encryption" do
360
+ book = EncryptedBook.create!
361
+ assert_equal book, Marshal.load(Marshal.dump(book))
362
+ end
363
+
364
+ test "supports decrypting data encrypted non deterministically with SHA1 when digest class is SHA256" do
365
+ ActiveRecord::Encryption.configure \
366
+ primary_key: "the primary key",
367
+ deterministic_key: "the deterministic key",
368
+ key_derivation_salt: "the salt",
369
+ support_sha1_for_non_deterministic_encryption: true
370
+
371
+ key_provider_sha1 = build_derived_key_provider_with OpenSSL::Digest::SHA1
372
+ key_provider_sha256 = build_derived_key_provider_with OpenSSL::Digest::SHA256
373
+
374
+ encrypted_post_class_sha_1 = Class.new(Post) do
375
+ self.table_name = "posts"
376
+ encrypts :title, key_provider: key_provider_sha1
377
+ end
378
+ encrypted_post_class_sha_1.create! title: "Post 1", body: "The post body", type: nil
379
+
380
+ encrypted_post_class_sha_256 = Class.new(Post) do
381
+ self.table_name = "posts"
382
+ encrypts :title, key_provider: key_provider_sha256
383
+ end
384
+
385
+ assert_equal "Post 1", encrypted_post_class_sha_256.last.title
386
+ end
387
+
388
+ test "encryption schemes are resolved when used, not when declared" do
389
+ OtherEncryptedPost = Class.new(Post) do
390
+ self.table_name = "posts"
391
+ encrypts :title
392
+ end
393
+
394
+ ActiveRecord::Encryption.configure \
395
+ primary_key: "the primary key",
396
+ deterministic_key: "the deterministic key",
397
+ key_derivation_salt: "the salt",
398
+ support_sha1_for_non_deterministic_encryption: true
399
+
400
+ assert_predicate OtherEncryptedPost.type_for_attribute(:title).scheme.previous_schemes, :one?
401
+ end
402
+
403
+ test "binary data can be encrypted" do
404
+ all_bytes = (0..255).map(&:chr).join
405
+ assert_equal all_bytes, EncryptedBookWithBinary.create!(logo: all_bytes).logo
406
+ assert_nil EncryptedBookWithBinary.create!(logo: nil).logo
407
+ assert_equal "", EncryptedBookWithBinary.create!(logo: "").logo
408
+ end
409
+
410
+ test "binary data can be encrypted uncompressed" do
411
+ low_bytes = (0..127).map(&:chr).join
412
+ high_bytes = (128..255).map(&:chr).join
413
+ assert_encrypted_attribute EncryptedBookWithBinary.create!(logo: low_bytes), :logo, low_bytes
414
+ assert_encrypted_attribute EncryptedBookWithBinary.create!(logo: high_bytes), :logo, high_bytes
415
+ end
416
+
417
+ test "serialized binary data can be encrypted" do
418
+ json_bytes = (32..127).map(&:chr)
419
+ assert_encrypted_attribute EncryptedBookWithSerializedFirstBinary.create!(logo: json_bytes), :logo, json_bytes
420
+ assert_encrypted_attribute EncryptedBookWithSerializedSecondBinary.create!(logo: json_bytes), :logo, json_bytes
421
+ end
422
+
423
+ test "can compress data with custom compressor" do
424
+ name = "a" * 141
425
+ assert EncryptedBookWithCustomCompressor.create!(name: name).name.start_with?("[compressed]")
426
+ end
427
+
428
+ test "type method returns cast type" do
429
+ assert_equal :string, EncryptedBook.type_for_attribute(:name).type
430
+
431
+ expected_post_body_type = if ActiveRecord::TestCase.current_adapter?(:OracleAdapter, :IBM_DBAdapter)
432
+ :string
433
+ else
434
+ :text
435
+ end
436
+ assert_equal expected_post_body_type, EncryptedPost.type_for_attribute(:body).type
437
+ end
438
+
439
+ test "encrypts normalized data" do
440
+ assert_encrypted_attribute EncryptedBookNormalizedFirst.create!(name: "Book"), :name, "book"
441
+ assert_encrypted_attribute EncryptedBookNormalizedSecond.create!(name: "Book"), :name, "book"
442
+ assert_encrypted_attribute EncryptedBookNormalizedFirst.create!(logo: "Book"), :logo, "book"
443
+ assert_encrypted_attribute EncryptedBookNormalizedSecond.create!(logo: "Book"), :logo, "book"
444
+ end
445
+
446
+ test "encrypts attribute data" do
447
+ assert_encrypted_attribute EncryptedBookAttribute.create!(name: "2024-01-01"), :name, Date.new(2024, 1, 1)
448
+ end
449
+
450
+ private
451
+ def build_derived_key_provider_with(hash_digest_class)
452
+ ActiveRecord::Encryption.with_encryption_context(key_generator: ActiveRecord::Encryption::KeyGenerator.new(hash_digest_class: hash_digest_class)) do
453
+ ActiveRecord::Encryption::DerivedSecretKeyProvider.new(ActiveRecord::Encryption.config.primary_key)
454
+ end
455
+ end
456
+
457
+ class FailingKeyProvider
458
+ def decryption_key(message) end
459
+
460
+ def encryption_key
461
+ raise ActiveRecord::Encryption::Errors::Encryption
462
+ end
463
+ end
464
+
465
+ class BookThatWillFailToEncryptName < UnencryptedBook
466
+ self.table_name = "encrypted_books"
467
+
468
+ encrypts :name, key_provider: FailingKeyProvider.new
469
+ end
470
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/encryption/helper"
4
+ require "models/book_encrypted"
5
+
6
+ class ActiveRecord::Encryption::EncryptableFixtureTest < ActiveRecord::EncryptionTestCase
7
+ self.use_transactional_tests = false
8
+
9
+ fixtures :encrypted_books, :encrypted_book_that_ignores_cases
10
+
11
+ test "fixtures get encrypted automatically" do
12
+ assert encrypted_books(:awdr).encrypted_attribute?(:name)
13
+ end
14
+
15
+ test "preserved columns due to ignore_case: true gets encrypted automatically" do
16
+ book = encrypted_book_that_ignores_cases(:rfr)
17
+ assert_equal "Ruby for Rails", book.name
18
+ assert_encrypted_attribute book, :name, "Ruby for Rails"
19
+
20
+ assert EncryptedBookThatIgnoresCase.find_by_name("Ruby for Rails")
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/encryption/helper"
4
+
5
+ class ActiveRecord::Encryption::EncryptingOnlyEncryptorTest < ActiveRecord::EncryptionTestCase
6
+ setup do
7
+ @encryptor = ActiveRecord::Encryption::EncryptingOnlyEncryptor.new
8
+ ActiveRecord::Encryption.config.support_unencrypted_data = true
9
+ end
10
+
11
+ test "decrypt returns the passed data" do
12
+ assert_equal "Some data", @encryptor.decrypt("Some data")
13
+ end
14
+
15
+ test "encrypt encrypts the passed data" do
16
+ encrypted_text = @encryptor.encrypt("Some data")
17
+ assert_not_equal encrypted_text, "Some data"
18
+ assert_equal "Some data", ActiveRecord::Encryption::Encryptor.new.decrypt(encrypted_text)
19
+ end
20
+ end