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
@@ -35,24 +35,74 @@ class QueryCacheTest < ActiveRecord::TestCase
35
35
  end
36
36
 
37
37
  def teardown
38
- Task.connection.clear_query_cache
39
- ActiveRecord::Base.connection.disable_query_cache!
38
+ Task.connection_pool.clear_query_cache
39
+ ActiveRecord::Base.connection_pool.disable_query_cache!
40
40
  super
41
41
  end
42
42
 
43
+ def test_execute_clear_cache
44
+ assert_cache :off
45
+
46
+ mw = middleware { |env|
47
+ Post.first
48
+ query_cache = ActiveRecord::Base.connection_pool.query_cache
49
+ assert_equal 1, query_cache.size, query_cache.inspect
50
+ Post.lease_connection.execute("SELECT 1")
51
+ query_cache = ActiveRecord::Base.connection_pool.query_cache
52
+ assert_equal 0, query_cache.size, query_cache.inspect
53
+ }
54
+ mw.call({})
55
+
56
+ assert_cache :off
57
+ end
58
+
59
+ def test_exec_query_clear_cache
60
+ assert_cache :off
61
+
62
+ mw = middleware { |env|
63
+ Post.first
64
+ query_cache = ActiveRecord::Base.connection_pool.query_cache
65
+ assert_equal 1, query_cache.size, query_cache.inspect
66
+ Post.lease_connection.exec_query("SELECT 1")
67
+ query_cache = ActiveRecord::Base.connection_pool.query_cache
68
+ assert_equal 0, query_cache.size, query_cache.inspect
69
+ }
70
+ mw.call({})
71
+
72
+ assert_cache :off
73
+ end
74
+
43
75
  def test_writes_should_always_clear_cache
44
76
  assert_cache :off
45
77
 
46
78
  mw = middleware { |env|
47
79
  Post.first
48
- query_cache = ActiveRecord::Base.connection.query_cache
49
- assert_equal 1, query_cache.length, query_cache.keys
50
- Post.connection.uncached do
80
+ query_cache = ActiveRecord::Base.connection_pool.query_cache
81
+ assert_equal 1, query_cache.size, query_cache.inspect
82
+ Post.lease_connection.uncached do
51
83
  # should clear the cache
52
84
  Post.create!(title: "a new post", body: "and a body")
53
85
  end
54
- query_cache = ActiveRecord::Base.connection.query_cache
55
- assert_equal 0, query_cache.length, query_cache.keys
86
+ query_cache = ActiveRecord::Base.connection_pool.query_cache
87
+ assert_equal 0, query_cache.size, query_cache.inspect
88
+ }
89
+ mw.call({})
90
+
91
+ assert_cache :off
92
+ end
93
+
94
+ def test_reads_dont_clear_disabled_cache
95
+ assert_cache :off
96
+
97
+ mw = middleware { |env|
98
+ Post.first
99
+ query_cache = ActiveRecord::Base.connection_pool.query_cache
100
+ assert_equal 1, query_cache.size, query_cache.inspect
101
+ Post.lease_connection.uncached do
102
+ Post.count # shouldn't clear the cache
103
+ end
104
+ query_cache = ActiveRecord::Base.connection_pool.query_cache
105
+ assert_equal 1, query_cache.size, query_cache.inspect
56
106
  }
57
107
  mw.call({})
58
108
 
@@ -65,8 +115,8 @@ class QueryCacheTest < ActiveRecord::TestCase
65
115
  mw = middleware { |env|
66
116
  Task.find 1
67
117
  Task.find 1
68
- query_cache = ActiveRecord::Base.connection.query_cache
69
- assert_equal 1, query_cache.length, query_cache.keys
118
+ query_cache = ActiveRecord::Base.connection_pool.query_cache
119
+ assert_equal 1, query_cache.size, query_cache.inspect
70
120
  raise "lol borked"
71
121
  }
72
122
  assert_raises(RuntimeError) { mw.call({}) }
@@ -74,120 +124,96 @@ class QueryCacheTest < ActiveRecord::TestCase
74
124
  assert_cache :off
75
125
  end
76
126
 
77
- def test_query_cache_is_applied_to_legacy_connections_in_all_handlers
78
- old_value = ActiveRecord::Base.legacy_connection_handling
79
- ActiveRecord::Base.legacy_connection_handling = true
80
-
81
- ActiveRecord::Base.connection_handlers = {
82
- writing: ActiveRecord::Base.default_connection_handler,
83
- reading: ActiveRecord::ConnectionAdapters::ConnectionHandler.new
84
- }
85
-
127
+ def test_query_cache_is_applied_to_all_connections
86
128
  ActiveRecord::Base.connected_to(role: :reading) do
87
129
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
88
130
  ActiveRecord::Base.establish_connection(db_config)
89
131
  end
90
132
 
91
133
  mw = middleware { |env|
92
- reading_handler = ActiveRecord::Base.connection_handlers[:reading]
93
- ro_pool = reading_handler.connection_pool_list
94
- ro_conn = ro_pool.first.connection
95
- assert_predicate ActiveRecord::Base.connection, :query_cache_enabled
96
- assert_predicate ro_conn, :query_cache_enabled
134
+ ActiveRecord::Base.connection_handler.connection_pool_list(:all).each do |pool|
135
+ assert_predicate pool.lease_connection, :query_cache_enabled
136
+ end
97
137
  }
98
138
 
99
139
  mw.call({})
100
140
  ensure
101
- clean_up_legacy_connection_handlers
102
- ActiveRecord::Base.legacy_connection_handling = old_value
141
+ clean_up_connection_handler
103
142
  end
104
143
 
105
- def test_query_cache_is_applied_to_all_connections
144
+ def test_cache_is_not_applied_when_config_is_false
106
145
  ActiveRecord::Base.connected_to(role: :reading) do
107
146
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
108
- ActiveRecord::Base.establish_connection(db_config)
147
+ ActiveRecord::Base.establish_connection(db_config.configuration_hash.merge(query_cache: false))
109
148
  end
110
149
 
111
- mw = middleware { |env|
112
- rw_conn = ActiveRecord::Base.connection_handler.connection_pool_list(:writing).first.connection
113
- assert_predicate rw_conn, :query_cache_enabled
114
-
115
- ro_conn = ActiveRecord::Base.connection_handler.connection_pool_list(:reading).first.connection
116
- assert_predicate ActiveRecord::Base.connection, :query_cache_enabled
117
- assert_predicate ro_conn, :query_cache_enabled
118
- }
150
+ mw = middleware do |env|
151
+ ActiveRecord::Base.connected_to(role: :reading) do
152
+ assert_cache :off
153
+ assert_nil ActiveRecord::Base.lease_connection.pool.query_cache.instance_variable_get(:@max_size)
154
+ end
155
+ end
119
156
 
