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
@@ -10,14 +10,6 @@ module ActiveRecord
10
10
 
11
11
  fixtures :people
12
12
 
13
- def setup
14
- @handler = ConnectionHandler.new
15
- @owner_name = "ActiveRecord::Base"
16
- db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
17
- @rw_pool = @handler.establish_connection(db_config)
18
- @ro_pool = @handler.establish_connection(db_config, role: :reading)
19
- end
20
-
21
13
  def teardown
22
14
  clean_up_connection_handler
23
15
  end
@@ -29,7 +21,7 @@ module ActiveRecord
29
21
  ActiveRecord::Base.establish_connection(db_config)
30
22
  assert_nothing_raised { Person.first }
31
23
 
32
- assert_equal [:default, :shard_one], ActiveRecord::Base.connection_handler.send(:owner_to_pool_manager).fetch("ActiveRecord::Base").instance_variable_get(:@name_to_role_mapping).values.flat_map(&:keys).uniq
24
+ assert_equal [:default, :shard_one].sort, ActiveRecord::Base.connection_handler.send(:get_pool_manager, "ActiveRecord::Base").shard_names.sort
33
25
  end
34
26
  end
35
27
 
@@ -46,13 +38,14 @@ module ActiveRecord
46
38
  @prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
47
39
 
48
40
  ActiveRecord::Base.connects_to(shards: {
49
- default: { writing: :primary },
50
- shard_one: { writing: :primary_shard_one }
41
+ default: { writing: :primary, reading: :primary },
42
+ shard_one: { writing: :primary_shard_one, reading: :primary_shard_one }
51
43
  })
52
44
 
53
45
  base_pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool("ActiveRecord::Base")
54
46
  default_pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool("ActiveRecord::Base", shard: :default)
55
47
 
48
+ assert_equal [:default, :shard_one], ActiveRecord::Base.connection_handler.send(:get_pool_manager, "ActiveRecord::Base").shard_names
56
49
  assert_equal base_pool, default_pool
57
50
  assert_equal "test/db/primary.sqlite3", default_pool.db_config.database
58
51
  assert_equal "primary", default_pool.db_config.name
@@ -135,7 +128,7 @@ module ActiveRecord
135
128
  assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :default)
136
129
  assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :shard_one)
137
130
  assert_not ActiveRecord::Base.connected_to?(role: :reading, shard: :shard_one)
138
- assert_predicate ActiveRecord::Base.connection, :preventing_writes?
131
+ assert_predicate ActiveRecord::Base.lease_connection, :preventing_writes?
139
132
  end
140
133
 
141
134
  ActiveRecord::Base.connected_to(role: :writing, shard: :default) do
@@ -144,7 +137,7 @@ module ActiveRecord
144
137
  assert_not ActiveRecord::Base.connected_to?(role: :reading, shard: :default)
145
138
  assert_not ActiveRecord::Base.connected_to?(role: :reading, shard: :shard_one)
146
139
  assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :shard_one)
147
- assert_not_predicate ActiveRecord::Base.connection, :preventing_writes?
140
+ assert_not_predicate ActiveRecord::Base.lease_connection, :preventing_writes?
148
141
  end
149
142
 
150
143
  ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one) do
@@ -153,7 +146,7 @@ module ActiveRecord
153
146
  assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :shard_one)
154
147
  assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :default)
155
148
  assert_not ActiveRecord::Base.connected_to?(role: :reading, shard: :default)
156
- assert_predicate ActiveRecord::Base.connection, :preventing_writes?
149
+ assert_predicate ActiveRecord::Base.lease_connection, :preventing_writes?
157
150
  end
158
151
 
159
152
  ActiveRecord::Base.connected_to(role: :writing, shard: :shard_one) do
@@ -162,7 +155,7 @@ module ActiveRecord
162
155
  assert_not ActiveRecord::Base.connected_to?(role: :reading, shard: :shard_one)
163
156
  assert_not ActiveRecord::Base.connected_to?(role: :reading, shard: :default)
164
157
  assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :default)
165
- assert_not_predicate ActiveRecord::Base.connection, :preventing_writes?
158
+ assert_not_predicate ActiveRecord::Base.lease_connection, :preventing_writes?
166
159
  end
