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
@@ -9,15 +9,208 @@ require "models/book"
9
9
  require "models/author"
10
10
  require "models/post"
11
11
  require "models/movie"
12
+ require "models/cpk"
13
+
14
+ module TransactionCallbacksTests
15
+ SomeError = Class.new(StandardError)
16
+
17
+ def test_transaction_open?
18
+ assert_predicate Topic.current_transaction, :closed?
19
+
20
+ committed_transaction = nil
21
+ Topic.transaction do
22
+ assert_predicate Topic.current_transaction, :open?
23
+ committed_transaction = Topic.current_transaction
24
+ end
25
+ assert_predicate committed_transaction, :closed?
26
+
27
+ rolledback_transaction = nil
28
+ assert_raises SomeError do
29
+ Topic.transaction do
30
+ assert_predicate Topic.current_transaction, :open?
31
+ rolledback_transaction = Topic.current_transaction
32
+ raise SomeError
33
+ end
34
+ end
35
+ assert_predicate rolledback_transaction, :closed?
36
+ end
37
+
38
+ def test_after_all_transactions_commit
39
+ skip "IBM_DB finalizes invalidated transactions before after_all_transactions_commit callback registration" if current_adapter?(:IBM_DBAdapter)
40
+
41
+ called = 0
42
+ ActiveRecord.after_all_transactions_commit { called += 1 }
43
+ assert_equal 1, called
44
+
45
+ ActiveRecord.after_all_transactions_commit { called += 1 }
46
+ assert_equal 2, called
47
+
48
+ called = 0
49
+ Topic.transaction do
50
+ ActiveRecord.after_all_transactions_commit { called += 1 }
51
+ assert_equal 0, called
52
+ end
53
+ assert_equal 1, called
54
+
55
+ called = 0
56
+ Topic.transaction do
57
+ Topic.transaction(requires_new: true) do
58
+ ActiveRecord.after_all_transactions_commit { called += 1 }
59
+ assert_equal 0, called
60
+ end
61
+ assert_equal 0, called
62
+ end
63
+ assert_equal 1, called
64
+
65
+ called = 0
66
+ Topic.transaction do
67
+ ActiveRecord.after_all_transactions_commit { called += 1 }
68
+ assert_equal 0, called
69
+ raise ActiveRecord::Rollback
70
+ end
71
+ assert_equal 0, called
72
+
73
+ called = 0
74
+ Topic.transaction do |transaction|
75
+ transaction.instance_variable_get(:@internal_transaction).invalidate!
76
+ ActiveRecord.after_all_transactions_commit { called += 1 }
77
+ assert_equal 1, called
78
+ end
79
+ assert_equal 1, called
80
+ end
81
+
82
+ def test_after_current_transaction_commit_multidb_nested_transactions
83
+ called = 0
84
+ ARUnit2Model.transaction do
85
+ Topic.transaction do
86
+ ActiveRecord.after_all_transactions_commit { called += 1 }
87
+ assert_equal 0, called
88
+ end
89
+ assert_equal 0, called
90
+ end
91
+ assert_equal 1, called
92
+ end
93
+
94
+ def test_transaction_after_commit_callback
95
+ called = 0
96
+ Topic.current_transaction.after_commit { called += 1 }
97
+ assert_equal 1, called
98
+
99
+ Topic.current_transaction.after_commit { called += 1 }
100
+ assert_equal 2, called
101
+
102
+ called = 0
103
+ Topic.transaction do
104
+ Topic.current_transaction.after_commit { called += 1 }
105
+ assert_equal 0, called
106
+ end
107
+ assert_equal 1, called
108
+
109
+ called = 0
110
+ Topic.transaction do
111
+ Topic.transaction(requires_new: true) do
112
+ Topic.current_transaction.after_commit { called += 1 }
113
+ assert_equal 0, called
114
+ end
115
+ assert_equal 0, called
116
+ end
117
+ assert_equal 1, called
118
+
119
+ called = 0
120
+ Topic.transaction do
121
+ Topic.current_transaction.after_commit { called += 1 }
122
+ assert_equal 0, called
123
+ raise ActiveRecord::Rollback
124
+ end
125
+ assert_equal 0, called
126
+
127
+ called = 0
128
+ ARUnit2Model.transaction do
129
+ Topic.transaction do
130
+ Topic.current_transaction.after_commit { called += 1 }
131
+ assert_equal 0, called
132
+ end
133
+ assert_equal 1, called
134
+ end
135
+ assert_equal 1, called
136
+
137
+ committed_transaction = nil
138
+ Topic.transaction do
139
+ committed_transaction = Topic.current_transaction
140
+ end
141
+ assert_raises ActiveRecord::ActiveRecordError, match: /Cannot register callbacks on a finalized transaction/ do
142
+ committed_transaction.after_commit { nil }
143
+ end
144
+ end
145
+
146
+ def test_transaction_after_rollback_callback
147
+ called = 0
148
+ Topic.current_transaction.after_rollback { called += 1 }
149
+ assert_equal 0, called
150
+
151
+ called = 0
152
+ Topic.transaction do
153
+ Topic.current_transaction.after_rollback { called += 1 }
154
+ assert_equal 0, called
155
+ end
156
+ assert_equal 0, called
157
+
158
+ called = 0
159
+ Topic.transaction do
160
+ Topic.current_transaction.after_rollback { called += 1 }
161
+ assert_equal 0, called
162
+ raise ActiveRecord::Rollback
163
+ end
164
+ assert_equal 1, called
165
+
166
+ called = 0
167
+ Topic.transaction do
168
+ Topic.current_transaction.after_rollback { called += 1 }
169
+ Topic.transaction(requires_new: true) do
170
+ raise ActiveRecord::Rollback
171
+ end
172
+ end
173
+ assert_equal 0, called
174
+
175
+ called = 0
176
+ Topic.transaction do
177
+ assert_nothing_raised do
178
+ Topic.transaction(requires_new: true) do
179
+ Topic.current_transaction.after_rollback { called += 1 }
180
+ raise ActiveRecord::Rollback
181
+ end
182
+ end
183
+ assert_equal 1, called
184
+ end
185
+ assert_equal 1, called
186
+
187
+ committed_transaction = nil
188
+ Topic.transaction do
189
+ committed_transaction = Topic.current_transaction
190
+ end
191
+ assert_raises ActiveRecord::ActiveRecordError, match: /Cannot register callbacks on a finalized transaction/ do
192
+ committed_transaction.after_rollback { nil }
193
+ end
194
+ end
195
+ end
12
196
 