120
157
  mw.call({})
121
158
  ensure
122
159
  clean_up_connection_handler
123
160
  end
124
161
 
125
- if Process.respond_to?(:fork) && !in_memory_db?
126
- def test_query_cache_with_multiple_handlers_and_forked_processes_legacy_handling
127
- old_value = ActiveRecord::Base.legacy_connection_handling
128
- ActiveRecord::Base.legacy_connection_handling = true
129
- ActiveRecord::Base.connection_handlers = {
130
- writing: ActiveRecord::Base.default_connection_handler,
131
- reading: ActiveRecord::ConnectionAdapters::ConnectionHandler.new
132
- }
162
+ def test_cache_is_applied_when_config_is_string
163
+ ActiveRecord::Base.connected_to(role: :reading) do
164
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
165
+ ActiveRecord::Base.establish_connection(db_config.configuration_hash.merge(query_cache: "unlimited"))
166
+ end
133
167
 
168
+ mw = middleware do |env|
134
169
  ActiveRecord::Base.connected_to(role: :reading) do
135
- db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
136
- ActiveRecord::Base.establish_connection(db_config)
170
+ assert_cache :clean
171
+ assert_nil ActiveRecord::Base.lease_connection.pool.query_cache.instance_variable_get(:@max_size)
137
172
  end
173
+ end
138
174
 
139
- rd, wr = IO.pipe
140
- rd.binmode
141
- wr.binmode
142
-
143
- pid = fork {
144
- rd.close
145
- status = 0
146
-
147
- middleware { |env|
148
- begin
149
- assert_cache :clean
150
-
151
- # first request dirties cache
152
- ActiveRecord::Base.connected_to(role: :reading) do
153
- Post.first
154
- assert_cache :dirty
155
- end
156
-
157
- # should clear the cache
158
- Post.create!(title: "a new post", body: "and a body")
175
+ mw.call({})
176
+ ensure
177
+ clean_up_connection_handler
178
+ end
159
179
 
160
- # fails because cache is still dirty
161
- ActiveRecord::Base.connected_to(role: :reading) do
162
- assert_cache :clean
163
- Post.first
164
- end
180
+ def test_cache_is_applied_when_config_is_integer
181
+ ActiveRecord::Base.connected_to(role: :reading) do
182
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
183
+ ActiveRecord::Base.establish_connection(db_config.configuration_hash.merge(query_cache: 42))
184
+ end
165
185
 
166
- rescue Minitest::Assertion => e
167
- wr.write Marshal.dump e
168
- status = 1
169
- end
170
- }.call({})
186
+ mw = middleware do |env|
187
+ ActiveRecord::Base.connected_to(role: :reading) do
188
+ assert_cache :clean
189
+ assert_equal 42, ActiveRecord::Base.lease_connection.pool.query_cache.instance_variable_get(:@max_size)
190
+ end
191
+ end
171
192
 
172
- wr.close
173
- exit!(status)
174
- }
193
+ mw.call({})
194
+ ensure
195
+ clean_up_connection_handler
196
+ end
175
197
 
176
- wr.close
198
+ def test_cache_is_applied_when_config_is_nil
199
+ ActiveRecord::Base.connected_to(role: :reading) do
200
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
201
+ ActiveRecord::Base.establish_connection(db_config.configuration_hash.merge(query_cache: nil))
202
+ end
177
203
 
178
- Process.waitpid pid
179
- if !$?.success?
180
- raise Marshal.load(rd.read)
181
- else
182
- assert_predicate $?, :success?
204
+ mw = middleware do |env|
205
+ ActiveRecord::Base.connected_to(role: :reading) do
206
+ assert_cache :clean
207
+ assert_equal ActiveRecord::ConnectionAdapters::QueryCache::DEFAULT_SIZE, ActiveRecord::Base.lease_connection.pool.query_cache.instance_variable_get(:@max_size)
183
208
  end
184
-
185
- rd.close
186
- ensure
187
- clean_up_legacy_connection_handlers
188
- ActiveRecord::Base.legacy_connection_handling = old_value
189
209
  end
190
210
 
211
+ mw.call({})
212
+ ensure
213
+ clean_up_connection_handler
214
+ end
215
+
216
+ if Process.respond_to?(:fork) && !in_memory_db?
191
217
  def test_query_cache_with_forked_processes
192
218
  ActiveRecord::Base.connected_to(role: :reading) do
193
219
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
@@ -257,14 +283,14 @@ class QueryCacheTest < ActiveRecord::TestCase
257
283
  t.datetime :ending
258
284
  end
259
285
  end
260
- ActiveRecord::FixtureSet.create_fixtures(self.class.fixture_path, ["tasks"], {}, ActiveRecord::Base)
286
+ ActiveRecord::FixtureSet.create_fixtures(self.class.fixture_paths, ["tasks"], {}, ActiveRecord::Base)
261
287
  end
262
288
 
263
289
  ActiveRecord::Base.connection_pool.connections.each do |conn|
264
290
  assert_cache :off, conn
265
291
  end
266
292
 
267
- assert_not_predicate ActiveRecord::Base.connection, :nil?
293
+ assert_not_predicate ActiveRecord::Base.lease_connection, :nil?
268
294
  assert_cache :off
269
295
 
270
296
  middleware {
@@ -273,8 +299,8 @@ class QueryCacheTest < ActiveRecord::TestCase
273
299
  Task.find 1
274
300
  assert_cache :dirty
275
301
 
276
- thread_1_connection = ActiveRecord::Base.connection
277
- ActiveRecord::Base.clear_active_connections!
302
+ thread_1_connection = ActiveRecord::Base.lease_connection
303
+ ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
278
304
  assert_cache :off, thread_1_connection
279
305
 
280
306
  started = Concurrent::Event.new
@@ -282,7 +308,7 @@ class QueryCacheTest < ActiveRecord::TestCase
282
308
 
283
309
  thread_2_connection = nil
284
310
  thread = Thread.new {
285
- thread_2_connection = ActiveRecord::Base.connection
311
+ thread_2_connection = ActiveRecord::Base.lease_connection
286
312
 
287
313
  assert_equal thread_2_connection, thread_1_connection
288
314
  assert_cache :off
@@ -296,13 +322,13 @@ class QueryCacheTest < ActiveRecord::TestCase
296
322
  started.set
297
323
  checked.wait
298
324
 
299
- ActiveRecord::Base.clear_active_connections!
325
+ ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
300
326
  }.call({})
301
327
  }
302
328
 
303
329
  started.wait
304
330
 
305
- thread_1_connection = ActiveRecord::Base.connection
331
+ thread_1_connection = ActiveRecord::Base.lease_connection
306
332
  assert_not_equal thread_1_connection, thread_2_connection
307
333
  assert_cache :dirty, thread_2_connection