167
160
  ensure
168
161
  ActiveRecord::Base.configurations = @prev_configs
@@ -231,11 +224,8 @@ module ActiveRecord
231
224
  end
232
225
 
233
226
  def test_retrieve_connection_pool_with_invalid_shard
234
- assert_not_nil @handler.retrieve_connection_pool("ActiveRecord::Base")
235
- assert_nil @handler.retrieve_connection_pool("ActiveRecord::Base", shard: :foo)
236
-
237
- assert_not_nil @handler.retrieve_connection_pool("ActiveRecord::Base", role: :reading)
238
- assert_nil @handler.retrieve_connection_pool("ActiveRecord::Base", role: :reading, shard: :foo)
227
+ assert_not_nil ActiveRecord::Base.connection_handler.retrieve_connection_pool("ActiveRecord::Base")
228
+ assert_nil ActiveRecord::Base.connection_handler.retrieve_connection_pool("ActiveRecord::Base", shard: :foo)
239
229
  end
240
230
 
241
231
  def test_calling_connected_to_on_a_non_existent_shard_raises
@@ -243,13 +233,106 @@ module ActiveRecord
243
233
  default: { writing: :arunit, reading: :arunit }
244
234
  })
245
235
 
246
- error = assert_raises ActiveRecord::ConnectionNotEstablished do
236
+ error = assert_raises ActiveRecord::ConnectionNotDefined do
247
237
  ActiveRecord::Base.connected_to(role: :reading, shard: :foo) do
248
238
  Person.first
249
239
  end
250
240
  end
251
241
 
252
- assert_equal "No connection pool for 'ActiveRecord::Base' found for the 'foo' shard.", error.message
242
+ assert_equal "No database connection defined for 'foo' shard and 'reading' role.", error.message
243
+ assert_equal "ActiveRecord::Base", error.connection_name
244
+ assert_equal :foo, error.shard
245
+ assert_equal :reading, error.role
246
+ end
247
+
248
+ def test_calling_connected_to_on_a_non_existent_role_for_shard_raises
249
+ ActiveRecord::Base.connects_to(shards: {
250
+ default: { writing: :arunit, reading: :arunit },
251
+ shard_one: { writing: :arunit, reading: :arunit }
252
+ })
253
+
254
+ error = assert_raises ActiveRecord::ConnectionNotDefined do
255
+ ActiveRecord::Base.connected_to(role: :non_existent, shard: :shard_one) do
256
+ Person.first
257
+ end
258
+ end
259
+
260
+ assert_equal "No database connection defined for 'shard_one' shard and 'non_existent' role.", error.message
261
+ assert_equal "ActiveRecord::Base", error.connection_name
262
+ assert_equal :shard_one, error.shard
263
+ assert_equal :non_existent, error.role
264
+ end
265
+
266
+ def test_calling_connected_to_on_a_default_role_for_non_existent_shard_raises
267
+ ActiveRecord::Base.connects_to(shards: {
268
+ default: { writing: :arunit, reading: :arunit }
269
+ })
270
+
271
+ error = assert_raises ActiveRecord::ConnectionNotDefined do
272
+ ActiveRecord::Base.connected_to(shard: :foo) do
273
+ Person.first
274
+ end
275
+ end
276
+
277
+ assert_equal "No database connection defined for 'foo' shard.", error.message
278
+ assert_equal "ActiveRecord::Base", error.connection_name
279
+ assert_equal :foo, error.shard
280
+ assert_equal :writing, error.role
281
+ end
282
+
283
+ def test_cannot_swap_shards_while_prohibited
284
+ previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
285
+
286
+ config = {
287
+ "default_env" => {
288
+ "primary" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3" },
289
+ "primary_shard_one" => { "adapter" => "sqlite3", "database" => "test/db/primary_shard_one.sqlite3" }
290
+ }
291
+ }
292
+
293
+ @prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
294
+
295
+ ActiveRecord::Base.connects_to(shards: {
296
+ default: { writing: :primary },
297
+ shard_one: { writing: :primary_shard_one }
298
+ })
299
+
300
+ assert_raises(ArgumentError) do
301
+ ActiveRecord::Base.prohibit_shard_swapping do
302
+ ActiveRecord::Base.connected_to(role: :reading, shard: :default) do
303
+ end
304
+ end
305
+ end
306
+ ensure
307
+ ActiveRecord::Base.configurations = @prev_configs
308
+ ActiveRecord::Base.establish_connection(:arunit)
309
+ ENV["RAILS_ENV"] = previous_env
310
+ end
311
+
312
+ def test_can_swap_roles_while_shard_swapping_is_prohibited
313
+ previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
314
+
315
+ config = {
316
+ "default_env" => {
317
+ "primary" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3" },
318
+ "primary_replica" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3", "replica" => true }
319
+ }
320
+ }
321
+
322
+ @prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
323
+
324
+ ActiveRecord::Base.connects_to(shards: { default: { writing: :primary, reading: :primary_replica } })
325
+
326
+ assert_nothing_raised do
327
+ ActiveRecord::Base.prohibit_shard_swapping do # no exception
328
+ ActiveRecord::Base.connected_to(role: :reading) do
329
+ end
330
+ end
331
+ end
332
+ ensure
333
+ ActiveRecord::Base.configurations = @prev_configs
334
+ ActiveRecord::Base.establish_connection(:arunit)
335
+ ENV["RAILS_ENV"] = previous_env
253
336
  end