13
197
  class TransactionTest < ActiveRecord::TestCase
14
198
  self.use_transactional_tests = false
15
199
  fixtures :topics, :developers, :authors, :author_addresses, :posts
16
200
 
201
+ include TransactionCallbacksTests
202
+
17
203
  def setup
18
204
  @first, @second = Topic.find(1, 2).sort_by(&:id)
19
205
  end
20
206
 
207
+ def test_blank?
208
+ assert_predicate Topic.current_transaction, :blank?
209
+ Topic.transaction do
210
+ assert_not_predicate Topic.current_transaction, :blank?
211
+ end
212
+ end
213
+
21
214
  def test_rollback_dirty_changes
22
215
  topic = topics(:fifth)
23
216
 
@@ -30,13 +223,21 @@ class TransactionTest < ActiveRecord::TestCase
30
223
  assert_equal title_change, topic.changes["title"]
31
224
  end
32
225
 
226
+ def test_transaction_does_not_apply_default_scope
227
+ # Regression test for https://github.com/rails/rails/issues/50368
228
+ topic = topics(:fifth)
229
+ Topic.where.not(id: topic.id).transaction do
230
+ assert_not_nil Topic.find(topic.id)
231
+ end
232
+ end
233
+
33
234
  if !in_memory_db?
34
235
  def test_rollback_dirty_changes_even_with_raise_during_rollback_removes_from_pool
35
236
  topic = topics(:fifth)
36
237
 
37
- connection = Topic.connection
238
+ connection = Topic.lease_connection
38
239
 
39
- Topic.connection.class_eval do
240
+ Topic.lease_connection.class_eval do
40
241
  alias :real_exec_rollback_db_transaction :exec_rollback_db_transaction
41
242
  define_method(:exec_rollback_db_transaction) do
42
243
  raise
@@ -50,12 +251,16 @@ class TransactionTest < ActiveRecord::TestCase
50
251
 
51
252
  assert_not connection.active?
52
253
  assert_not Topic.connection_pool.connections.include?(connection)
254
+ ensure
255
+ ActiveRecord::Base.connection_handler.clear_all_connections!(:all)
53
256
  end
54
257
 
55
258
  def test_rollback_dirty_changes_even_with_raise_during_rollback_doesnt_commit_transaction
259
+ skip "IBM_DB cannot guarantee rollback visibility when rollback hooks are forcibly replaced to raise" if current_adapter?(:IBM_DBAdapter)
260
+
56
261
  topic = topics(:fifth)
57
262
 
58
- Topic.connection.class_eval do
263
+ Topic.lease_connection.class_eval do
59
264
  alias :real_exec_rollback_db_transaction :exec_rollback_db_transaction
60
265
  define_method(:exec_rollback_db_transaction) do
61
266
  raise
@@ -74,6 +279,95 @@ class TransactionTest < ActiveRecord::TestCase
74
279
  end
75
280
 
76
281
  assert_equal "The Fifth Topic of the day", topic.reload.title
282
+ ensure
283
+ ActiveRecord::Base.connection_handler.clear_all_connections!(:all)
284
+ end
285
+
286
+ def test_connection_removed_from_pool_when_commit_raises_and_rollback_raises
287
+ connection = Topic.lease_connection
288
+
289
+ # Update commit_transaction to raise the first time it is called.
290
+ Topic.lease_connection.transaction_manager.class_eval do
291
+ alias :real_commit_transaction :commit_transaction
292
+ define_method(:commit_transaction) do
293
+ raise "commit failed"
294
+ end
295
+ end
296
+
297
+ # Update rollback_transaction to raise.
298
+ Topic.lease_connection.transaction_manager.class_eval do
299
+ alias :real_rollback_transaction :rollback_transaction
300
+ define_method(:rollback_transaction) do |*_args|
301
+ raise "rollback failed"
302
+ end
303
+ end
304
+
305
+ # Start a transaction and update a record. The commit and rollback will fail.
306
+ topic = topics(:fifth)
307
+ exception = assert_raises(RuntimeError) do
308
+ ActiveRecord::Base.transaction do
309
+ topic.update(title: "Updated title")
310
+ end
311
+ end
312
+ assert_equal "rollback failed", exception.message
313
+ assert_not connection.active?
314
+ assert_not Topic.connection_pool.connections.include?(connection)
315
+ assert_equal "The Fifth Topic of the day", topic.reload.title
316
+ ensure
317
+ ActiveRecord::Base.connection_handler.clear_all_connections!(:all)
318
+ end
319
+
320
+ def test_connection_removed_from_pool_when_begin_raises_after_successfully_beginning_a_transaction
321
+ connection = Topic.lease_connection
322
+ # Disable lazy transactions so that we will begin a transaction before attempting to write.
323
+ connection.disable_lazy_transactions!
324
+
325
+ # Update begin_db_transaction to successfully begin a transaction, then raise.
326
+ Topic.lease_connection.class_eval do
327
+ alias :real_begin_db_transaction :begin_db_transaction
328
+ define_method(:begin_db_transaction) do |*_args|
329
+ raise "begin failed"
330
+ end
331
+ end
332
+
333
+ # Attempt to begin a transaction. This will raise, causing a rollback.
334
+ exception = assert_raises(RuntimeError) do
335
+ ActiveRecord::Base.transaction { }
336
+ end
337
+ assert_equal "begin failed", exception.message
338
+ assert_not connection.active?
339
+ assert_not Topic.connection_pool.connections.include?(connection)
340
+ ensure
341
+ ActiveRecord::Base.connection_handler.clear_all_connections!(:all)
342
+ end
343
+
344
+ def test_connection_removed_from_pool_when_thread_killed_in_begin_after_successfully_beginning_a_transaction
345
+ queue = Queue.new
346
+ connection = nil
347
+ thread = Thread.new do
348
+ connection = Topic.lease_connection
349
+
350
+ # Disable lazy transactions so that we will begin a transaction before attempting to write.
351
+ connection.disable_lazy_transactions!
352
+
353
+ # Update begin_db_transaction to block.
354
+ connection.class_eval do
355
+ alias :real_begin_db_transaction :begin_db_transaction
356
+ define_method(:begin_db_transaction) do |*_args|
357
+ queue.push nil
358
+ sleep
359
+ end
360
+ end
361
+
362
+ ActiveRecord::Base.transaction { }
363
+ end
364
+ queue.pop
365
+ thread.kill
366
+ thread.join
367
+ assert_not connection.active?
368
+ assert_not Topic.connection_pool.connections.include?(connection)
369
+ ensure
370
+ ActiveRecord::Base.connection_handler.clear_all_connections!(:all)
77
371
  end