308
334
  checked.set
@@ -333,8 +359,8 @@ class QueryCacheTest < ActiveRecord::TestCase
333
359
  mw = middleware { |env|
334
360
  Task.find 1
335
361
  Task.find 1
336
- query_cache = ActiveRecord::Base.connection.query_cache
337
- assert_equal 1, query_cache.length, query_cache.keys
362
+ query_cache = ActiveRecord::Base.connection_pool.query_cache
363
+ assert_equal 1, query_cache.size, query_cache.inspect
338
364
  [200, {}, nil]
339
365
  }
340
366
  mw.call({})
@@ -354,30 +380,30 @@ class QueryCacheTest < ActiveRecord::TestCase
354
380
  post = Post.first
355
381
  Post.cache do
356
382
  query = post.categories.select(:post_id)
357
- assert Post.connection.select_all(query).is_a?(ActiveRecord::Result)
383
+ assert Post.lease_connection.select_all(query).is_a?(ActiveRecord::Result)
358
384
  end
359
385
  end
360
386
 
361
387
  def test_find_queries
362
- assert_queries(2) { Task.find(1); Task.find(1) }
388
+ assert_queries_count(2) { Task.find(1); Task.find(1) }
363
389
  end
364
390
 
365
391
  def test_find_queries_with_cache
366
392
  Task.cache do
367
- assert_queries(1) { Task.find(1); Task.find(1) }
393
+ assert_queries_count(1) { Task.find(1); Task.find(1) }
368
394
  end
369
395
  end
370
396
 
371
397
  def test_find_queries_with_cache_multi_record
372
398
  Task.cache do
373
- assert_queries(2) { Task.find(1); Task.find(1); Task.find(2) }
399
+ assert_queries_count(2) { Task.find(1); Task.find(1); Task.find(2) }
374
400
  end
375
401
  end
376
402
 
377
403
  def test_find_queries_with_multi_cache_blocks
378
404
  Task.cache do
379
405
  Task.cache do
380
- assert_queries(2) { Task.find(1); Task.find(2) }
406
+ assert_queries_count(2) { Task.find(1); Task.find(2) }
381
407
  end
382
408
  assert_no_queries { Task.find(1); Task.find(1); Task.find(2) }
383
409
  end
@@ -385,52 +411,52 @@ class QueryCacheTest < ActiveRecord::TestCase
385
411
 
386
412
  def test_count_queries_with_cache
387
413
  Task.cache do
388
- assert_queries(1) { Task.count; Task.count }
414
+ assert_queries_count(1) { Task.count; Task.count }
389
415
  end
390
416
  end
391
417
 
392
418
  def test_exists_queries_with_cache
393
419
  Post.cache do
394
- assert_queries(1) { Post.exists?; Post.exists? }
420
+ assert_queries_count(1) { Post.exists?; Post.exists? }
395
421
  end
396
422
  end
397
423
 
398
424
  def test_select_all_with_cache
399
425
  Post.cache do
400
- assert_queries(1) do
401
- 2.times { Post.connection.select_all(Post.all) }
426
+ assert_queries_count(1) do
427
+ 2.times { Post.lease_connection.select_all(Post.all) }
402
428
  end
403
429
  end
404
430
  end
405
431
 
406
432
  def test_select_one_with_cache
407
433
  Post.cache do
408
- assert_queries(1) do
409
- 2.times { Post.connection.select_one(Post.all) }
434
+ assert_queries_count(1) do
435
+ 2.times { Post.lease_connection.select_one(Post.all) }
410
436
  end
411
437
  end
412
438
  end
413
439
 
414
440
  def test_select_value_with_cache
415
441
  Post.cache do
416
- assert_queries(1) do
417
- 2.times { Post.connection.select_value(Post.all) }
442
+ assert_queries_count(1) do
443
+ 2.times { Post.lease_connection.select_value(Post.all) }
418
444
  end
419
445
  end
420
446
  end
421
447
 
422
448
  def test_select_values_with_cache
423
449
  Post.cache do
424
- assert_queries(1) do
425
- 2.times { Post.connection.select_values(Post.all) }
450
+ assert_queries_count(1) do
451
+ 2.times { Post.lease_connection.select_values(Post.all) }
426
452
  end
427
453
  end
428
454
  end
429
455
 
430
456
  def test_select_rows_with_cache
431
457
  Post.cache do
432
- assert_queries(1) do
433
- 2.times { Post.connection.select_rows(Post.all) }
458
+ assert_queries_count(1) do
459
+ 2.times { Post.lease_connection.select_rows(Post.all) }
434
460
  end
435
461
  end
436
462
  end
@@ -450,15 +476,15 @@ class QueryCacheTest < ActiveRecord::TestCase
450
476
  logger = ShouldNotHaveExceptionsLogger.new
451
477
  subscriber = ActiveSupport::Notifications.subscribe "sql.active_record", logger
452
478
 
453
- connection = ActiveRecord::Base.connection.dup
479
+ connection = ActiveRecord::Base.lease_connection.dup
454
480
 
455
481
  def connection.cache_notification_info(sql, name, binds)
456
482
  super.merge(neat: true)
457
483
  end
458
484
 
459
485
  connection.cache do
460
- connection.select_all "select 1 from SYSIBM.DUAL"
461
- connection.select_all "select 1 from SYSIBM.DUAL"
486
+ connection.select_all "select 1"
487
+ connection.select_all "select 1"
462
488
  end
463
489
 
464
490
  assert_equal true, logger.events.last.payload[:neat]
@@ -471,7 +497,7 @@ class QueryCacheTest < ActiveRecord::TestCase
471
497
  subscriber = ActiveSupport::Notifications.subscribe "sql.active_record", logger
472
498
 
473
499
  ActiveRecord::Base.cache do
474
- assert_queries(1) { Task.find(1); Task.find(1) }
500
+ assert_queries_count(1) { Task.find(1); Task.find(1) }
475
501
  end
476
502
 
477
503
  assert_not_predicate logger, :exception?
@@ -481,12 +507,14 @@ class QueryCacheTest < ActiveRecord::TestCase
481
507
 
482
508
  def test_query_cache_does_not_allow_sql_key_mutation
483
509
  subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |_, _, _, _, payload|
484
- payload[:sql].downcase!
510
+ payload[:sql].downcase! if payload[:name] == "Task Load"
485
511
  end
486
512
 
487
- assert_raises FrozenError do
488
- ActiveRecord::Base.cache do
489
- assert_queries(1) { Task.find(1); Task.find(1) }
513
+ ActiveRecord::Base.cache do
514
+ assert_queries_count(1) do
515
+ assert_raises FrozenError do
516
+ Task.find(1)
517
+ end
490
518
  end
491
519
  end
492
520
  ensure