254
337
  end
255
338
 
@@ -267,15 +350,23 @@ module ActiveRecord
267
350
  class ShardConnectionTestModelB < SomeOtherBase
268
351
  end
269
352
 
353
+ def test_default_shard_is_chosen_by_first_key_or_default
354
+ SecondaryBase.connects_to shards: { not_default: { writing: { database: ":memory:", adapter: "sqlite3" } } }
355
+ SomeOtherBase.connects_to database: { writing: { database: ":memory:", adapter: "sqlite3" } }
356
+
357
+ assert_equal :not_default, SecondaryBase.default_shard
358
+ assert_equal :default, SomeOtherBase.default_shard
359
+ end
360
+
270
361
  def test_same_shards_across_clusters
271
362
  SecondaryBase.connects_to shards: { one: { writing: { database: ":memory:", adapter: "sqlite3" } } }
272
363
  SomeOtherBase.connects_to shards: { one: { writing: { database: ":memory:", adapter: "sqlite3" } } }
273
364
 
274
365
  ActiveRecord::Base.connected_to(role: :writing, shard: :one) do
275
- ShardConnectionTestModel.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
366
+ ShardConnectionTestModel.lease_connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
276
367
  ShardConnectionTestModel.create!(shard_key: "test_model_default")
277
368
 
278
- ShardConnectionTestModelB.connection.execute("CREATE TABLE `shard_connection_test_model_bs` (shard_key VARCHAR (255))")
369
+ ShardConnectionTestModelB.lease_connection.execute("CREATE TABLE `shard_connection_test_model_bs` (shard_key VARCHAR (255))")
279
370
  ShardConnectionTestModelB.create!(shard_key: "test_model_b_default")
280
371
 
281
372
  assert_equal "test_model_default", ShardConnectionTestModel.where(shard_key: "test_model_default").first.shard_key
@@ -291,7 +382,7 @@ module ActiveRecord
291
382
 
292
383
  [:default, :one].each do |shard_name|
293
384
  ActiveRecord::Base.connected_to(role: :writing, shard: shard_name) do
294
- ShardConnectionTestModel.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
385
+ ShardConnectionTestModel.lease_connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
295
386
  end
296
387
  end
297
388
 
@@ -327,27 +418,27 @@ module ActiveRecord
327
418
 
328
419
  [:default, :one].each do |shard_name|
329
420
  ActiveRecord::Base.connected_to(role: :writing, shard: shard_name) do
330
- ShardConnectionTestModel.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
331
- ShardConnectionTestModel.connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}')")
421
+ ShardConnectionTestModel.lease_connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
422
+ ShardConnectionTestModel.lease_connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}')")
332
423
  end
333
424
  end
334
425
 
335
426
  shard_one_latch = Concurrent::CountDownLatch.new
336
427
  shard_default_latch = Concurrent::CountDownLatch.new
337
428
 
338
- ShardConnectionTestModel.connection
429
+ ShardConnectionTestModel.lease_connection
339
430
 