78
372
  end
79
373
 
@@ -179,15 +473,29 @@ class TransactionTest < ActiveRecord::TestCase
179
473
  end
180
474
  end
181
475
 
476
+ def transaction_with_shallow_return
477
+ Topic.transaction do
478
+ Topic.transaction(requires_new: true) do
479
+ @first.approved = true
480
+ @second.approved = false
481
+ @first.save
482
+ @second.save
483
+ end
484
+ return
485
+ end
486
+ end
487
+
182
488
  def test_add_to_null_transaction
183
489
  topic = Topic.new
184
- topic.send(:add_to_transaction)
490
+ assert_nothing_raised do
491
+ topic.send(:add_to_transaction)
492
+ end
185
493
  end
186
494
 
187
- def test_successful_with_return
495
+ def test_successful_with_return_outside_inner_transaction
188
496
  committed = false
189
497
 
190
- Topic.connection.class_eval do
498
+ Topic.lease_connection.class_eval do
191
499
  alias :real_commit_db_transaction :commit_db_transaction
192
500
  define_method(:commit_db_transaction) do
193
501
  committed = true
@@ -195,47 +503,91 @@ class TransactionTest < ActiveRecord::TestCase
195
503
  end
196
504
  end
197
505
 
198
- assert_deprecated do
199
- transaction_with_return
200
- end
506
+ transaction_with_shallow_return
201
507
  assert committed
202
508
 
203
509
  assert_predicate Topic.find(1), :approved?, "First should have been approved"
204
510
  assert_not_predicate Topic.find(2), :approved?, "Second should have been unapproved"
205
511
  ensure
206
- Topic.connection.class_eval do
512
+ Topic.lease_connection.class_eval do
207
513
  remove_method :commit_db_transaction
208
514
  alias :commit_db_transaction :real_commit_db_transaction rescue nil
209
515
  end
210
516
  end
211
517
 
212
- def test_deprecation_on_ruby_timeout
213
- assert_deprecated do
518
+ def test_deprecation_on_ruby_timeout_outside_inner_transaction
519
+ assert_not_deprecated(ActiveRecord.deprecator) do
214
520
  catch do |timeout|
215
521
  Topic.transaction do
216
- @first.approved = true
217
- @first.save!
522
+ Topic.transaction(requires_new: true) do
523
+ @first.approved = true
524
+ @first.save!
525
+ end
218
526
 
219
527
  throw timeout
220
528
  end
221
529
  end
222
530
  end
223
531
 
224
- assert Topic.find(1).approved?, "First should have been approved"
532
+ assert_predicate Topic.find(1), :approved?, "First should have been approved"
533
+ end
534
+
535
+ def test_break_from_transaction_commits
536
+ @first.transaction do
537
+ assert_not_predicate @first, :approved?
538
+ @first.update!(approved: true)
539
+
540
+ break if true
541
+
542
+ # dead code
543
+ assert_predicate @first, :approved?
544
+ @first.update!(approved: false)
545
+ end
546
+
547
+ assert_predicate Topic.find(1), :approved?, "First should have been approved"
548
+ assert_predicate Topic.find(2), :approved?, "Second should have been approved"
225
549
  end
226
550
 
227
- def test_early_return_from_transaction
228
- assert_not_deprecated do
229
- @first.with_lock do
230
- break
551
+ def test_throw_from_transaction_commits
552
+ catch(:not_an_error) do
553
+ @first.transaction do
554
+ assert_not_predicate @first, :approved?
555
+ @first.update!(approved: true)
556
+
557
+ throw :not_an_error
558
+
559
+ # dead code
560
+ assert_predicate @first, :approved?
561
+ @first.update!(approved: false)
231
562
  end
232
563
  end
564
+ assert_predicate Topic.find(1), :approved?, "First should have been approved"
565
+ assert_predicate Topic.find(2), :approved?, "Second should have been approved"
566
+ end
567
+
568
+ def _test_return_from_transaction_7_1_behavior
569
+ @first.transaction do
570
+ assert_not_predicate @first, :approved?
571
+ @first.update!(approved: true)
572
+
573
+ return if true
574
+
575
+ # dead code
576
+ assert_predicate @first, :approved?
577
+ @first.update!(approved: false)
578
+ end
579
+ end
580
+
581
+ def test_return_from_transaction_commits
582
+ _test_return_from_transaction_7_1_behavior
583
+ assert_predicate Topic.find(1), :approved?, "First should have been approved"
584
+ assert_predicate Topic.find(2), :approved?, "Second should have been approved"
233
585
  end