@@ -495,17 +523,17 @@ class QueryCacheTest < ActiveRecord::TestCase
495
523
 
496
524
  def test_cache_is_flat
497
525
  Task.cache do
498
- assert_queries(1) { Topic.find(1); Topic.find(1); }
526
+ assert_queries_count(1) { Topic.find(1); Topic.find(1) }
499
527
  end
500
528
 
501
529
  ActiveRecord::Base.cache do
502
- assert_queries(1) { Task.find(1); Task.find(1) }
530
+ assert_queries_count(1) { Task.find(1); Task.find(1) }
503
531
  end
504
532
  end
505
533
 
506
534
  def test_cache_does_not_wrap_results_in_arrays
507
535
  Task.cache do
508
- assert_equal 2, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
536
+ assert_equal 2, Task.lease_connection.select_value("SELECT count(*) AS count_all FROM tasks")
509
537
  end
510
538
  end
511
539
 
@@ -513,7 +541,7 @@ class QueryCacheTest < ActiveRecord::TestCase
513
541
  task = Task.find 1
514
542
 
515
543
  Task.cache do
516
- assert_queries(2) { task.lock!; task.lock! }
544
+ assert_queries_count(2) { task.lock!; task.lock! }
517
545
  end
518
546
  end
519
547
 
@@ -522,7 +550,7 @@ class QueryCacheTest < ActiveRecord::TestCase
522
550
 
523
551
  ActiveRecord::Base.configurations = {}
524
552
  Task.cache do
525
- assert_queries(1) { Task.find(1); Task.find(1) }
553
+ assert_queries_count(1) { Task.find(1); Task.find(1) }
526
554
  end
527
555
  ensure
528
556
  ActiveRecord::Base.configurations = conf
@@ -530,23 +558,25 @@ class QueryCacheTest < ActiveRecord::TestCase
530
558
 
531
559
  def test_cache_is_available_when_using_a_not_connected_connection
532
560
  skip "In-Memory DB can't test for using a not connected connection" if in_memory_db?
533
- db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary").dup
534
- db_config.owner_name = "test2"
535
- ActiveRecord::Base.connection_handler.establish_connection(db_config)
561
+ db_config = ActiveRecord::Base.connection_db_config
562
+ original_connection = ActiveRecord::Base.remove_connection
563
+
564
+ ActiveRecord::Base.establish_connection(db_config)
536
565
  assert_not_predicate Task, :connected?
537
566
 
538
567
  Task.cache do
539
- assert_queries(1) { Task.find(1); Task.find(1) }
568
+ assert_queries_count(1) { Task.find(1) }
569
+ assert_no_queries { Task.find(1) }
540
570
  ensure
541
- ActiveRecord::Base.connection_handler.remove_connection_pool(db_config.owner_name)
571
+ ActiveRecord::Base.establish_connection(original_connection)
542
572
  end
543
573
  end
544
574
 
545
575
  def test_query_cache_executes_new_queries_within_block
546
- ActiveRecord::Base.connection.enable_query_cache!
576
+ ActiveRecord::Base.lease_connection.enable_query_cache!
547
577
 
548
578
  # Warm up the cache by running the query
549
- assert_queries(1) do
579
+ assert_queries_count(1) do
550
580
  assert_equal 0, Post.where(title: "test").to_a.count
551
581
  end
552
582
 
@@ -555,16 +585,16 @@ class QueryCacheTest < ActiveRecord::TestCase
555
585
  assert_equal 0, Post.where(title: "test").to_a.count
556
586
  end
557
587
 
558
- ActiveRecord::Base.connection.uncached do
588
+ ActiveRecord::Base.lease_connection.uncached do
559
589
  # Check that new query is executed, avoiding the cache
560
- assert_queries(1) do
590
+ assert_queries_count(1) do
561
591
  assert_equal 0, Post.where(title: "test").to_a.count
562
592
  end
563
593
  end
564
594
  end
565
595
 
566
596
  def test_query_cache_doesnt_leak_cached_results_of_rolled_back_queries
567
- ActiveRecord::Base.connection.enable_query_cache!
597
+ ActiveRecord::Base.lease_connection.enable_query_cache!
568
598
  post = Post.first
569
599
 
570
600
  Post.transaction do
@@ -575,7 +605,7 @@ class QueryCacheTest < ActiveRecord::TestCase
575
605
 
576
606
  assert_equal 0, Post.where(title: "rollback").to_a.count
577
607
 
578
- ActiveRecord::Base.connection.uncached do
608
+ ActiveRecord::Base.lease_connection.uncached do
579
609
  assert_equal 0, Post.where(title: "rollback").to_a.count
580
610
  end
581
611
 
@@ -590,7 +620,7 @@ class QueryCacheTest < ActiveRecord::TestCase
590
620
 
591
621
  assert_equal 0, Post.where(title: "rollback").to_a.count
592
622
 
593
- ActiveRecord::Base.connection.uncached do
623
+ ActiveRecord::Base.lease_connection.uncached do
594
624
  assert_equal 0, Post.where(title: "rollback").to_a.count
595
625
  end
596
626
  end
@@ -601,7 +631,7 @@ class QueryCacheTest < ActiveRecord::TestCase
601
631
  Task.find(1)
602
632
 
603
633
  # Preload the type cache again (so we don't have those queries issued during our assertions)
604
- Task.connection.send(:reload_type_map)
634
+ Task.lease_connection.send(:reload_type_map) if Task.lease_connection.respond_to?(:reload_type_map, true)
605
635
 
606
636
  # Clear places where type information is cached
607
637
  Task.reset_column_information
@@ -615,150 +645,209 @@ class QueryCacheTest < ActiveRecord::TestCase
615
645
  end
616
646
 
617
647
  def test_query_cache_does_not_establish_connection_if_unconnected
618
- ActiveRecord::Base.clear_active_connections!
619
- assert_not ActiveRecord::Base.connection_handler.active_connections? # sanity check
648
+ ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
649
+ assert_not ActiveRecord::Base.connection_handler.active_connections?(:all) # Double check they are cleared
620
650
 
621
651
  middleware {
622
- assert_not ActiveRecord::Base.connection_handler.active_connections?, "QueryCache forced ActiveRecord::Base to establish a connection in setup"
652
+ assert_not ActiveRecord::Base.connection_handler.active_connections?(:all), "QueryCache forced ActiveRecord::Base to establish a connection in setup"
623
653
  }.call({})
624
654
 
625
- assert_not ActiveRecord::Base.connection_handler.active_connections?, "QueryCache forced ActiveRecord::Base to establish a connection in cleanup"
655
+ assert_not ActiveRecord::Base.connection_handler.active_connections?(:all), "QueryCache forced ActiveRecord::Base to establish a connection in cleanup"
626
656
  end
627
657
 