340
431
  thread = Thread.new do
341
- ShardConnectionTestModel.connection
432
+ ShardConnectionTestModel.lease_connection
342
433
 
343
434
  shard_default_latch.wait
344
- assert_equal "shard_key_default", ShardConnectionTestModel.connection.select_value("SELECT shard_key from shard_connection_test_models")
435
+ assert_equal "shard_key_default", ShardConnectionTestModel.lease_connection.select_value("SELECT shard_key from shard_connection_test_models")
345
436
  shard_one_latch.count_down
346
437
  end
347
438
 
348
439
  ActiveRecord::Base.connected_to(role: :writing, shard: :one) do
349
440
  shard_default_latch.count_down
350
- assert_equal "shard_key_one", ShardConnectionTestModel.connection.select_value("SELECT shard_key from shard_connection_test_models")
441
+ assert_equal "shard_key_one", ShardConnectionTestModel.lease_connection.select_value("SELECT shard_key from shard_connection_test_models")
351
442
  shard_one_latch.wait
352
443
  end
353
444
 
@@ -372,32 +463,32 @@ module ActiveRecord
372
463
 
373
464
  [:default, :one].each do |shard_name|
374
465
  ActiveRecord::Base.connected_to(role: :writing, shard: shard_name) do
375
- ShardConnectionTestModel.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
376
- ShardConnectionTestModel.connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}')")
466
+ ShardConnectionTestModel.lease_connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
467
+ ShardConnectionTestModel.lease_connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}')")
377
468
  end
378
469
 
379
470
  ActiveRecord::Base.connected_to(role: :secondary, shard: shard_name) do
380
- ShardConnectionTestModel.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
381
- ShardConnectionTestModel.connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}_secondary')")
471
+ ShardConnectionTestModel.lease_connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
472
+ ShardConnectionTestModel.lease_connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}_secondary')")
382
473
  end
383
474
  end
384
475
 
385
476
  shard_one_latch = Concurrent::CountDownLatch.new
386
477
  shard_default_latch = Concurrent::CountDownLatch.new
387
478
 
388
- ShardConnectionTestModel.connection
479
+ ShardConnectionTestModel.lease_connection
389
480
 
390
481
  thread = Thread.new do
391
- ShardConnectionTestModel.connection
482
+ ShardConnectionTestModel.lease_connection
392
483
 
393
484
  shard_default_latch.wait
394
- assert_equal "shard_key_default", ShardConnectionTestModel.connection.select_value("SELECT shard_key from shard_connection_test_models")
485
+ assert_equal "shard_key_default", ShardConnectionTestModel.lease_connection.select_value("SELECT shard_key from shard_connection_test_models")
395
486
  shard_one_latch.count_down
396
487
  end
397
488
 
398
489
  ActiveRecord::Base.connected_to(shard: :one, role: :secondary) do
399
490
  shard_default_latch.count_down
400
- assert_equal "shard_key_one_secondary", ShardConnectionTestModel.connection.select_value("SELECT shard_key from shard_connection_test_models")
491
+ assert_equal "shard_key_one_secondary", ShardConnectionTestModel.lease_connection.select_value("SELECT shard_key from shard_connection_test_models")
401
492
  shard_one_latch.wait
402
493
  end
403
494
 
@@ -435,42 +526,42 @@ module ActiveRecord
435
526
 
436
527
  [:default, :one].each do |shard_name|
437
528
  ActiveRecord::Base.connected_to(role: :writing, shard: shard_name) do
438
- ShardConnectionTestModel.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
439
- ShardConnectionTestModel.connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}')")
440
- ShardConnectionTestModelB.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
441
- ShardConnectionTestModelB.connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}_b')")
529
+ ShardConnectionTestModel.lease_connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
530
+ ShardConnectionTestModel.lease_connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}')")
531
+ ShardConnectionTestModelB.lease_connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
532
+ ShardConnectionTestModelB.lease_connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}_b')")
442
533
  end
443
534
 
444
535
  ActiveRecord::Base.connected_to(role: :secondary, shard: shard_name) do