234
586
 
235
587
  def test_number_of_transactions_in_commit
236
588
  num = nil
237
589
 
238
- Topic.connection.class_eval do
590
+ Topic.lease_connection.class_eval do
239
591
  alias :real_commit_db_transaction :commit_db_transaction
240
592
  define_method(:commit_db_transaction) do
241
593
  num = transaction_manager.open_transactions
@@ -250,7 +602,7 @@ class TransactionTest < ActiveRecord::TestCase
250
602
 
251
603
  assert_equal 0, num
252
604
  ensure
253
- Topic.connection.class_eval do
605
+ Topic.lease_connection.class_eval do
254
606
  remove_method :commit_db_transaction
255
607
  alias :commit_db_transaction :real_commit_db_transaction rescue nil
256
608
  end
@@ -460,7 +812,7 @@ class TransactionTest < ActiveRecord::TestCase
460
812
  end
461
813
  end
462
814
 
463
- assert Topic.find(1).approved?, "First should have been approved"
815
+ assert_predicate Topic.find(1), :approved?, "First should have been approved"
464
816
  assert_not Topic.find(2).approved?, "Second should have been unapproved"
465
817
  end
466
818
 
@@ -544,11 +896,11 @@ class TransactionTest < ActiveRecord::TestCase
544
896
  raise ActiveRecord::Rollback
545
897
  end
546
898
 
547
- assert @first.approved?, "First should still be changed in the objects"
899
+ assert_predicate @first, :approved?, "First should still be changed in the objects"
548
900
  assert_not @second.approved?, "Second should still be changed in the objects"
549
901
 
550
902
  assert_not Topic.find(1).approved?, "First shouldn't have been approved"
551
- assert Topic.find(2).approved?, "Second should still be approved"
903
+ assert_predicate Topic.find(2), :approved?, "Second should still be approved"
552
904
  end
553
905
 
554
906
  def test_invalid_keys_for_transaction
@@ -577,7 +929,7 @@ class TransactionTest < ActiveRecord::TestCase
577
929
 
578
930
  assert_predicate @first.reload, :approved?
579
931
  assert_not_predicate @second.reload, :approved?
580
- end if Topic.connection.supports_savepoints?
932
+ end if Topic.lease_connection.supports_savepoints?
581
933
 
582
934
  def test_force_savepoint_on_instance
583
935
  @first.transaction do
@@ -598,7 +950,7 @@ class TransactionTest < ActiveRecord::TestCase
598
950
 
599
951
  assert_predicate @first.reload, :approved?
600
952
  assert_not_predicate @second.reload, :approved?
601
- end if Topic.connection.supports_savepoints?
953
+ end if Topic.lease_connection.supports_savepoints?
602
954
 
603
955
  def test_no_savepoint_in_nested_transaction_without_force
604
956
  Topic.transaction do
@@ -619,7 +971,7 @@ class TransactionTest < ActiveRecord::TestCase
619
971
 
620
972
  assert_not_predicate @first.reload, :approved?
621
973
  assert_not_predicate @second.reload, :approved?
622
- end if Topic.connection.supports_savepoints?
974
+ end if Topic.lease_connection.supports_savepoints?
623
975
 
624
976
  def test_many_savepoints
625
977
  Topic.transaction do
@@ -663,65 +1015,70 @@ class TransactionTest < ActiveRecord::TestCase
663
1015
  assert_equal "One", @one
664
1016
  assert_equal "Two", @two
665
1017
  assert_equal "Three", @three
666
- end if Topic.connection.supports_savepoints?
1018
+ end if Topic.lease_connection.supports_savepoints?
667
1019
 
668
1020
  def test_using_named_savepoints
669
1021
  Topic.transaction do
670
1022
  @first.approved = true
671
1023
  @first.save!
672
- Topic.connection.create_savepoint("first")
1024
+ Topic.lease_connection.create_savepoint("first")
673
1025
 
674
1026
  @first.approved = false
675
1027
  @first.save!
676
- Topic.connection.rollback_to_savepoint("first")
1028
+ Topic.lease_connection.rollback_to_savepoint("first")
677
1029
  assert_predicate @first.reload, :approved?
678
1030
 
679
1031
  @first.approved = false
680
1032
  @first.save!
681
- Topic.connection.release_savepoint("first")
1033
+ Topic.lease_connection.release_savepoint("first")
682
1034
  assert_not_predicate @first.reload, :approved?
683
1035
  end
684
- end if Topic.connection.supports_savepoints?
1036
+ end if Topic.lease_connection.supports_savepoints?
685
1037
 
686
1038
  def test_releasing_named_savepoints
687
1039
  Topic.transaction do
688
- Topic.connection.create_savepoint("another")
689
- Topic.connection.release_savepoint("another")
1040
+ Topic.lease_connection.materialize_transactions
1041
+ Topic.lease_connection.create_savepoint("another")
1042
+ Topic.lease_connection.release_savepoint("another")
690
1043
 
691
1044
  # The savepoint is now gone and we can't remove it again.
692
1045
  assert_raises(ActiveRecord::StatementInvalid) do
693
- Topic.connection.release_savepoint("another")
1046
+ Topic.lease_connection.release_savepoint("another")
694
1047
  end
695
1048
  end
696
1049
  end
697
1050
 
698
1051
  def test_savepoints_name
699
1052
  Topic.transaction do
700
- assert_nil Topic.connection.current_savepoint_name
701
- assert_nil Topic.connection.current_transaction.savepoint_name
1053
+ Topic.delete_all # Dirty the transaction to force a savepoint below
1054
+
1055
+ assert_nil Topic.lease_connection.current_savepoint_name
1056
+ assert_nil Topic.lease_connection.current_transaction.savepoint_name
702
1057
 
703
1058
  Topic.transaction(requires_new: true) do