628
658
  def test_query_cache_is_enabled_on_connections_established_after_middleware_runs
629
- ActiveRecord::Base.clear_active_connections!
630
- assert_not ActiveRecord::Base.connection_handler.active_connections? # sanity check
659
+ ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
660
+ assert_not ActiveRecord::Base.connection_handler.active_connections?(:all) # Double check they are cleared
631
661
 
632
662
  middleware {
633
- assert_predicate ActiveRecord::Base.connection, :query_cache_enabled
663
+ assert_predicate ActiveRecord::Base.lease_connection, :query_cache_enabled
634
664
  }.call({})
635
- assert_not_predicate ActiveRecord::Base.connection, :query_cache_enabled
665
+ assert_not_predicate ActiveRecord::Base.lease_connection, :query_cache_enabled
636
666
  end
637
667
 
638
668
  def test_query_caching_is_local_to_the_current_thread
639
- ActiveRecord::Base.clear_active_connections!
669
+ ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
640
670
 
641
671
  middleware {
642
672
  assert ActiveRecord::Base.connection_pool.query_cache_enabled
643
- assert ActiveRecord::Base.connection.query_cache_enabled
673
+ assert ActiveRecord::Base.connection_pool.query_cache_enabled
644
674
 
645
675
  Thread.new {
646
676
  assert_not ActiveRecord::Base.connection_pool.query_cache_enabled
647
- assert_not ActiveRecord::Base.connection.query_cache_enabled
677
+ assert_not ActiveRecord::Base.connection_pool.query_cache_enabled
678
+
679
+ ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
648
680
  }.join
649
681
  }.call({})
650
682
  end
651
683
 
652
684
  def test_query_cache_is_enabled_on_all_connection_pools
653
685
  middleware {
654
- ActiveRecord::Base.connection_handler.connection_pool_list.each do |pool|
686
+ ActiveRecord::Base.connection_handler.connection_pool_list(:all).each do |pool|
655
687
  assert pool.query_cache_enabled
656
- assert pool.connection.query_cache_enabled
688
+ assert pool.with_connection(&:query_cache_enabled)
657
689
  end
658
690
  }.call({})
659
691
  end
660
692
 
661
- def test_clear_query_cache_is_called_on_all_legacy_connections
662
- skip "with in memory db, reading role won't be able to see database on writing role" if in_memory_db?
663
- old_value = ActiveRecord::Base.legacy_connection_handling
664
- ActiveRecord::Base.legacy_connection_handling = true
693
+ # with in memory db, reading role won't be able to see database on writing role
694
+ unless in_memory_db?
695
+ def test_clear_query_cache_is_called_on_all_connections
696
+ ActiveRecord::Base.connected_to(role: :reading) do
697
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
698
+ ActiveRecord::Base.establish_connection(db_config)
699
+ end
665
700
 
666
- ActiveRecord::Base.connection_handlers = {
667
- writing: ActiveRecord::Base.default_connection_handler,
668
- reading: ActiveRecord::ConnectionAdapters::ConnectionHandler.new
669
- }
701
+ mw = middleware { |env|
702
+ ActiveRecord::Base.connected_to(role: :reading) do
703
+ @topic = Topic.first
704
+ end
670
705
 
671
- ActiveRecord::Base.connected_to(role: :reading) do
672
- db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
673
- ActiveRecord::Base.establish_connection(db_config)
674
- end
706
+ assert @topic
675
707
 
676
- mw = middleware { |env|
677
- ActiveRecord::Base.connected_to(role: :reading) do
678
- @topic = Topic.first
679
- end
708
+ ActiveRecord::Base.connected_to(role: :writing) do
709
+ @topic.title = "Topic title"
710
+ @topic.save!
711
+ end
680
712
 
681
- assert @topic
713
+ assert_equal "Topic title", @topic.title
682
714
 
683
- ActiveRecord::Base.connected_to(role: :writing) do
684
- @topic.title = "It doesn't have to be crazy at work"
685
- @topic.save!
686
- end
715
+ ActiveRecord::Base.connected_to(role: :reading) do
716
+ @topic = Topic.first
717
+ assert_equal "Topic title", @topic.title
718
+ end
719
+ }
720
+
721
+ mw.call({})
722
+ ensure
723
+ clean_up_connection_handler
724
+ end
725
+ end
687
726
 
688
- assert_equal "It doesn't have to be crazy at work", @topic.title
727
+ test "query cache is enabled in threads with shared connection" do
728
+ ActiveRecord::Base.connection_pool.pin_connection!(ActiveSupport::IsolatedExecutionState.context)
689
729
 
690
- ActiveRecord::Base.connected_to(role: :reading) do
691
- @topic = Topic.first
692
- assert_equal "It doesn't have to be crazy at work", @topic.title
730
+ begin
731
+ assert_cache :off
732
+ ActiveRecord::Base.lease_connection.enable_query_cache!
733
+ assert_cache :clean
734
+
735
+ main_thread_cache = ActiveRecord::Base.lease_connection.query_cache
736
+ assert_same main_thread_cache, ActiveRecord::Base.lease_connection.query_cache
737
+
738
+ thread_a = Thread.new do
739
+ middleware { |env|
740
+ assert_cache :clean
741
+
742
+ # In a background thread, the cache instance must stay consistent but be different from the main
743
+ # thread.
744
+ background_thread_cache = ActiveRecord::Base.lease_connection.query_cache
745
+ assert_same background_thread_cache, ActiveRecord::Base.lease_connection.query_cache
746
+ assert_not_same main_thread_cache, ActiveRecord::Base.lease_connection.query_cache
747
+ [200, {}, nil]
748
+ }.call({})
693
749
  end
694
- }
695
750
 
696
- mw.call({})
697
- ensure
698
- unless in_memory_db?
699
- clean_up_legacy_connection_handlers
700
- ActiveRecord::Base.legacy_connection_handling = old_value
751
+ thread_a.join
752
+
753
+ assert_same main_thread_cache, ActiveRecord::Base.lease_connection.query_cache
754
+ ensure
755
+ ActiveRecord::Base.connection_pool.unpin_connection!
756
+ assert_same main_thread_cache, ActiveRecord::Base.lease_connection.query_cache
701
757
  end
702
758
  end
703
759
 
704
- def test_clear_query_cache_is_called_on_all_connections
705
- skip "with in memory db, reading role won't be able to see database on writing role" if in_memory_db?
760
+ test "query cache is cleared for all thread when a connection is shared" do
761
+ ActiveRecord::Base.connection_pool.pin_connection!(ActiveSupport::IsolatedExecutionState.context)
706
762
 
707
- ActiveRecord::Base.connected_to(role: :reading) do
708
- db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
709
- ActiveRecord::Base.establish_connection(db_config)
710
- end
763
+ begin
764
+ assert_cache :off
765
+ ActiveRecord::Base.lease_connection.enable_query_cache!
766
+ assert_cache :clean
711
767
 