445
- ShardConnectionTestModel.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
446
- ShardConnectionTestModel.connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}_secondary')")
447
- ShardConnectionTestModelB.connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
448
- ShardConnectionTestModelB.connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}_secondary_b')")
536
+ ShardConnectionTestModel.lease_connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
537
+ ShardConnectionTestModel.lease_connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}_secondary')")
538
+ ShardConnectionTestModelB.lease_connection.execute("CREATE TABLE `shard_connection_test_models` (shard_key VARCHAR (255))")
539
+ ShardConnectionTestModelB.lease_connection.execute("INSERT INTO `shard_connection_test_models` VALUES ('shard_key_#{shard_name}_secondary_b')")
449
540
  end
450
541
  end
451
542
 
452
543
  shard_one_latch = Concurrent::CountDownLatch.new
453
544
  shard_default_latch = Concurrent::CountDownLatch.new
454
545
 
455
- ShardConnectionTestModel.connection
546
+ ShardConnectionTestModel.lease_connection
456
547
 
457
548
  thread = Thread.new do
458
- ShardConnectionTestModel.connection
549
+ ShardConnectionTestModel.lease_connection
459
550
 
460
551
  shard_default_latch.wait
461
- assert_equal "shard_key_default", ShardConnectionTestModel.connection.select_value("SELECT shard_key from shard_connection_test_models")
462
- assert_equal "shard_key_default_b", ShardConnectionTestModelB.connection.select_value("SELECT shard_key from shard_connection_test_models")
552
+ assert_equal "shard_key_default", ShardConnectionTestModel.lease_connection.select_value("SELECT shard_key from shard_connection_test_models")
553
+ assert_equal "shard_key_default_b", ShardConnectionTestModelB.lease_connection.select_value("SELECT shard_key from shard_connection_test_models")
463
554
  shard_one_latch.count_down
464
555
  end
465
556
 
466
557
  SecondaryBase.connected_to(shard: :one, role: :secondary) do
467
558
  shard_default_latch.count_down
468
- assert_equal "shard_key_one_secondary", ShardConnectionTestModel.connection.select_value("SELECT shard_key from shard_connection_test_models")
469
- assert_equal "shard_key_default_b", ShardConnectionTestModelB.connection.select_value("SELECT shard_key from shard_connection_test_models")
559
+ assert_equal "shard_key_one_secondary", ShardConnectionTestModel.lease_connection.select_value("SELECT shard_key from shard_connection_test_models")
560
+ assert_equal "shard_key_default_b", ShardConnectionTestModelB.lease_connection.select_value("SELECT shard_key from shard_connection_test_models")
470
561
 
471
562
  SomeOtherBase.connected_to(shard: :one, role: :secondary) do
472
- assert_equal "shard_key_one_secondary", ShardConnectionTestModel.connection.select_value("SELECT shard_key from shard_connection_test_models")
473
- assert_equal "shard_key_one_secondary_b", ShardConnectionTestModelB.connection.select_value("SELECT shard_key from shard_connection_test_models")
563
+ assert_equal "shard_key_one_secondary", ShardConnectionTestModel.lease_connection.select_value("SELECT shard_key from shard_connection_test_models")
564
+ assert_equal "shard_key_one_secondary_b", ShardConnectionTestModelB.lease_connection.select_value("SELECT shard_key from shard_connection_test_models")
474
565
  end
475
566
  shard_one_latch.wait
476
567
  end
@@ -14,6 +14,16 @@ module ActiveRecord
14
14
  clean_up_connection_handler
15
15
  end
16
16
 
17
+ def skip_unless_sqlite3_gem_available
18
+ @prev_configs ||= ActiveRecord::Base.configurations
19
+
20
+ skip "DB2 limitation: sqlite3-based nested connection swapping scenarios are not supported under ibm_db adapter runs" if current_adapter?(:IBM_DBAdapter)
21
+
22
+ return if Gem::Specification.find_all_by_name("sqlite3", ">= 2.1").any?
23
+
24
+ skip "requires sqlite3 gem (>= 2.1)"
25
+ end
26
+
17
27
  class PrimaryBase < ActiveRecord::Base
18
28
  self.abstract_class = true
19
29
  end
@@ -44,6 +54,8 @@ module ActiveRecord
44
54
 
45
55
  unless in_memory_db?