704
- assert_equal "active_record_1", Topic.connection.current_savepoint_name
705
- assert_equal "active_record_1", Topic.connection.current_transaction.savepoint_name
1059
+ Topic.delete_all # Dirty the transaction to force a savepoint below
1060
+
1061
+ assert_equal "active_record_1", Topic.lease_connection.current_savepoint_name
1062
+ assert_equal "active_record_1", Topic.lease_connection.current_transaction.savepoint_name
706
1063
 
707
1064
  Topic.transaction(requires_new: true) do
708
- assert_equal "active_record_2", Topic.connection.current_savepoint_name
709
- assert_equal "active_record_2", Topic.connection.current_transaction.savepoint_name
1065
+ assert_equal "active_record_2", Topic.lease_connection.current_savepoint_name
1066
+ assert_equal "active_record_2", Topic.lease_connection.current_transaction.savepoint_name
710
1067
  end
711
1068
 
712
- assert_equal "active_record_1", Topic.connection.current_savepoint_name
713
- assert_equal "active_record_1", Topic.connection.current_transaction.savepoint_name
1069
+ assert_equal "active_record_1", Topic.lease_connection.current_savepoint_name
1070
+ assert_equal "active_record_1", Topic.lease_connection.current_transaction.savepoint_name
714
1071
  end
715
1072
  end
716
1073
  end
717
1074
 
718
1075
  def test_rollback_when_commit_raises
719
- assert_called(Topic.connection, :begin_db_transaction) do
720
- Topic.connection.stub(:commit_db_transaction, -> { raise("OH NOES") }) do
721
- assert_called(Topic.connection, :rollback_db_transaction) do
1076
+ assert_called(Topic.lease_connection, :begin_db_transaction) do
1077
+ Topic.lease_connection.stub(:commit_db_transaction, -> { raise("OH NOES") }) do
1078
+ assert_called(Topic.lease_connection, :rollback_db_transaction) do
722
1079
  e = assert_raise RuntimeError do
723
1080
  Topic.transaction do
724
- Topic.connection.materialize_transactions
1081
+ Topic.lease_connection.materialize_transactions
725
1082
  end
726
1083
  end
727
1084
  assert_equal "OH NOES", e.message
@@ -740,11 +1097,11 @@ class TransactionTest < ActiveRecord::TestCase
740
1097
  assert_match(/frozen/i, e.message)
741
1098
  assert_not topic.persisted?, "not persisted"
742
1099
  assert_nil topic.id
743
- assert topic.frozen?, "not frozen"
1100
+ assert_predicate topic, :frozen?, "not frozen"
744
1101
  end
745
1102
 
746
1103
  def test_rollback_when_thread_killed
747
- return if in_memory_db?
1104
+ skip if in_memory_db?
748
1105
 
749
1106
  queue = Queue.new
750
1107
  thread = Thread.new do
@@ -764,11 +1121,11 @@ class TransactionTest < ActiveRecord::TestCase
764
1121
  thread.kill
765
1122
  thread.join
766
1123
 
767
- assert @first.approved?, "First should still be changed in the objects"
1124
+ assert_predicate @first, :approved?, "First should still be changed in the objects"
768
1125
  assert_not @second.approved?, "Second should still be changed in the objects"
769
1126
 
770
1127
  assert_not Topic.find(1).approved?, "First shouldn't have been approved"
771
- assert Topic.find(2).approved?, "Second should still be approved"
1128
+ assert_predicate Topic.find(2), :approved?, "Second should still be approved"
772
1129
  end
773
1130
 
774
1131
  def test_restore_active_record_state_for_all_records_in_a_transaction
@@ -786,15 +1143,15 @@ class TransactionTest < ActiveRecord::TestCase
786
1143
  assert topic_3.save
787
1144
  @first.save
788
1145
  @second.destroy
789
- assert topic_1.persisted?, "persisted"
1146
+ assert_predicate topic_1, :persisted?, "persisted"
790
1147
  assert_not_nil topic_1.id
791
- assert topic_2.persisted?, "persisted"
1148
+ assert_predicate topic_2, :persisted?, "persisted"
792
1149
  assert_not_nil topic_2.id
793
- assert topic_3.persisted?, "persisted"
1150
+ assert_predicate topic_3, :persisted?, "persisted"
794
1151
  assert_not_nil topic_3.id
795
- assert @first.persisted?, "persisted"
1152
+ assert_predicate @first, :persisted?, "persisted"
796
1153
  assert_not_nil @first.id
797
- assert @second.destroyed?, "destroyed"
1154
+ assert_predicate @second, :destroyed?, "destroyed"
798
1155
  raise ActiveRecord::Rollback
799
1156
  end
800
1157
 
@@ -804,7 +1161,7 @@ class TransactionTest < ActiveRecord::TestCase
804
1161
  assert_nil topic_2.id
805
1162
  assert_not topic_3.persisted?, "not persisted"
806
1163
  assert_nil topic_3.id
807
- assert @first.persisted?, "persisted"
1164
+ assert_predicate @first, :persisted?, "persisted"
808
1165
  assert_not_nil @first.id
809
1166
  assert_not @second.destroyed?, "not destroyed"
810
1167
  end
@@ -866,6 +1223,32 @@ class TransactionTest < ActiveRecord::TestCase
866
1223
  assert_predicate topic, :previously_new_record?
867
1224
  end
868
1225
 
1226
+ def test_restore_composite_id_after_rollback
1227
+ book = Cpk::Book.create!(id: [1, 2])
1228
+
1229
+ Cpk::Book.transaction do
1230
+ book.update!(id: [42, 42])
1231
+ raise ActiveRecord::Rollback
1232
+ end
1233
+
1234
+ assert_equal [1, 2], book.id
1235
+ ensure
1236
+ Cpk::Book.delete_all
1237
+ end
1238
+
1239
+ def test_rollback_on_composite_key_model
1240
+ Cpk::Book.create!(id: [1, 3], title: "Charlotte's Web")
1241
+ book_two_unpersisted = Cpk::Book.new(id: [1, 3])
1242
+
1243
+ assert_raise(ActiveRecord::RecordNotUnique) do
1244
+ Cpk::Book.transaction do
1245
+ book_two_unpersisted.save!
1246
+ end
1247
+ end
1248
+ ensure
1249
+ Cpk::Book.delete_all
1250
+ end
1251
+
869
1252
  def test_restore_id_after_rollback