712
- mw = middleware { |env|
713
- ActiveRecord::Base.connected_to(role: :reading) do
714
- @topic = Topic.first
715
- end
768
+ Post.first
769
+ assert_cache :dirty
770
+
771
+ thread_a = Thread.new do
772
+ middleware { |env|
773
+ assert_cache :clean
774
+
775
+ Post.first
776
+ assert_cache :dirty
716
777
 
717
- assert @topic
778
+ Post.delete_all
718
779
 
719
- ActiveRecord::Base.connected_to(role: :writing) do
720
- @topic.title = "It doesn't have to be crazy at work"
721
- @topic.save!
780
+ assert_cache :clean
781
+
782
+ [200, {}, nil]
783
+ }.call({})
722
784
  end
723
785
 
724
- assert_equal "It doesn't have to be crazy at work", @topic.title
786
+ thread_a.join
725
787
 
726
- ActiveRecord::Base.connected_to(role: :reading) do
727
- @topic = Topic.first
728
- assert_equal "It doesn't have to be crazy at work", @topic.title
788
+ assert_cache :clean
789
+ ensure
790
+ ActiveRecord::Base.connection_pool.unpin_connection!
791
+ end
792
+ end
793
+
794
+ def test_query_cache_uncached_dirties
795
+ mw = middleware { |env|
796
+ Post.first
797
+ assert_no_changes -> { ActiveRecord::Base.connection_pool.query_cache.size } do
798
+ Post.uncached(dirties: false) { Post.create!(title: "a new post", body: "and a body") }
729
799
  end
730
- }
731
800
 
801
+ assert_changes -> { ActiveRecord::Base.connection_pool.query_cache.size }, from: 1, to: 0 do
802
+ Post.uncached(dirties: true) { Post.create!(title: "a new post", body: "and a body") }
803
+ end
804
+ }
732
805
  mw.call({})
733
- ensure
734
- clean_up_connection_handler
735
806
  end
736
807
 
737
- test "query cache is enabled in threads with shared connection" do
738
- ActiveRecord::Base.connection_pool.lock_thread = true
739
-
740
- assert_cache :off
808
+ def test_query_cache_connection_uncached_dirties
809
+ mw = middleware { |env|
810
+ Post.first
811
+ assert_no_changes -> { ActiveRecord::Base.connection_pool.query_cache.size } do
812
+ Post.lease_connection.uncached(dirties: false) { Post.create!(title: "a new post", body: "and a body") }
813
+ end
741
814
 
742
- thread_a = Thread.new do
743
- middleware { |env|
744
- assert_cache :clean
745
- [200, {}, nil]
746
- }.call({})
747
- end
815
+ assert_changes -> { ActiveRecord::Base.connection_pool.query_cache.size }, from: 1, to: 0 do
816
+ Post.lease_connection.uncached(dirties: true) { Post.create!(title: "a new post", body: "and a body") }
817
+ end
818
+ }
819
+ mw.call({})
820
+ end
748
821
 
749
- thread_a.join
822
+ def test_query_cache_uncached_dirties_disabled_with_nested_cache
823
+ mw = middleware { |env|
824
+ Post.first
825
+ assert_changes -> { ActiveRecord::Base.connection_pool.query_cache.size }, from: 1, to: 0 do
826
+ Post.uncached(dirties: false) do
827
+ Post.cache do
828
+ Post.create!(title: "a new post", body: "and a body")
829
+ end
830
+ end
831
+ end
750
832
 
751
- ActiveRecord::Base.connection_pool.lock_thread = false
833
+ Post.first
834
+ assert_changes -> { ActiveRecord::Base.connection_pool.query_cache.size }, from: 1, to: 0 do
835
+ Post.lease_connection.uncached(dirties: false) do
836
+ Post.lease_connection.cache do
837
+ Post.create!(title: "a new post", body: "and a body")
838
+ end
839
+ end
840
+ end
841
+ }
842
+ mw.call({})
752
843
  end
753
844
 
754
845
  private
755
- def with_temporary_connection_pool
756
- pool_config = ActiveRecord::Base.connection_handler.send(:owner_to_pool_manager).fetch("ActiveRecord::Base").get_pool_config(ActiveRecord::Base.writing_role, :default)
846
+ def with_temporary_connection_pool(&block)
847
+ pool_config = ActiveRecord::Base.lease_connection.pool.pool_config
757
848
  new_pool = ActiveRecord::ConnectionAdapters::ConnectionPool.new(pool_config)
758
849
 
759
- pool_config.stub(:pool, new_pool) do
760
- yield
761
- end
850
+ pool_config.stub(:pool, new_pool, &block)
762
851
  end
763
852
 
764
853
  def middleware(&app)
@@ -767,28 +856,135 @@ class QueryCacheTest < ActiveRecord::TestCase
767
856
  lambda { |env| executor.wrap { app.call(env) } }
768
857
  end
769
858
 
770
- def assert_cache(state, connection = ActiveRecord::Base.connection)
859
+ def assert_cache(state, connection = ActiveRecord::Base.lease_connection)
771
860
  case state
772
861
  when :off
773
862
  assert_not connection.query_cache_enabled, "cache should be off"
774
- assert connection.query_cache.empty?, "cache should be empty"
863
+ if connection.query_cache.nil?
864
+ assert_nil connection.query_cache
865
+ else
866
+ assert_predicate connection.query_cache, :empty?, "cache should be nil or empty"
867
+ end
775
868
  when :clean
776
869
  assert connection.query_cache_enabled, "cache should be on"
777
- assert connection.query_cache.empty?, "cache should be empty"
870
+ assert_not_nil connection.query_cache
871
+ assert_predicate connection.query_cache, :empty?, "cache should be empty"
778
872
  when :dirty
779
873
  assert connection.query_cache_enabled, "cache should be on"
780
- assert_not connection.query_cache.empty?, "cache should be dirty"
874
+ assert_not_nil connection.query_cache
875
+ assert_not_predicate connection.query_cache, :empty?, "cache should be dirty"
781
876
  else
782
877
  raise "unknown state"
783
878
  end
784
879
  end
785
880
  end
786
881
 