46
56
  def test_roles_can_be_swapped_granularly
57
+ skip_unless_sqlite3_gem_available
58
+
47
59
  previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
48
60
 
49
61
  config = {
@@ -116,6 +128,8 @@ module ActiveRecord
116
128
  end
117
129
 
118
130
  def test_shards_can_be_swapped_granularly
131
+ skip_unless_sqlite3_gem_available
132
+
119
133
  previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
120
134
 
121
135
  config = {
@@ -156,17 +170,17 @@ module ActiveRecord
156
170
  assert_equal "secondary", SecondaryBase.connection_pool.db_config.name
157
171
 
158
172
  # Switch only primary to shard_one
159
- PrimaryBase.connected_to(role: global_role, shard: :shard_one) do
173
+ PrimaryBase.connected_to(shard: :shard_one) do
160
174
  assert_equal "primary_shard_one", PrimaryBase.connection_pool.db_config.name
161
175
  assert_equal "secondary", SecondaryBase.connection_pool.db_config.name
162
176
 
163
177
  # Switch global to shard_one
164
- ActiveRecord::Base.connected_to(role: global_role, shard: :shard_one) do
178
+ ActiveRecord::Base.connected_to(shard: :shard_one) do
165
179
  assert_equal "primary_shard_one", PrimaryBase.connection_pool.db_config.name
166
180
  assert_equal "secondary_shard_one", SecondaryBase.connection_pool.db_config.name
167
181
 
168
182
  # Switch only secondary to shard_two
169
- SecondaryBase.connected_to(role: global_role, shard: :shard_two) do
183
+ SecondaryBase.connected_to(shard: :shard_two) do
170
184
  assert_equal "primary_shard_one", PrimaryBase.connection_pool.db_config.name
171
185
  assert_equal "secondary_shard_two", SecondaryBase.connection_pool.db_config.name
172
186
  end
@@ -183,7 +197,7 @@ module ActiveRecord
183
197
  end
184
198
 
185
199
  # Switch everything to default
186
- ActiveRecord::Base.connected_to(role: global_role, shard: :default) do
200
+ ActiveRecord::Base.connected_to(shard: :default) do
187
201
  assert_equal "primary", PrimaryBase.connection_pool.db_config.name
188
202
  assert_equal "secondary", SecondaryBase.connection_pool.db_config.name
189
203
  end
@@ -203,7 +217,63 @@ module ActiveRecord
203
217
  ENV["RAILS_ENV"] = previous_env
204
218
  end
205
219
 
220
+ def test_shard_swapping_prohibition_exception_recovery
221
+ skip_unless_sqlite3_gem_available
222
+
223
+ previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
224
+
225
+ config = {
226
+ "default_env" => {
227
+ "primary" => { "adapter" => "sqlite3", "database" => "test/db/primary.sqlite3" },
228
+ "primary_shard_one" => { "adapter" => "sqlite3", "database" => "test/db/primary_shard_one.sqlite3" },
229
+ "primary_shard_two" => { "adapter" => "sqlite3", "database" => "test/db/primary_shard_two.sqlite3" },
230
+ }
231
+ }
232
+
233
+ @prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
234
+
235
+ PrimaryBase.connects_to(shards: {
236
+ default: { writing: :primary },
237
+ shard_one: { writing: :primary_shard_one }
238
+ })
239
+
240
+ global_role = :writing
241
+
242
+ # Switch everything to default
243
+ ActiveRecord::Base.connected_to(role: global_role, shard: :default) do
244
+ assert_equal "primary", PrimaryBase.connection_pool.db_config.name
245
+
246
+ # Switch only primary to shard_one
247
+ PrimaryBase.connected_to(shard: :shard_one) do
248
+ assert_equal "primary_shard_one", PrimaryBase.connection_pool.db_config.name
249
+
250
+ PrimaryBase.prohibit_shard_swapping do
251
+ e = assert_raises(ArgumentError) do
252
+ PrimaryBase.connected_to(shard: :shard_two) { }
253
+ end
254
+ assert_match(/cannot swap/, e.message)
255
+ end
256
+
257
+ assert_equal "primary_shard_one", PrimaryBase.connection_pool.db_config.name
258
+
259
+ PrimaryBase.prohibit_shard_swapping do
260
+ e = assert_raises(ArgumentError) do
261
+ ActiveRecord::Base.connected_to_many([PrimaryBase], shard: :shard_two, role: :writing) { }
262
+ end
263
+ assert_match(/cannot swap/, e.message)
264
+ end
265
+
266
+ assert_equal "primary_shard_one", PrimaryBase.connection_pool.db_config.name
267
+ end
268
+ end
269
+ ensure
270
+ ActiveRecord::Base.configurations = @prev_configs
271
+ ActiveRecord::Base.establish_connection(:arunit)
272
+ ENV["RAILS_ENV"] = previous_env
273
+ end
206
274
  def test_roles_and_shards_can_be_swapped_granularly
275
+ skip_unless_sqlite3_gem_available
276
+
207
277
  previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
208
278
 
209
279
  config = {
@@ -290,6 +360,8 @@ module ActiveRecord
290
360
  end
291
361
 
292
362
  def test_connected_to_many
363
+ skip_unless_sqlite3_gem_available
364
+
293
365
  previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
294
366
 
295
367
  config = {
@@ -366,6 +438,8 @@ module ActiveRecord
366
438
  end
367
439
 
368
440
  def test_prevent_writes_can_be_changed_granularly
441
+ skip_unless_sqlite3_gem_available
442
+
369
443
  previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
370
444
 
371
445
  # replica: true is purposefully left out so we can test the pools behavior
@@ -385,44 +459,44 @@ module ActiveRecord
385
459
 
386
460
  # Switch everything to writing
387
461
  ActiveRecord::Base.connected_to(role: :writing) do
388
- assert_not_predicate ActiveRecord::Base.connection, :preventing_writes?
389
- assert_not_predicate PrimaryBase.connection, :preventing_writes?
390
- assert_not_predicate SecondaryBase.connection, :preventing_writes?
462
+ assert_not_predicate ActiveRecord::Base.lease_connection, :preventing_writes?
463
+ assert_not_predicate PrimaryBase.lease_connection, :preventing_writes?
464
+ assert_not_predicate SecondaryBase.lease_connection, :preventing_writes?
391
465
 
392
466
  # Switch only primary to reading
393
467
  PrimaryBase.connected_to(role: :reading) do
394
- assert_predicate PrimaryBase.connection, :preventing_writes?
395
- assert_not_predicate SecondaryBase.connection, :preventing_writes?
468
+ assert_predicate PrimaryBase.lease_connection, :preventing_writes?
469
+ assert_not_predicate SecondaryBase.lease_connection, :preventing_writes?
396
470
 
397
471
  # Switch global to reading
398
472
  ActiveRecord::Base.connected_to(role: :reading) do
399
- assert_predicate PrimaryBase.connection, :preventing_writes?
400
- assert_predicate SecondaryBase.connection, :preventing_writes?
473
+ assert_predicate PrimaryBase.lease_connection, :preventing_writes?
474
+ assert_predicate SecondaryBase.lease_connection, :preventing_writes?
401
475
 
402
476
  # Switch only secondary to writing
403
477
  SecondaryBase.connected_to(role: :writing) do
404
- assert_predicate PrimaryBase.connection, :preventing_writes?
405
- assert_not_predicate SecondaryBase.connection, :preventing_writes?
478
+ assert_predicate PrimaryBase.lease_connection, :preventing_writes?
479
+ assert_not_predicate SecondaryBase.lease_connection, :preventing_writes?
406
480
  end
407
481
 
408
482
  # Ensure restored to global reading
409
- assert_predicate PrimaryBase.connection, :preventing_writes?
410
- assert_predicate SecondaryBase.connection, :preventing_writes?
483
+ assert_predicate PrimaryBase.lease_connection, :preventing_writes?
484
+ assert_predicate SecondaryBase.lease_connection, :preventing_writes?
411
485
  end
412
486
 
413
487
  # Switch everything to writing
414
488
  ActiveRecord::Base.connected_to(role: :writing) do
415
- assert_not_predicate PrimaryBase.connection, :preventing_writes?
416
- assert_not_predicate SecondaryBase.connection, :preventing_writes?
489
+ assert_not_predicate PrimaryBase.lease_connection, :preventing_writes?
490
+ assert_not_predicate SecondaryBase.lease_connection, :preventing_writes?
417
491
  end
418
492
 
419
- assert_predicate PrimaryBase.connection, :preventing_writes?
420
- assert_not_predicate SecondaryBase.connection, :preventing_writes?
493
+ assert_predicate PrimaryBase.lease_connection, :preventing_writes?
494
+ assert_not_predicate SecondaryBase.lease_connection, :preventing_writes?
421
495
  end
422
496
 
423
497
  # Ensure restored to global writing
424
- assert_not_predicate PrimaryBase.connection, :preventing_writes?
425
- assert_not_predicate SecondaryBase.connection, :preventing_writes?
498
+ assert_not_predicate PrimaryBase.lease_connection, :preventing_writes?
499
+ assert_not_predicate SecondaryBase.lease_connection, :preventing_writes?
426
500
  end
427
501
  ensure
428
502
  ActiveRecord::Base.configurations = @prev_configs
@@ -441,16 +515,55 @@ module ActiveRecord
441
515
 
442
516
  # Switch everything to writing
443
517
  ActiveRecord::Base.connected_to(role: :writing) do
444
- assert_not_predicate ApplicationRecord.connection, :preventing_writes?
518
+ assert_not_predicate ActiveRecord::Base.lease_connection, :preventing_writes?
519
+ assert_not_predicate ApplicationRecord.lease_connection, :preventing_writes?
445
520
 
446
521
  ApplicationRecord.connected_to(role: :reading) do
447
- assert_predicate ApplicationRecord.connection, :preventing_writes?
522
+ assert_predicate ApplicationRecord.lease_connection, :preventing_writes?
523
+ end
524
+
525
+ # reading is fine bc it's looking up by AppRec but writing is not fine
526
+ # bc its looking up by ARB in the stack
527
+ ApplicationRecord.connected_to(role: :writing, prevent_writes: true) do
528
+ assert_predicate ApplicationRecord.lease_connection, :preventing_writes?
448
529
  end
449
530
  end
450
531
  ensure
532
+ ApplicationRecord.remove_connection
533
+ ActiveRecord.application_record_class = nil
451
534
  Object.send(:remove_const, :ApplicationRecord)
452
535
  ActiveRecord::Base.establish_connection :arunit
453
536
  end
537
+
538
+ def test_prevent_writes_handles_class_reloading
539
+ skip "IBM_DB keeps preventing_writes enabled for this class-reloading override path" if current_adapter?(:IBM_DBAdapter)
540
+
541
+ # Regression test for https://github.com/rails/rails/issues/54343
542
+ Object.const_set(:ReloadedRecord, Class.new(ActiveRecord::Base) { self.abstract_class = true })
543
+ ReloadedRecord.connects_to(database: { writing: :arunit, reading: :arunit })
544
+
545
+ ActiveRecord::Base.connected_to(role: :reading, prevent_writes: true) do
546
+ ReloadedRecord.connected_to(role: :writing, prevent_writes: false) do
547
+ assert_not_predicate ReloadedRecord.lease_connection, :preventing_writes?
548
+ end
549
+ end
550
+
551
+ # emulate a reload in development mode
552
+ Object.send(:remove_const, :ReloadedRecord)
553
+ Object.const_set(:ReloadedRecord, Class.new(ActiveRecord::Base) { self.abstract_class = true })
554
+ ReloadedRecord.connects_to(database: { writing: :arunit, reading: :arunit })
555
+
556
+ ActiveRecord::Base.connected_to(role: :reading, prevent_writes: true) do
557
+ ReloadedRecord.connected_to(role: :writing, prevent_writes: false) do
558
+ assert_not_predicate ReloadedRecord.lease_connection, :preventing_writes?
559
+ end
560
+ end
561
+ ensure
562
+ ReloadedRecord.remove_connection if Object.const_defined?(:ReloadedRecord)
563
+ ActiveRecord.application_record_class = nil
564
+ Object.send(:remove_const, :ReloadedRecord) if Object.const_defined?(:ReloadedRecord)
565
+ ActiveRecord::Base.establish_connection :arunit
566
+ end
454
567
  end
455
568
  end
456
569
  end