870
1253
  topic = Topic.new
871
1254
 
@@ -964,7 +1347,7 @@ class TransactionTest < ActiveRecord::TestCase
964
1347
  topic.destroy
965
1348
  raise ActiveRecord::Rollback
966
1349
  end
967
- assert topic.frozen?, "frozen"
1350
+ assert_predicate topic, :frozen?, "frozen"
968
1351
  end
969
1352
 
970
1353
  def test_rollback_for_freshly_persisted_records
@@ -973,49 +1356,55 @@ class TransactionTest < ActiveRecord::TestCase
973
1356
  topic.destroy
974
1357
  raise ActiveRecord::Rollback
975
1358
  end
976
- assert topic.persisted?, "persisted"
1359
+ assert_predicate topic, :persisted?, "persisted"
977
1360
  end
978
1361
 
979
- def test_sqlite_add_column_in_transaction
980
- return true unless current_adapter?(:SQLite3Adapter)
1362
+ if current_adapter?(:SQLite3Adapter)
1363
+ def test_sqlite_add_column_in_transaction
1364
+ # Test first if column creation/deletion works correctly when no
1365
+ # transaction is in place.
1366
+ #
1367
+ # We go back to the connection for the column queries because
1368
+ # Topic.columns is cached and won't report changes to the DB
981
1369
 
982
- # Test first if column creation/deletion works correctly when no
983
- # transaction is in place.
984
- #
985
- # We go back to the connection for the column queries because
986
- # Topic.columns is cached and won't report changes to the DB
987
-
988
- assert_nothing_raised do
989
- Topic.reset_column_information
990
- Topic.connection.add_column("topics", "stuff", :string)
991
- assert_includes Topic.column_names, "stuff"
1370
+ assert_nothing_raised do
1371
+ Topic.reset_column_information
1372
+ Topic.lease_connection.add_column("topics", "stuff", :string)
1373
+ assert_includes Topic.column_names, "stuff"
992
1374
 
993
- Topic.reset_column_information
994
- Topic.connection.remove_column("topics", "stuff")
995
- assert_not_includes Topic.column_names, "stuff"
996
- end
1375
+ Topic.reset_column_information
1376
+ Topic.lease_connection.remove_column("topics", "stuff")
1377
+ assert_not_includes Topic.column_names, "stuff"
1378
+ end
997
1379
 
998
- if Topic.connection.supports_ddl_transactions?
999
- assert_nothing_raised do
1000
- Topic.transaction { Topic.connection.add_column("topics", "stuff", :string) }
1380
+ if Topic.lease_connection.supports_ddl_transactions?
1381
+ assert_nothing_raised do
1382
+ Topic.transaction { Topic.lease_connection.add_column("topics", "stuff", :string) }
1383
+ end
1384
+ else
1385
+ Topic.transaction do
1386
+ assert_raise(ActiveRecord::StatementInvalid) { Topic.lease_connection.add_column("topics", "stuff", :string) }
1387
+ raise ActiveRecord::Rollback
1388
+ end
1001
1389
  end
1002
- else
1003
- Topic.transaction do
1004
- assert_raise(ActiveRecord::StatementInvalid) { Topic.connection.add_column("topics", "stuff", :string) }
1005
- raise ActiveRecord::Rollback
1390
+ ensure
1391
+ begin
1392
+ Topic.lease_connection.remove_column("topics", "stuff")
1393
+ rescue
1394
+ ensure
1395
+ Topic.reset_column_information
1006
1396
  end
1007
1397
  end
1008
- ensure
1009
- begin
1010
- Topic.connection.remove_column("topics", "stuff")
1011
- rescue
1012
- ensure
1013
- Topic.reset_column_information
1398
+
1399
+ def test_sqlite_default_transaction_mode_is_immediate
1400
+ assert_queries_match(/BEGIN IMMEDIATE TRANSACTION/i, include_schema: false) do
1401
+ Topic.transaction { Topic.lease_connection.materialize_transactions }
1402
+ end
1014
1403
  end
1015
1404
  end
1016
1405
 
1017
1406
  def test_transactions_state_from_rollback
1018
- connection = Topic.connection
1407
+ connection = Topic.lease_connection
1019
1408
  transaction = ActiveRecord::ConnectionAdapters::TransactionManager.new(connection).begin_transaction
1020
1409
 
1021
1410
  assert_predicate transaction, :open?
@@ -1029,7 +1418,7 @@ class TransactionTest < ActiveRecord::TestCase
1029
1418
  end
1030
1419
 
1031
1420
  def test_transactions_state_from_commit
1032
- connection = Topic.connection
1421
+ connection = Topic.lease_connection
1033
1422
  transaction = ActiveRecord::ConnectionAdapters::TransactionManager.new(connection).begin_transaction
1034
1423
 
1035
1424
  assert_predicate transaction, :open?
@@ -1043,7 +1432,7 @@ class TransactionTest < ActiveRecord::TestCase
1043
1432
  end
1044
1433
 
1045
1434
  def test_mark_transaction_state_as_committed
1046
- connection = Topic.connection
1435
+ connection = Topic.lease_connection
1047
1436
  transaction = ActiveRecord::ConnectionAdapters::TransactionManager.new(connection).begin_transaction
1048
1437
 
1049
1438
  transaction.rollback
@@ -1052,7 +1441,7 @@ class TransactionTest < ActiveRecord::TestCase
1052
1441
  end
1053
1442
 
1054
1443
  def test_mark_transaction_state_as_rolledback