882
+ class QueryCacheMutableParamTest < ActiveRecord::TestCase
883
+ self.use_transactional_tests = false
884
+
885
+ class JsonObj < ActiveRecord::Base
886
+ self.table_name = "json_objs"
887
+
888
+ attribute :payload, :json
889
+ end
890
+
891
+ class ObjectFixedHash < Struct.new(:a, :b)
892
+ # this isn't very realistic, but it is the worst case and therefore a good
893
+ # case to test
894
+ def hash
895
+ 1
896
+ end
897
+ end
898
+
899
+ def setup
900
+ ActiveRecord::Base.lease_connection.create_table("json_objs", force: true) do |t|
901
+ if current_adapter?(:PostgreSQLAdapter)
902
+ t.jsonb "payload"
903
+ else
904
+ t.json "payload"
905
+ end
906
+ end
907
+
908
+ ActiveRecord::Base.lease_connection.enable_query_cache!
909
+ end
910
+
911
+ def test_query_cache_handles_mutated_binds
912
+ JsonObj.create(payload: ObjectFixedHash.new({ a: 1 }))
913
+
914
+ search = ObjectFixedHash.new({ a: 1 })
915
+ JsonObj.where(payload: search).first # populate the cache
916
+
917
+ search.b = 2
918
+ assert_nil JsonObj.where(payload: search).first, "cache returned a false positive"
919
+ end
920
+
921
+ def teardown
922
+ ActiveRecord::Base.lease_connection.disable_query_cache!
923
+ ActiveRecord::Base.lease_connection.drop_table("json_objs", if_exists: true)
924
+ end
925
+ end
926
+
927
+ class QuerySerializedParamTest < ActiveRecord::TestCase
928
+ self.use_transactional_tests = false
929
+
930
+ fixtures :topics
931
+
932
+ class YAMLObj < ActiveRecord::Base
933
+ self.table_name = "yaml_objs"
934
+
935
+ serialize :payload
936
+ end
937
+
938
+ def setup
939
+ @use_yaml_unsafe_load_was = ActiveRecord.use_yaml_unsafe_load
940
+
941
+ ActiveRecord::Base.lease_connection.create_table("yaml_objs", force: true) do |t|
942
+ t.text "payload"
943
+ end
944
+
945
+ ActiveRecord::Base.lease_connection.enable_query_cache!
946
+ end
947
+
948
+ def teardown
949
+ ActiveRecord::Base.lease_connection.disable_query_cache!
950
+ ActiveRecord::Base.lease_connection.drop_table("yaml_objs", if_exists: true)
951
+
952
+ ActiveRecord.use_yaml_unsafe_load = @use_yaml_unsafe_load_was
953
+ end
954
+
955
+ def test_query_serialized_active_record
956
+ skip if current_adapter?(:IBM_DBAdapter)
957
+
958
+ ActiveRecord.use_yaml_unsafe_load = true
959
+
960
+ topic = Topic.first
961
+ assert_not_nil topic
962
+
963
+ obj = YAMLObj.create!(payload: { topic: topic })
964
+
965
+ # This is absolutely terrible, no-one should ever do this
966
+ assert_equal obj, YAMLObj.where(payload: { topic: topic }).first
967
+
968
+ relation = YAMLObj.where(payload: { topic: topic })
969
+ topic.title = "New Title"
970
+ assert_equal obj, relation.first
971
+
972
+ assert_nil YAMLObj.where(payload: { topic: topic }).first
973
+ end
974
+
975
+ def test_query_serialized_string
976
+ ActiveRecord.use_yaml_unsafe_load = false
977
+
978
+ obj = YAMLObj.create!(payload: "payload")
979
+ assert_equal obj, YAMLObj.find_by!(payload: "payload")
980
+ end
981
+ end
982
+
787
983
  class QueryCacheExpiryTest < ActiveRecord::TestCase
788
984
  fixtures :tasks, :posts, :categories, :categories_posts
789
985
 
790
986
  def teardown
791
- Task.connection.clear_query_cache
987
+ Task.lease_connection.clear_query_cache
792
988
  end
793
989
 
794
990
  def test_cache_gets_cleared_after_migration
@@ -796,34 +992,44 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
796
992
  Post.find(1)
797
993
 
798
994
  # change the column definition
799
- Post.connection.change_column :posts, :title, :string, limit: 80
995
+ Post.lease_connection.change_column :posts, :title, :string, limit: 80
800
996
  assert_nothing_raised { Post.find(1) }
801
997
 
802
998
  # restore the old definition
803
- Post.connection.change_column :posts, :title, :string
999
+ Post.lease_connection.change_column :posts, :title, :string
804
1000
  end
805
1001
 
806
1002
  def test_find
807
- assert_called(Task.connection, :clear_query_cache) do
808
- assert_not Task.connection.query_cache_enabled
1003
+ assert_called(Task.connection_pool.query_cache, :clear, times: 1) do
1004
+ assert_not Task.connection_pool.query_cache_enabled
809
1005
  Task.cache do
810
- assert Task.connection.query_cache_enabled
1006
+ assert Task.connection_pool.query_cache_enabled
811
1007
  Task.find(1)
812
1008
 
813
1009
  Task.uncached do
814
- assert_not Task.connection.query_cache_enabled
1010
+ assert_not Task.connection_pool.query_cache_enabled
815
1011
  Task.find(1)
816
1012
  end
817
1013
 
818
- assert Task.connection.query_cache_enabled
1014
+ assert Task.connection_pool.query_cache_enabled
819
1015
  end
820
- assert_not Task.connection.query_cache_enabled
1016
+ assert_not Task.connection_pool.query_cache_enabled
1017
+ end
1018
+ end
1019
+
1020
+ def test_enable_disable
1021
+ assert_called(Task.connection_pool.query_cache, :clear, times: 1) do
1022
+ Task.cache { }
1023
+ end
1024
+
1025
+ assert_called(Task.connection_pool.query_cache, :clear, times: 1) do
1026
+ Task.cache { Task.cache { } }
821
1027
  end
822
1028
  end
823
1029
 
824
1030
  def test_update
825
- assert_called(Task.connection, :clear_query_cache, times: 2) do
826
- Task.cache do
1031
+ Task.cache do
1032
+ assert_called(Task.connection_pool.query_cache, :clear, times: 1) do
827
1033
  task = Task.find(1)
828
1034
  task.starting = Time.now.utc
829
1035
  task.save!
@@ -832,16 +1038,16 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
832
1038
  end
833
1039
 
834
1040
  def test_destroy
835
- assert_called(Task.connection, :clear_query_cache, times: 2) do
836
- Task.cache do
1041
+ Task.cache do
1042
+ assert_called(Task.connection_pool.query_cache, :clear, times: 1) do
837
1043
  Task.find(1).destroy
838
1044
  end
839
1045
  end
840
1046
  end
841
1047
 
842
1048
  def test_insert
843
- assert_called(ActiveRecord::Base.connection, :clear_query_cache, times: 2) do
844
- Task.cache do
1049
+ Task.cache do
1050
+ assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
845
1051
  Task.create!
846
1052
  end
847
1053
  end
@@ -850,40 +1056,46 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
850
1056
  def test_insert_all
851
1057
  skip unless supports_insert_on_duplicate_skip?
852
1058
 