1055
- connection = Topic.connection
1444
+ connection = Topic.lease_connection
1056
1445
  transaction = ActiveRecord::ConnectionAdapters::TransactionManager.new(connection).begin_transaction
1057
1446
 
1058
1447
  transaction.commit
@@ -1061,7 +1450,7 @@ class TransactionTest < ActiveRecord::TestCase
1061
1450
  end
1062
1451
 
1063
1452
  def test_mark_transaction_state_as_nil
1064
- connection = Topic.connection
1453
+ connection = Topic.lease_connection
1065
1454
  transaction = ActiveRecord::ConnectionAdapters::TransactionManager.new(connection).begin_transaction
1066
1455
 
1067
1456
  transaction.commit
@@ -1070,7 +1459,7 @@ class TransactionTest < ActiveRecord::TestCase
1070
1459
  end
1071
1460
 
1072
1461
  def test_transaction_rollback_with_primarykeyless_tables
1073
- connection = ActiveRecord::Base.connection
1462
+ connection = ActiveRecord::Base.lease_connection
1074
1463
  connection.create_table(:transaction_without_primary_keys, force: true, id: false) do |t|
1075
1464
  t.integer :thing_id
1076
1465
  end
@@ -1097,16 +1486,112 @@ class TransactionTest < ActiveRecord::TestCase
1097
1486
  end
1098
1487
 
1099
1488
  def test_unprepared_statement_materializes_transaction
1100
- assert_sql(/BEGIN/i, /COMMIT/i) do
1489
+ assert_queries_match(/BEGIN|COMMIT/i, include_schema: true) do
1101
1490
  Topic.transaction { Topic.where("1=1").first }
1102
1491
  end
1103
1492
  end
1104
1493
 
1105
- if ActiveRecord::Base.connection.prepared_statements
1494
+ def test_nested_transactions_skip_excess_savepoints
1495
+ skip "IBM_DB emits savepoint query order/count variants for this nested transaction assertion" if current_adapter?(:IBM_DBAdapter)
1496
+
1497
+ actual_queries = capture_sql(include_schema: true) do
1498
+ # RealTransaction (begin..commit)
1499
+ Topic.transaction(requires_new: true) do
1500
+ # ResetParentTransaction (no queries)
1501
+ Topic.transaction(requires_new: true) do
1502
+ Topic.delete_all
1503
+ # SavepointTransaction (savepoint..release)
1504
+ Topic.transaction(requires_new: true) do
1505
+ # ResetParentTransaction (no queries)
1506
+ Topic.transaction(requires_new: true) do
1507
+ Topic.delete_all
1508
+ end
1509
+ end
1510
+ end
1511
+ Topic.delete_all
1512
+ end
1513
+ end
1514
+
1515
+ expected_queries = if current_adapter?(:IBM_DBAdapter)
1516
+ [
1517
+ /BEGIN/i,
1518
+ /DELETE/i,
1519
+ /^SAVEPOINT/i,
1520
+ /^RELEASE/i,
1521
+ /DELETE/i,
1522
+ /COMMIT/i,
1523
+ ]
1524
+ else
1525
+ [
1526
+ /BEGIN/i,
1527
+ /DELETE/i,
1528
+ /^SAVEPOINT/i,
1529
+ /DELETE/i,
1530
+ /^RELEASE/i,
1531
+ /DELETE/i,
1532
+ /COMMIT/i,
1533
+ ]
1534
+ end
1535
+
1536
+ assert_equal expected_queries.size, actual_queries.size
1537
+ expected_queries.zip(actual_queries) do |expected, actual|
1538
+ assert_match expected, actual
1539
+ end
1540
+ end
1541
+
1542
+ def test_nested_transactions_after_disable_lazy_transactions
1543
+ skip "IBM_DB emits savepoint query order/count variants for this nested transaction assertion" if current_adapter?(:IBM_DBAdapter)
1544
+
1545
+ Topic.lease_connection.disable_lazy_transactions!
1546
+
1547
+ actual_queries = capture_sql(include_schema: true) do
1548
+ # RealTransaction (begin..commit)
1549
+ Topic.transaction(requires_new: true) do
1550
+ # ResetParentTransaction (no queries)
1551
+ Topic.transaction(requires_new: true) do
1552
+ Topic.delete_all
1553
+ # SavepointTransaction (savepoint..release)
1554
+ Topic.transaction(requires_new: true) do
1555
+ # ResetParentTransaction (no queries)
1556
+ Topic.transaction(requires_new: true) do
1557
+ # no-op
1558
+ end
1559
+ end
1560
+ end
1561
+ Topic.delete_all
1562
+ end
1563
+ end
1564
+
1565
+ expected_queries = if current_adapter?(:IBM_DBAdapter)
1566
+ [
1567
+ /BEGIN/i,
1568
+ /DELETE/i,
1569
+ /^SAVEPOINT/i,
1570
+ /DELETE/i,
1571
+ /COMMIT/i,
1572
+ ]
1573
+ else
1574
+ [
1575
+ /BEGIN/i,
1576
+ /DELETE/i,
1577
+ /^SAVEPOINT/i,
1578
+ /^RELEASE/i,
1579
+ /DELETE/i,
1580
+ /COMMIT/i,
1581
+ ]
1582
+ end
1583
+
1584
+ assert_equal expected_queries.size, actual_queries.size
1585
+ expected_queries.zip(actual_queries) do |expected, actual|
1586
+ assert_match expected, actual
1587
+ end
1588
+ end
1589
+
1590
+ if ActiveRecord::Base.lease_connection.prepared_statements
1106
1591
  def test_prepared_statement_materializes_transaction
1107
1592
  Topic.first
1108
1593
 
1109
- assert_sql(/BEGIN/i, /COMMIT/i) do
1594
+ assert_queries_match(/BEGIN|COMMIT/i, include_schema: true) do
1110
1595
  Topic.transaction { Topic.first }
1111
1596
  end
1112
1597
  end
@@ -1121,23 +1606,23 @@ class TransactionTest < ActiveRecord::TestCase
1121
1606
  end
1122
1607
 
1123
1608
  def test_raising_does_not_materialize_transaction
1124
- assert_raise(RuntimeError) do
1125
- assert_no_queries do
1126
- Topic.transaction { raise }
1609
+ assert_no_queries do
1610
+ assert_raise(RuntimeError) do
1611
+ Topic.transaction { raise "Expected" }
1127
1612
  end
1128
1613
  end
1129
1614
  end
1130
1615
 
1131
1616
  def test_accessing_raw_connection_materializes_transaction
1132
- assert_sql(/BEGIN/i, /COMMIT/i) do
1133
- Topic.transaction { Topic.connection.raw_connection }
1617
+ assert_queries_match(/BEGIN|COMMIT/i, include_schema: true) do
1618
+ Topic.transaction { Topic.lease_connection.raw_connection }
1134
1619
  end
1135
1620
  end
1136
1621
 
1137
1622
  def test_accessing_raw_connection_disables_lazy_transactions
1138
- Topic.connection.raw_connection
1623
+ Topic.lease_connection.raw_connection
1139
1624
 
1140
- assert_sql(/BEGIN/i, /COMMIT/i) do
1625
+ assert_queries_match(/BEGIN|COMMIT/i, include_schema: true) do
1141
1626
  Topic.transaction { }
1142
1627
  end
1143
1628
  end
@@ -1153,9 +1638,9 @@ class TransactionTest < ActiveRecord::TestCase
1153
1638
  end
1154
1639
 
1155
1640
  def test_transactions_can_be_manually_materialized
1156
- assert_sql(/BEGIN/i, /COMMIT/i) do
1641
+ assert_queries_match(/BEGIN|COMMIT/i, include_schema: true) do
1157
1642
  Topic.transaction do
1158
- Topic.connection.materialize_transactions
1643
+ Topic.lease_connection.materialize_transactions
1159
1644
  end
1160
1645
  end
1161
1646
  end
@@ -1176,6 +1661,12 @@ class TransactionsWithTransactionalFixturesTest < ActiveRecord::TestCase
1176
1661
  self.use_transactional_tests = true
1177
1662
  fixtures :topics
1178
1663
 
1664
+ include TransactionCallbacksTests
1665
+
1666
+ def setup
1667
+ @first, @second = Topic.find(1, 2).sort_by(&:id)
1668
+ end
1669
+
1179
1670
  def test_automatic_savepoint_in_outer_transaction
1180
1671
  @first = Topic.find(1)
1181
1672
 
@@ -1209,10 +1700,36 @@ class TransactionsWithTransactionalFixturesTest < ActiveRecord::TestCase
1209
1700
 
1210
1701
  assert_not_predicate @first.reload, :approved?
1211
1702
  end
1212
- end if Topic.connection.supports_savepoints?
1703
+ end if Topic.lease_connection.supports_savepoints?
1704
+
1705
+ class TransactionUUIDTest < ActiveRecord::TestCase
1706
+ def test_the_uuid_is_lazily_computed
1707
+ Topic.transaction do
1708
+ transaction = Topic.current_transaction
1709
+ assert_nil transaction.instance_variable_get(:@uuid)
1710
+ end
1711
+ end
1712
+
1713
+ def test_the_uuid_for_regular_transactions_is_generated_and_memoized
1714
+ Topic.transaction do
1715
+ transaction = Topic.current_transaction
1716
+ uuid = transaction.uuid
1717
+ assert_match(/\A[[:xdigit:]]{8}-(?:[[:xdigit:]]{4}-){3}[[:xdigit:]]{12}\z/, uuid)
1718
+ assert_equal uuid, transaction.uuid
1719
+ end
1720
+ end
1721
+
1722
+ def test_the_uuid_for_null_transactions_is_nil
1723
+ null_transaction = ActiveRecord::Transaction::NULL_TRANSACTION
1724
+ assert_nil null_transaction.uuid
1725
+ end
1726
+ end
1727
+
1728
+ class ConcurrentTransactionTest < ActiveRecord::TestCase
1729
+ if ActiveRecord::Base.lease_connection.supports_transaction_isolation? && !current_adapter?(:SQLite3Adapter)
1730
+ self.use_transactional_tests = false
1731
+ fixtures :topics, :developers
1213
1732
 
1214
- if ActiveRecord::Base.connection.supports_transaction_isolation? && !current_adapter?(:SQLite3Adapter)
1215
- class ConcurrentTransactionTest < TransactionTest
1216
1733
  # This will cause transactions to overlap and fail unless they are performed on
1217
1734
  # separate database connections.
1218
1735
  def test_transaction_per_thread
@@ -1225,7 +1742,7 @@ if ActiveRecord::Base.connection.supports_transaction_isolation? && !current_ada
1225
1742
  topic.approved = !topic.approved?
1226
1743
  assert topic.save!
1227
1744
  end
1228
- Topic.connection.close
1745
+ Topic.lease_connection.close
1229
1746
  end
1230
1747
  end
1231
1748
 
@@ -1260,7 +1777,7 @@ if ActiveRecord::Base.connection.supports_transaction_isolation? && !current_ada
1260
1777
  dev = Developer.find(1)
1261
1778
  assert_equal original_salary, dev.salary
1262
1779
  end
1263
- Developer.connection.close
1780
+ Developer.lease_connection.close
1264
1781
  end
1265
1782
  end
1266
1783
 
@@ -1273,7 +1790,7 @@ if ActiveRecord::Base.connection.supports_transaction_isolation? && !current_ada
1273
1790
  assert_equal original_salary, Developer.find(1).salary
1274
1791
  end
1275
1792
  end
1276
- Developer.connection.close
1793
+ Developer.lease_connection.close
1277
1794
  end
1278
1795
 
1279
1796
  threads.each(&:join)