853
- assert_called(ActiveRecord::Base.connection, :clear_query_cache, times: 2) do
854
- Task.cache { Task.insert({ starting: Time.now }) }
855
- end
1059
+ Task.cache do
1060
+ assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
1061
+ Task.insert({ starting: Time.now })
1062
+ end
856
1063
 
857
- assert_called(ActiveRecord::Base.connection, :clear_query_cache, times: 2) do
858
- Task.cache { Task.insert_all([{ starting: Time.now }]) }
1064
+ assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
1065
+ Task.insert_all([{ starting: Time.now }])
1066
+ end
859
1067
  end
860
1068
  end
861
1069
 
862
1070
  def test_insert_all_bang
863
- assert_called(ActiveRecord::Base.connection, :clear_query_cache, times: 2) do
864
- Task.cache { Task.insert!({ starting: Time.now }) }
865
- end
1071
+ Task.cache do
1072
+ assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
1073
+ Task.insert!({ starting: Time.now })
1074
+ end
866
1075
 
867
- assert_called(ActiveRecord::Base.connection, :clear_query_cache, times: 2) do
868
- Task.cache { Task.insert_all!([{ starting: Time.now }]) }
1076
+ assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
1077
+ Task.insert_all!([{ starting: Time.now }])
1078
+ end
869
1079
  end
870
1080
  end
871
1081
 
872
1082
  def test_upsert_all
873
1083
  skip unless supports_insert_on_duplicate_update?
874
1084
 
875
- assert_called(ActiveRecord::Base.connection, :clear_query_cache, times: 2) do
876
- Task.cache { Task.upsert({ starting: Time.now }) }
877
- end
1085
+ Task.cache do
1086
+ assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
1087
+ Task.upsert({ starting: Time.now })
1088
+ end
878
1089
 
879
- assert_called(ActiveRecord::Base.connection, :clear_query_cache, times: 2) do
880
- Task.cache { Task.upsert_all([{ starting: Time.now }]) }
1090
+ assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
1091
+ Task.upsert_all([{ starting: Time.now }])
1092
+ end
881
1093
  end
882
1094
  end
883
1095
 
884
1096
  def test_cache_is_expired_by_habtm_update
885
- assert_called(ActiveRecord::Base.connection, :clear_query_cache, times: 2) do
886
- ActiveRecord::Base.cache do
1097
+ ActiveRecord::Base.cache do
1098
+ assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
887
1099
  c = Category.first
888
1100
  p = Post.first
889
1101
  p.categories << c
@@ -892,8 +1104,8 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
892
1104
  end
893
1105
 
894
1106
  def test_cache_is_expired_by_habtm_delete
895
- assert_called(ActiveRecord::Base.connection, :clear_query_cache, times: 2) do
896
- ActiveRecord::Base.cache do
1107
+ ActiveRecord::Base.cache do
1108
+ assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
897
1109
  p = Post.find(1)
898
1110
  assert_predicate p.categories, :any?
899
1111
  p.categories.delete_all
@@ -901,11 +1113,47 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
901
1113
  end
902
1114
  end
903
1115
 
1116
+ def test_query_cache_lru_eviction
1117
+ store = ActiveRecord::ConnectionAdapters::QueryCache::Store.new(Concurrent::AtomicFixnum.new, 2)
1118
+ store.enabled = true
1119
+
1120
+ connection = Post.lease_connection
1121
+ old_store, connection.query_cache = connection.query_cache, store
1122
+ begin
1123
+ select1 = current_adapter?(:IBM_DBAdapter) ? "SELECT 1 FROM SYSIBM.SYSDUMMY1" : "SELECT 1"
1124
+ select2 = current_adapter?(:IBM_DBAdapter) ? "SELECT 2 FROM SYSIBM.SYSDUMMY1" : "SELECT 2"
1125
+ select3 = current_adapter?(:IBM_DBAdapter) ? "SELECT 3 FROM SYSIBM.SYSDUMMY1" : "SELECT 3"
1126
+
1127
+ Post.cache do
1128
+ assert_queries_count(2) do
1129
+ connection.select_all(select1)
1130
+ connection.select_all(select2)
1131
+ connection.select_all(select1)
1132
+ end
1133
+
1134
+ assert_queries_count(1) do
1135
+ connection.select_all(select3)
1136
+ connection.select_all(select3)
1137
+ end
1138
+
1139
+ assert_no_queries do
1140
+ connection.select_all(select1)
1141
+ end
1142
+
1143
+ assert_queries_count(1) do
1144
+ connection.select_all(select2)
1145
+ end
1146
+ end
1147
+ ensure
1148
+ connection.query_cache = old_store
1149
+ end
1150
+ end
1151
+
904
1152
  test "threads use the same connection" do
905
- @connection_1 = ActiveRecord::Base.connection.object_id
1153
+ @connection_1 = ActiveRecord::Base.lease_connection.object_id
906
1154
 
907
1155
  thread_a = Thread.new do
908
- @connection_2 = ActiveRecord::Base.connection.object_id
1156
+ @connection_2 = ActiveRecord::Base.lease_connection.object_id
909
1157
  end
910
1158
 
911
1159
  thread_a.join
@@ -913,3 +1161,50 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
913
1161
  assert_equal @connection_1, @connection_2
914
1162
  end
915
1163
  end
1164
+
1165
+ class TransactionInCachedSqlActiveRecordPayloadTest < ActiveRecord::TestCase
1166
+ # We need current_transaction to return the null transaction.
1167
+ self.use_transactional_tests = false
1168
+
1169
+ def test_payload_without_open_transaction
1170
+ asserted = false
1171
+
1172
+ subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |event|
1173
+ if event.payload[:cached]
1174
+ assert_nil event.payload.fetch(:transaction)
1175
+ asserted = true
1176
+ end
1177
+ end
1178
+ Task.cache do
1179
+ 2.times { Task.count }
1180
+ end
1181
+
1182
+ assert asserted
1183
+ ensure
1184
+ ActiveSupport::Notifications.unsubscribe(subscriber)
1185
+ end
1186
+
1187
+ def test_payload_with_open_transaction
1188
+ asserted = false
1189
+ expected_transaction = nil
1190
+
1191
+ subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |event|
1192
+ if event.payload[:cached]
1193
+ assert_same expected_transaction, event.payload[:transaction]
1194
+ asserted = true
1195
+ end
1196
+ end
1197
+
1198
+ Task.transaction do |transaction|
1199
+ expected_transaction = transaction
1200
+
1201
+ Task.cache do
1202
+ 2.times { Task.count }
1203
+ end
1204
+ end
1205
+
1206
+ assert asserted
1207
+ ensure
1208
+ ActiveSupport::Notifications.unsubscribe(subscriber)
1209
+ end
1210
+ end