ibm_db 5.6.1-arm64-darwin-24

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 (753) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +299 -0
  3. data/LICENSE +55 -0
  4. data/MANIFEST +14 -0
  5. data/ParameterizedQueries README +39 -0
  6. data/README +210 -0
  7. data/ext/Makefile +270 -0
  8. data/ext/Makefile.nt32 +181 -0
  9. data/ext/Makefile.nt32.191 +212 -0
  10. data/ext/extconf.rb +320 -0
  11. data/ext/gil_release_version.h +3 -0
  12. data/ext/ibm_db.bundle +0 -0
  13. data/ext/ibm_db.c +11865 -0
  14. data/ext/ibm_db.o +0 -0
  15. data/ext/mkmf.log +98 -0
  16. data/ext/ruby_ibm_db.h +241 -0
  17. data/ext/ruby_ibm_db_cli.c +867 -0
  18. data/ext/ruby_ibm_db_cli.h +508 -0
  19. data/ext/ruby_ibm_db_cli.o +0 -0
  20. data/ext/unicode_support_version.h +3 -0
  21. data/init.rb +42 -0
  22. data/lib/IBM_DB.rb +27 -0
  23. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +4407 -0
  24. data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1965 -0
  25. data/lib/active_record/connection_adapters/ibmdb_adapter.rb +5 -0
  26. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -0
  27. data/lib/ibm_db.bundle +0 -0
  28. data/test/active_record/connection_adapters/fake_adapter.rb +52 -0
  29. data/test/activejob/destroy_association_async_test.rb +305 -0
  30. data/test/activejob/destroy_async_job_not_present_test.rb +31 -0
  31. data/test/activejob/helper.rb +15 -0
  32. data/test/assets/example.log +1 -0
  33. data/test/assets/flowers.jpg +0 -0
  34. data/test/assets/schema_dump_5_1.yml +345 -0
  35. data/test/assets/test.txt +1 -0
  36. data/test/cases/adapter_prevent_writes_test.rb +334 -0
  37. data/test/cases/adapter_test.rb +565 -0
  38. data/test/cases/adapters/mysql2/active_schema_test.rb +203 -0
  39. data/test/cases/adapters/mysql2/auto_increment_test.rb +34 -0
  40. data/test/cases/adapters/mysql2/bind_parameter_test.rb +52 -0
  41. data/test/cases/adapters/mysql2/boolean_test.rb +102 -0
  42. data/test/cases/adapters/mysql2/case_sensitivity_test.rb +65 -0
  43. data/test/cases/adapters/mysql2/charset_collation_test.rb +57 -0
  44. data/test/cases/adapters/mysql2/connection_test.rb +208 -0
  45. data/test/cases/adapters/mysql2/count_deleted_rows_with_lock_test.rb +28 -0
  46. data/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb +49 -0
  47. data/test/cases/adapters/mysql2/enum_test.rb +47 -0
  48. data/test/cases/adapters/mysql2/explain_test.rb +23 -0
  49. data/test/cases/adapters/mysql2/json_test.rb +24 -0
  50. data/test/cases/adapters/mysql2/mysql2_adapter_prevent_writes_test.rb +208 -0
  51. data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +238 -0
  52. data/test/cases/adapters/mysql2/nested_deadlock_test.rb +75 -0
  53. data/test/cases/adapters/mysql2/optimizer_hints_test.rb +69 -0
  54. data/test/cases/adapters/mysql2/reserved_word_test.rb +152 -0
  55. data/test/cases/adapters/mysql2/schema_migrations_test.rb +64 -0
  56. data/test/cases/adapters/mysql2/schema_test.rb +128 -0
  57. data/test/cases/adapters/mysql2/set_test.rb +32 -0
  58. data/test/cases/adapters/mysql2/sp_test.rb +38 -0
  59. data/test/cases/adapters/mysql2/sql_types_test.rb +16 -0
  60. data/test/cases/adapters/mysql2/table_options_test.rb +125 -0
  61. data/test/cases/adapters/mysql2/transaction_test.rb +151 -0
  62. data/test/cases/adapters/mysql2/unsigned_type_test.rb +68 -0
  63. data/test/cases/adapters/mysql2/virtual_column_test.rb +66 -0
  64. data/test/cases/adapters/postgresql/active_schema_test.rb +113 -0
  65. data/test/cases/adapters/postgresql/array_test.rb +394 -0
  66. data/test/cases/adapters/postgresql/bit_string_test.rb +84 -0
  67. data/test/cases/adapters/postgresql/bytea_test.rb +135 -0
  68. data/test/cases/adapters/postgresql/case_insensitive_test.rb +27 -0
  69. data/test/cases/adapters/postgresql/change_schema_test.rb +40 -0
  70. data/test/cases/adapters/postgresql/cidr_test.rb +27 -0
  71. data/test/cases/adapters/postgresql/citext_test.rb +78 -0
  72. data/test/cases/adapters/postgresql/collation_test.rb +55 -0
  73. data/test/cases/adapters/postgresql/composite_test.rb +134 -0
  74. data/test/cases/adapters/postgresql/connection_test.rb +245 -0
  75. data/test/cases/adapters/postgresql/create_unlogged_tables_test.rb +74 -0
  76. data/test/cases/adapters/postgresql/datatype_test.rb +89 -0
  77. data/test/cases/adapters/postgresql/date_test.rb +42 -0
  78. data/test/cases/adapters/postgresql/domain_test.rb +49 -0
  79. data/test/cases/adapters/postgresql/enum_test.rb +93 -0
  80. data/test/cases/adapters/postgresql/explain_test.rb +22 -0
  81. data/test/cases/adapters/postgresql/extension_migration_test.rb +64 -0
  82. data/test/cases/adapters/postgresql/foreign_table_test.rb +109 -0
  83. data/test/cases/adapters/postgresql/full_text_test.rb +46 -0
  84. data/test/cases/adapters/postgresql/geometric_test.rb +372 -0
  85. data/test/cases/adapters/postgresql/hstore_test.rb +390 -0
  86. data/test/cases/adapters/postgresql/infinity_test.rb +108 -0
  87. data/test/cases/adapters/postgresql/integer_test.rb +27 -0
  88. data/test/cases/adapters/postgresql/interval_test.rb +99 -0
  89. data/test/cases/adapters/postgresql/json_test.rb +52 -0
  90. data/test/cases/adapters/postgresql/ltree_test.rb +51 -0
  91. data/test/cases/adapters/postgresql/money_test.rb +127 -0
  92. data/test/cases/adapters/postgresql/network_test.rb +102 -0
  93. data/test/cases/adapters/postgresql/numbers_test.rb +51 -0
  94. data/test/cases/adapters/postgresql/optimizer_hints_test.rb +71 -0
  95. data/test/cases/adapters/postgresql/partitions_test.rb +22 -0
  96. data/test/cases/adapters/postgresql/postgresql_adapter_prevent_writes_test.rb +205 -0
  97. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +447 -0
  98. data/test/cases/adapters/postgresql/prepared_statements_disabled_test.rb +27 -0
  99. data/test/cases/adapters/postgresql/prepared_statements_test.rb +22 -0
  100. data/test/cases/adapters/postgresql/quoting_test.rb +50 -0
  101. data/test/cases/adapters/postgresql/range_test.rb +457 -0
  102. data/test/cases/adapters/postgresql/referential_integrity_test.rb +112 -0
  103. data/test/cases/adapters/postgresql/rename_table_test.rb +35 -0
  104. data/test/cases/adapters/postgresql/schema_authorization_test.rb +110 -0
  105. data/test/cases/adapters/postgresql/schema_test.rb +713 -0
  106. data/test/cases/adapters/postgresql/serial_test.rb +156 -0
  107. data/test/cases/adapters/postgresql/statement_pool_test.rb +61 -0
  108. data/test/cases/adapters/postgresql/timestamp_test.rb +92 -0
  109. data/test/cases/adapters/postgresql/transaction_nested_test.rb +114 -0
  110. data/test/cases/adapters/postgresql/transaction_test.rb +189 -0
  111. data/test/cases/adapters/postgresql/type_lookup_test.rb +35 -0
  112. data/test/cases/adapters/postgresql/utils_test.rb +64 -0
  113. data/test/cases/adapters/postgresql/uuid_test.rb +411 -0
  114. data/test/cases/adapters/postgresql/xml_test.rb +50 -0
  115. data/test/cases/adapters/sqlite3/collation_test.rb +64 -0
  116. data/test/cases/adapters/sqlite3/copy_table_test.rb +101 -0
  117. data/test/cases/adapters/sqlite3/explain_test.rb +23 -0
  118. data/test/cases/adapters/sqlite3/json_test.rb +29 -0
  119. data/test/cases/adapters/sqlite3/quoting_test.rb +79 -0
  120. data/test/cases/adapters/sqlite3/sqlite3_adapter_prevent_writes_test.rb +186 -0
  121. data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +628 -0
  122. data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +24 -0
  123. data/test/cases/adapters/sqlite3/statement_pool_test.rb +21 -0
  124. data/test/cases/adapters/sqlite3/transaction_test.rb +123 -0
  125. data/test/cases/aggregations_test.rb +170 -0
  126. data/test/cases/annotate_test.rb +46 -0
  127. data/test/cases/ar_schema_test.rb +213 -0
  128. data/test/cases/arel/attributes/attribute_test.rb +1145 -0
  129. data/test/cases/arel/attributes/math_test.rb +83 -0
  130. data/test/cases/arel/attributes_test.rb +27 -0
  131. data/test/cases/arel/collectors/bind_test.rb +40 -0
  132. data/test/cases/arel/collectors/composite_test.rb +47 -0
  133. data/test/cases/arel/collectors/sql_string_test.rb +41 -0
  134. data/test/cases/arel/collectors/substitute_bind_collector_test.rb +48 -0
  135. data/test/cases/arel/crud_test.rb +65 -0
  136. data/test/cases/arel/delete_manager_test.rb +53 -0
  137. data/test/cases/arel/factory_methods_test.rb +46 -0
  138. data/test/cases/arel/helper.rb +45 -0
  139. data/test/cases/arel/insert_manager_test.rb +241 -0
  140. data/test/cases/arel/nodes/and_test.rb +30 -0
  141. data/test/cases/arel/nodes/as_test.rb +36 -0
  142. data/test/cases/arel/nodes/ascending_test.rb +46 -0
  143. data/test/cases/arel/nodes/bin_test.rb +35 -0
  144. data/test/cases/arel/nodes/binary_test.rb +29 -0
  145. data/test/cases/arel/nodes/bind_param_test.rb +22 -0
  146. data/test/cases/arel/nodes/case_test.rb +96 -0
  147. data/test/cases/arel/nodes/casted_test.rb +18 -0
  148. data/test/cases/arel/nodes/comment_test.rb +22 -0
  149. data/test/cases/arel/nodes/count_test.rb +35 -0
  150. data/test/cases/arel/nodes/delete_statement_test.rb +36 -0
  151. data/test/cases/arel/nodes/descending_test.rb +46 -0
  152. data/test/cases/arel/nodes/distinct_test.rb +21 -0
  153. data/test/cases/arel/nodes/equality_test.rb +62 -0
  154. data/test/cases/arel/nodes/extract_test.rb +43 -0
  155. data/test/cases/arel/nodes/false_test.rb +21 -0
  156. data/test/cases/arel/nodes/grouping_test.rb +26 -0
  157. data/test/cases/arel/nodes/infix_operation_test.rb +42 -0
  158. data/test/cases/arel/nodes/insert_statement_test.rb +44 -0
  159. data/test/cases/arel/nodes/named_function_test.rb +48 -0
  160. data/test/cases/arel/nodes/node_test.rb +22 -0
  161. data/test/cases/arel/nodes/not_test.rb +31 -0
  162. data/test/cases/arel/nodes/or_test.rb +36 -0
  163. data/test/cases/arel/nodes/over_test.rb +69 -0
  164. data/test/cases/arel/nodes/select_core_test.rb +79 -0
  165. data/test/cases/arel/nodes/select_statement_test.rb +51 -0
  166. data/test/cases/arel/nodes/sql_literal_test.rb +75 -0
  167. data/test/cases/arel/nodes/sum_test.rb +35 -0
  168. data/test/cases/arel/nodes/table_alias_test.rb +29 -0
  169. data/test/cases/arel/nodes/true_test.rb +21 -0
  170. data/test/cases/arel/nodes/unary_operation_test.rb +41 -0
  171. data/test/cases/arel/nodes/update_statement_test.rb +60 -0
  172. data/test/cases/arel/nodes/window_test.rb +81 -0
  173. data/test/cases/arel/nodes_test.rb +34 -0
  174. data/test/cases/arel/select_manager_test.rb +1238 -0
  175. data/test/cases/arel/support/fake_record.rb +135 -0
  176. data/test/cases/arel/table_test.rb +216 -0
  177. data/test/cases/arel/update_manager_test.rb +126 -0
  178. data/test/cases/arel/visitors/dispatch_contamination_test.rb +78 -0
  179. data/test/cases/arel/visitors/dot_test.rb +90 -0
  180. data/test/cases/arel/visitors/mysql_test.rb +157 -0
  181. data/test/cases/arel/visitors/postgres_test.rb +366 -0
  182. data/test/cases/arel/visitors/sqlite_test.rb +75 -0
  183. data/test/cases/arel/visitors/to_sql_test.rb +750 -0
  184. data/test/cases/associations/association_scope_test.rb +16 -0
  185. data/test/cases/associations/belongs_to_associations_test.rb +1493 -0
  186. data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +43 -0
  187. data/test/cases/associations/callbacks_test.rb +208 -0
  188. data/test/cases/associations/cascaded_eager_loading_test.rb +245 -0
  189. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +156 -0
  190. data/test/cases/associations/eager_load_nested_include_test.rb +127 -0
  191. data/test/cases/associations/eager_singularization_test.rb +148 -0
  192. data/test/cases/associations/eager_test.rb +1658 -0
  193. data/test/cases/associations/extension_test.rb +93 -0
  194. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +1025 -0
  195. data/test/cases/associations/has_many_associations_test.rb +3074 -0
  196. data/test/cases/associations/has_many_through_associations_test.rb +1580 -0
  197. data/test/cases/associations/has_one_associations_test.rb +872 -0
  198. data/test/cases/associations/has_one_through_associations_test.rb +429 -0
  199. data/test/cases/associations/inner_join_association_test.rb +215 -0
  200. data/test/cases/associations/inverse_associations_test.rb +941 -0
  201. data/test/cases/associations/join_model_test.rb +787 -0
  202. data/test/cases/associations/left_outer_join_association_test.rb +123 -0
  203. data/test/cases/associations/nested_through_associations_test.rb +636 -0
  204. data/test/cases/associations/required_test.rb +127 -0
  205. data/test/cases/associations_test.rb +516 -0
  206. data/test/cases/attribute_decorators_test.rb +126 -0
  207. data/test/cases/attribute_methods/read_test.rb +60 -0
  208. data/test/cases/attribute_methods_test.rb +1124 -0
  209. data/test/cases/attribute_set_test.rb +270 -0
  210. data/test/cases/attribute_test.rb +246 -0
  211. data/test/cases/attributes_test.rb +371 -0
  212. data/test/cases/autosave_association_test.rb +1953 -0
  213. data/test/cases/base_prevent_writes_test.rb +229 -0
  214. data/test/cases/base_test.rb +1770 -0
  215. data/test/cases/batches_test.rb +695 -0
  216. data/test/cases/binary_test.rb +39 -0
  217. data/test/cases/bind_parameter_test.rb +283 -0
  218. data/test/cases/boolean_test.rb +52 -0
  219. data/test/cases/cache_key_test.rb +131 -0
  220. data/test/cases/calculations_test.rb +1361 -0
  221. data/test/cases/callbacks_test.rb +503 -0
  222. data/test/cases/clone_test.rb +45 -0
  223. data/test/cases/coders/json_test.rb +17 -0
  224. data/test/cases/coders/yaml_column_test.rb +66 -0
  225. data/test/cases/collection_cache_key_test.rb +272 -0
  226. data/test/cases/column_alias_test.rb +19 -0
  227. data/test/cases/column_definition_test.rb +34 -0
  228. data/test/cases/comment_test.rb +204 -0
  229. data/test/cases/connection_adapters/adapter_leasing_test.rb +60 -0
  230. data/test/cases/connection_adapters/connection_handler_test.rb +467 -0
  231. data/test/cases/connection_adapters/connection_handlers_multi_db_test.rb +400 -0
  232. data/test/cases/connection_adapters/connection_handlers_multi_pool_config_test.rb +103 -0
  233. data/test/cases/connection_adapters/connection_handlers_sharding_db_test.rb +499 -0
  234. data/test/cases/connection_adapters/connection_specification_test.rb +12 -0
  235. data/test/cases/connection_adapters/connection_swapping_nested_test.rb +457 -0
  236. data/test/cases/connection_adapters/legacy_connection_handlers_multi_db_test.rb +486 -0
  237. data/test/cases/connection_adapters/legacy_connection_handlers_sharding_db_test.rb +586 -0
  238. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +436 -0
  239. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +81 -0
  240. data/test/cases/connection_adapters/quoting_test.rb +13 -0
  241. data/test/cases/connection_adapters/schema_cache_test.rb +294 -0
  242. data/test/cases/connection_adapters/type_lookup_test.rb +119 -0
  243. data/test/cases/connection_management_test.rb +114 -0
  244. data/test/cases/connection_pool_test.rb +754 -0
  245. data/test/cases/connection_specification/resolver_test.rb +131 -0
  246. data/test/cases/core_test.rb +136 -0
  247. data/test/cases/counter_cache_test.rb +368 -0
  248. data/test/cases/custom_locking_test.rb +19 -0
  249. data/test/cases/database_configurations/hash_config_test.rb +74 -0
  250. data/test/cases/database_configurations/resolver_test.rb +150 -0
  251. data/test/cases/database_configurations_test.rb +145 -0
  252. data/test/cases/database_selector_test.rb +296 -0
  253. data/test/cases/database_statements_test.rb +36 -0
  254. data/test/cases/date_test.rb +36 -0
  255. data/test/cases/date_time_precision_test.rb +129 -0
  256. data/test/cases/date_time_test.rb +76 -0
  257. data/test/cases/defaults_test.rb +254 -0
  258. data/test/cases/delegated_type_test.rb +57 -0
  259. data/test/cases/dirty_test.rb +959 -0
  260. data/test/cases/disconnected_test.rb +30 -0
  261. data/test/cases/dup_test.rb +184 -0
  262. data/test/cases/enum_test.rb +823 -0
  263. data/test/cases/errors_test.rb +16 -0
  264. data/test/cases/explain_subscriber_test.rb +66 -0
  265. data/test/cases/explain_test.rb +79 -0
  266. data/test/cases/filter_attributes_test.rb +153 -0
  267. data/test/cases/finder_respond_to_test.rb +60 -0
  268. data/test/cases/finder_test.rb +1676 -0
  269. data/test/cases/fixture_set/file_test.rb +152 -0
  270. data/test/cases/fixtures_test.rb +1645 -0
  271. data/test/cases/forbidden_attributes_protection_test.rb +130 -0
  272. data/test/cases/habtm_destroy_order_test.rb +61 -0
  273. data/test/cases/helper.rb +233 -0
  274. data/test/cases/hot_compatibility_test.rb +143 -0
  275. data/test/cases/i18n_test.rb +46 -0
  276. data/test/cases/inheritance_test.rb +671 -0
  277. data/test/cases/insert_all_test.rb +489 -0
  278. data/test/cases/instrumentation_test.rb +101 -0
  279. data/test/cases/integration_test.rb +243 -0
  280. data/test/cases/invalid_connection_test.rb +26 -0
  281. data/test/cases/invertible_migration_test.rb +527 -0
  282. data/test/cases/json_attribute_test.rb +35 -0
  283. data/test/cases/json_serialization_test.rb +310 -0
  284. data/test/cases/json_shared_test_cases.rb +290 -0
  285. data/test/cases/locking_test.rb +787 -0
  286. data/test/cases/log_subscriber_test.rb +267 -0
  287. data/test/cases/marshal_serialization_test.rb +39 -0
  288. data/test/cases/migration/change_schema_test.rb +504 -0
  289. data/test/cases/migration/change_table_test.rb +364 -0
  290. data/test/cases/migration/check_constraint_test.rb +162 -0
  291. data/test/cases/migration/column_attributes_test.rb +186 -0
  292. data/test/cases/migration/column_positioning_test.rb +68 -0
  293. data/test/cases/migration/columns_test.rb +326 -0
  294. data/test/cases/migration/command_recorder_test.rb +437 -0
  295. data/test/cases/migration/compatibility_test.rb +673 -0
  296. data/test/cases/migration/create_join_table_test.rb +167 -0
  297. data/test/cases/migration/foreign_key_test.rb +581 -0
  298. data/test/cases/migration/helper.rb +40 -0
  299. data/test/cases/migration/index_test.rb +267 -0
  300. data/test/cases/migration/logger_test.rb +39 -0
  301. data/test/cases/migration/pending_migrations_test.rb +106 -0
  302. data/test/cases/migration/references_foreign_key_test.rb +235 -0
  303. data/test/cases/migration/references_index_test.rb +120 -0
  304. data/test/cases/migration/references_statements_test.rb +137 -0
  305. data/test/cases/migration/rename_table_test.rb +116 -0
  306. data/test/cases/migration_test.rb +1525 -0
  307. data/test/cases/migrator_test.rb +527 -0
  308. data/test/cases/mixin_test.rb +64 -0
  309. data/test/cases/modules_test.rb +174 -0
  310. data/test/cases/multi_db_migrator_test.rb +223 -0
  311. data/test/cases/multiparameter_attributes_test.rb +399 -0
  312. data/test/cases/multiple_db_test.rb +116 -0
  313. data/test/cases/nested_attributes_test.rb +1119 -0
  314. data/test/cases/nested_attributes_with_callbacks_test.rb +146 -0
  315. data/test/cases/null_relation_test.rb +84 -0
  316. data/test/cases/numeric_data_test.rb +93 -0
  317. data/test/cases/persistence_test.rb +1093 -0
  318. data/test/cases/pooled_connections_test.rb +73 -0
  319. data/test/cases/prepared_statement_status_test.rb +48 -0
  320. data/test/cases/primary_keys_test.rb +482 -0
  321. data/test/cases/query_cache_test.rb +915 -0
  322. data/test/cases/quoting_test.rb +303 -0
  323. data/test/cases/readonly_test.rb +120 -0
  324. data/test/cases/reaper_test.rb +199 -0
  325. data/test/cases/reflection_test.rb +520 -0
  326. data/test/cases/relation/delegation_test.rb +76 -0
  327. data/test/cases/relation/delete_all_test.rb +117 -0
  328. data/test/cases/relation/merging_test.rb +434 -0
  329. data/test/cases/relation/mutation_test.rb +145 -0
  330. data/test/cases/relation/or_test.rb +192 -0
  331. data/test/cases/relation/predicate_builder_test.rb +31 -0
  332. data/test/cases/relation/record_fetch_warning_test.rb +42 -0
  333. data/test/cases/relation/select_test.rb +67 -0
  334. data/test/cases/relation/update_all_test.rb +317 -0
  335. data/test/cases/relation/where_chain_test.rb +141 -0
  336. data/test/cases/relation/where_clause_test.rb +257 -0
  337. data/test/cases/relation/where_test.rb +429 -0
  338. data/test/cases/relation_test.rb +482 -0
  339. data/test/cases/relations_test.rb +2251 -0
  340. data/test/cases/reload_models_test.rb +26 -0
  341. data/test/cases/reserved_word_test.rb +141 -0
  342. data/test/cases/result_test.rb +141 -0
  343. data/test/cases/sanitize_test.rb +192 -0
  344. data/test/cases/schema_dumper_test.rb +550 -0
  345. data/test/cases/schema_loading_test.rb +53 -0
  346. data/test/cases/scoping/default_scoping_test.rb +569 -0
  347. data/test/cases/scoping/named_scoping_test.rb +649 -0
  348. data/test/cases/scoping/relation_scoping_test.rb +522 -0
  349. data/test/cases/secure_token_test.rb +47 -0
  350. data/test/cases/serialization_test.rb +106 -0
  351. data/test/cases/serialized_attribute_test.rb +455 -0
  352. data/test/cases/signed_id_test.rb +168 -0
  353. data/test/cases/statement_cache_test.rb +153 -0
  354. data/test/cases/statement_invalid_test.rb +42 -0
  355. data/test/cases/store_test.rb +320 -0
  356. data/test/cases/strict_loading_test.rb +473 -0
  357. data/test/cases/suppressor_test.rb +77 -0
  358. data/test/cases/tasks/database_tasks_test.rb +1526 -0
  359. data/test/cases/tasks/mysql_rake_test.rb +417 -0
  360. data/test/cases/tasks/postgresql_rake_test.rb +534 -0
  361. data/test/cases/tasks/sqlite_rake_test.rb +267 -0
  362. data/test/cases/test_case.rb +142 -0
  363. data/test/cases/test_databases_test.rb +79 -0
  364. data/test/cases/test_fixtures_test.rb +96 -0
  365. data/test/cases/time_precision_test.rb +125 -0
  366. data/test/cases/timestamp_test.rb +504 -0
  367. data/test/cases/touch_later_test.rb +123 -0
  368. data/test/cases/transaction_callbacks_test.rb +772 -0
  369. data/test/cases/transaction_isolation_test.rb +106 -0
  370. data/test/cases/transactions_test.rb +1285 -0
  371. data/test/cases/type/adapter_specific_registry_test.rb +145 -0
  372. data/test/cases/type/date_time_test.rb +16 -0
  373. data/test/cases/type/integer_test.rb +29 -0
  374. data/test/cases/type/string_test.rb +24 -0
  375. data/test/cases/type/time_test.rb +28 -0
  376. data/test/cases/type/type_map_test.rb +178 -0
  377. data/test/cases/type/unsigned_integer_test.rb +19 -0
  378. data/test/cases/type_test.rb +41 -0
  379. data/test/cases/types_test.rb +26 -0
  380. data/test/cases/unconnected_test.rb +46 -0
  381. data/test/cases/unsafe_raw_sql_test.rb +274 -0
  382. data/test/cases/validations/absence_validation_test.rb +75 -0
  383. data/test/cases/validations/association_validation_test.rb +99 -0
  384. data/test/cases/validations/i18n_generate_message_validation_test.rb +102 -0
  385. data/test/cases/validations/i18n_validation_test.rb +87 -0
  386. data/test/cases/validations/length_validation_test.rb +80 -0
  387. data/test/cases/validations/numericality_validation_test.rb +181 -0
  388. data/test/cases/validations/presence_validation_test.rb +105 -0
  389. data/test/cases/validations/uniqueness_validation_test.rb +618 -0
  390. data/test/cases/validations_repair_helper.rb +21 -0
  391. data/test/cases/validations_test.rb +229 -0
  392. data/test/cases/view_test.rb +222 -0
  393. data/test/cases/yaml_serialization_test.rb +166 -0
  394. data/test/config.example.yml +97 -0
  395. data/test/config.rb +7 -0
  396. data/test/config.yml +220 -0
  397. data/test/connections/native_ibm_db/connection.rb +44 -0
  398. data/test/fixtures/accounts.yml +29 -0
  399. data/test/fixtures/admin/accounts.yml +2 -0
  400. data/test/fixtures/admin/randomly_named_a9.yml +7 -0
  401. data/test/fixtures/admin/randomly_named_b0.yml +7 -0
  402. data/test/fixtures/admin/users.yml +10 -0
  403. data/test/fixtures/all/admin +1 -0
  404. data/test/fixtures/all/developers.yml +0 -0
  405. data/test/fixtures/all/namespaced/accounts.yml +2 -0
  406. data/test/fixtures/all/people.yml +0 -0
  407. data/test/fixtures/all/tasks.yml +0 -0
  408. data/test/fixtures/author_addresses.yml +11 -0
  409. data/test/fixtures/author_favorites.yml +4 -0
  410. data/test/fixtures/authors.yml +17 -0
  411. data/test/fixtures/bad_posts.yml +9 -0
  412. data/test/fixtures/binaries.yml +137 -0
  413. data/test/fixtures/books.yml +38 -0
  414. data/test/fixtures/bulbs.yml +5 -0
  415. data/test/fixtures/cars.yml +9 -0
  416. data/test/fixtures/categories/special_categories.yml +9 -0
  417. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  418. data/test/fixtures/categories.yml +19 -0
  419. data/test/fixtures/categories_ordered.yml +7 -0
  420. data/test/fixtures/categories_posts.yml +34 -0
  421. data/test/fixtures/categorizations.yml +23 -0
  422. data/test/fixtures/citations.yml +5 -0
  423. data/test/fixtures/clubs.yml +8 -0
  424. data/test/fixtures/collections.yml +3 -0
  425. data/test/fixtures/colleges.yml +3 -0
  426. data/test/fixtures/comments.yml +72 -0
  427. data/test/fixtures/companies.yml +72 -0
  428. data/test/fixtures/computers.yml +12 -0
  429. data/test/fixtures/content.yml +3 -0
  430. data/test/fixtures/content_positions.yml +3 -0
  431. data/test/fixtures/courses.yml +8 -0
  432. data/test/fixtures/customers.yml +35 -0
  433. data/test/fixtures/dashboards.yml +6 -0
  434. data/test/fixtures/dead_parrots.yml +5 -0
  435. data/test/fixtures/developers.yml +22 -0
  436. data/test/fixtures/developers_projects.yml +17 -0
  437. data/test/fixtures/dog_lovers.yml +7 -0
  438. data/test/fixtures/dogs.yml +4 -0
  439. data/test/fixtures/doubloons.yml +3 -0
  440. data/test/fixtures/edges.yml +5 -0
  441. data/test/fixtures/entrants.yml +14 -0
  442. data/test/fixtures/essays.yml +16 -0
  443. data/test/fixtures/faces.yml +11 -0
  444. data/test/fixtures/fk_test_has_fk.yml +3 -0
  445. data/test/fixtures/fk_test_has_pk.yml +2 -0
  446. data/test/fixtures/friendships.yml +4 -0
  447. data/test/fixtures/funny_jokes.yml +10 -0
  448. data/test/fixtures/humans.yml +5 -0
  449. data/test/fixtures/interests.yml +33 -0
  450. data/test/fixtures/items.yml +3 -0
  451. data/test/fixtures/jobs.yml +7 -0
  452. data/test/fixtures/legacy_things.yml +3 -0
  453. data/test/fixtures/live_parrots.yml +4 -0
  454. data/test/fixtures/mateys.yml +4 -0
  455. data/test/fixtures/member_details.yml +8 -0
  456. data/test/fixtures/member_types.yml +6 -0
  457. data/test/fixtures/members.yml +11 -0
  458. data/test/fixtures/memberships.yml +41 -0
  459. data/test/fixtures/men.yml +5 -0
  460. data/test/fixtures/minimalistics.yml +5 -0
  461. data/test/fixtures/minivans.yml +5 -0
  462. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  463. data/test/fixtures/mixins.yml +29 -0
  464. data/test/fixtures/movies.yml +7 -0
  465. data/test/fixtures/naked/yml/accounts.yml +1 -0
  466. data/test/fixtures/naked/yml/companies.yml +1 -0
  467. data/test/fixtures/naked/yml/courses.yml +1 -0
  468. data/test/fixtures/naked/yml/courses_with_invalid_key.yml +3 -0
  469. data/test/fixtures/naked/yml/parrots.yml +3 -0
  470. data/test/fixtures/naked/yml/trees.yml +3 -0
  471. data/test/fixtures/nodes.yml +29 -0
  472. data/test/fixtures/organizations.yml +5 -0
  473. data/test/fixtures/other_books.yml +26 -0
  474. data/test/fixtures/other_comments.yml +6 -0
  475. data/test/fixtures/other_dogs.yml +2 -0
  476. data/test/fixtures/other_posts.yml +8 -0
  477. data/test/fixtures/other_topics.yml +42 -0
  478. data/test/fixtures/owners.yml +9 -0
  479. data/test/fixtures/parrots.yml +33 -0
  480. data/test/fixtures/parrots_pirates.yml +7 -0
  481. data/test/fixtures/people.yml +24 -0
  482. data/test/fixtures/peoples_treasures.yml +3 -0
  483. data/test/fixtures/pets.yml +19 -0
  484. data/test/fixtures/pirates.yml +15 -0
  485. data/test/fixtures/posts.yml +88 -0
  486. data/test/fixtures/price_estimates.yml +16 -0
  487. data/test/fixtures/products.yml +4 -0
  488. data/test/fixtures/projects.yml +7 -0
  489. data/test/fixtures/randomly_named_a9.yml +7 -0
  490. data/test/fixtures/ratings.yml +14 -0
  491. data/test/fixtures/readers.yml +17 -0
  492. data/test/fixtures/references.yml +17 -0
  493. data/test/fixtures/reserved_words/distinct.yml +5 -0
  494. data/test/fixtures/reserved_words/distinct_select.yml +11 -0
  495. data/test/fixtures/reserved_words/group.yml +14 -0
  496. data/test/fixtures/reserved_words/select.yml +8 -0
  497. data/test/fixtures/reserved_words/values.yml +7 -0
  498. data/test/fixtures/ships.yml +6 -0
  499. data/test/fixtures/speedometers.yml +8 -0
  500. data/test/fixtures/sponsors.yml +15 -0
  501. data/test/fixtures/strict_zines.yml +2 -0
  502. data/test/fixtures/string_key_objects.yml +7 -0
  503. data/test/fixtures/subscribers.yml +11 -0
  504. data/test/fixtures/subscriptions.yml +12 -0
  505. data/test/fixtures/taggings.yml +78 -0
  506. data/test/fixtures/tags.yml +11 -0
  507. data/test/fixtures/tasks.yml +7 -0
  508. data/test/fixtures/teapots.yml +3 -0
  509. data/test/fixtures/to_be_linked/accounts.yml +2 -0
  510. data/test/fixtures/to_be_linked/users.yml +10 -0
  511. data/test/fixtures/topics.yml +49 -0
  512. data/test/fixtures/toys.yml +14 -0
  513. data/test/fixtures/traffic_lights.yml +10 -0
  514. data/test/fixtures/treasures.yml +10 -0
  515. data/test/fixtures/trees.yml +3 -0
  516. data/test/fixtures/uuid_children.yml +3 -0
  517. data/test/fixtures/uuid_parents.yml +2 -0
  518. data/test/fixtures/variants.yml +4 -0
  519. data/test/fixtures/vegetables.yml +20 -0
  520. data/test/fixtures/vertices.yml +4 -0
  521. data/test/fixtures/warehouse-things.yml +3 -0
  522. data/test/fixtures/warehouse_things.yml +3 -0
  523. data/test/fixtures/zines.yml +5 -0
  524. data/test/ibm_db_test.rb +25 -0
  525. data/test/migrations/10_urban/9_add_expressions.rb +13 -0
  526. data/test/migrations/decimal/1_give_me_big_numbers.rb +17 -0
  527. data/test/migrations/magic/1_currencies_have_symbols.rb +13 -0
  528. data/test/migrations/missing/1000_people_have_middle_names.rb +11 -0
  529. data/test/migrations/missing/1_people_have_last_names.rb +11 -0
  530. data/test/migrations/missing/3_we_need_reminders.rb +14 -0
  531. data/test/migrations/missing/4_innocent_jointable.rb +14 -0
  532. data/test/migrations/rename/1_we_need_things.rb +13 -0
  533. data/test/migrations/rename/2_rename_things.rb +11 -0
  534. data/test/migrations/to_copy/1_people_have_hobbies.rb +11 -0
  535. data/test/migrations/to_copy/2_people_have_descriptions.rb +11 -0
  536. data/test/migrations/to_copy2/1_create_articles.rb +9 -0
  537. data/test/migrations/to_copy2/2_create_comments.rb +9 -0
  538. data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +11 -0
  539. data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +11 -0
  540. data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +11 -0
  541. data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +9 -0
  542. data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +9 -0
  543. data/test/migrations/valid/1_valid_people_have_last_names.rb +11 -0
  544. data/test/migrations/valid/2_we_need_reminders.rb +14 -0
  545. data/test/migrations/valid/3_innocent_jointable.rb +14 -0
  546. data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +11 -0
  547. data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +14 -0
  548. data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +14 -0
  549. data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +11 -0
  550. data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +14 -0
  551. data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +14 -0
  552. data/test/migrations/version_check/20131219224947_migration_version_check.rb +10 -0
  553. data/test/models/account.rb +46 -0
  554. data/test/models/admin/account.rb +5 -0
  555. data/test/models/admin/randomly_named_c1.rb +9 -0
  556. data/test/models/admin/user.rb +48 -0
  557. data/test/models/admin.rb +7 -0
  558. data/test/models/aircraft.rb +7 -0
  559. data/test/models/arunit2_model.rb +5 -0
  560. data/test/models/author.rb +260 -0
  561. data/test/models/auto_id.rb +6 -0
  562. data/test/models/autoloadable/extra_firm.rb +4 -0
  563. data/test/models/binary.rb +4 -0
  564. data/test/models/binary_field.rb +6 -0
  565. data/test/models/bird.rb +24 -0
  566. data/test/models/book.rb +33 -0
  567. data/test/models/book_destroy_async.rb +24 -0
  568. data/test/models/boolean.rb +7 -0
  569. data/test/models/bulb.rb +61 -0
  570. data/test/models/cake_designer.rb +5 -0
  571. data/test/models/car.rb +36 -0
  572. data/test/models/carrier.rb +4 -0
  573. data/test/models/cart.rb +5 -0
  574. data/test/models/cat.rb +12 -0
  575. data/test/models/categorization.rb +21 -0
  576. data/test/models/category.rb +47 -0
  577. data/test/models/chef.rb +10 -0
  578. data/test/models/citation.rb +7 -0
  579. data/test/models/club.rb +28 -0
  580. data/test/models/college.rb +12 -0
  581. data/test/models/column.rb +5 -0
  582. data/test/models/column_name.rb +5 -0
  583. data/test/models/comment.rb +98 -0
  584. data/test/models/company.rb +226 -0
  585. data/test/models/company_in_module.rb +99 -0
  586. data/test/models/computer.rb +5 -0
  587. data/test/models/contact.rb +43 -0
  588. data/test/models/content.rb +42 -0
  589. data/test/models/contract.rb +38 -0
  590. data/test/models/country.rb +5 -0
  591. data/test/models/course.rb +8 -0
  592. data/test/models/customer.rb +85 -0
  593. data/test/models/customer_carrier.rb +16 -0
  594. data/test/models/dashboard.rb +5 -0
  595. data/test/models/default.rb +4 -0
  596. data/test/models/department.rb +6 -0
  597. data/test/models/destroy_async_parent.rb +15 -0
  598. data/test/models/destroy_async_parent_soft_delete.rb +20 -0
  599. data/test/models/developer.rb +341 -0
  600. data/test/models/dl_keyed_belongs_to.rb +13 -0
  601. data/test/models/dl_keyed_belongs_to_soft_delete.rb +19 -0
  602. data/test/models/dl_keyed_has_many.rb +5 -0
  603. data/test/models/dl_keyed_has_many_through.rb +5 -0
  604. data/test/models/dl_keyed_has_one.rb +5 -0
  605. data/test/models/dl_keyed_join.rb +10 -0
  606. data/test/models/dog.rb +7 -0
  607. data/test/models/dog_lover.rb +7 -0
  608. data/test/models/doubloon.rb +14 -0
  609. data/test/models/drink_designer.rb +20 -0
  610. data/test/models/edge.rb +7 -0
  611. data/test/models/electron.rb +7 -0
  612. data/test/models/engine.rb +5 -0
  613. data/test/models/entrant.rb +5 -0
  614. data/test/models/entry.rb +5 -0
  615. data/test/models/essay.rb +8 -0
  616. data/test/models/essay_destroy_async.rb +12 -0
  617. data/test/models/event.rb +5 -0
  618. data/test/models/eye.rb +39 -0
  619. data/test/models/face.rb +17 -0
  620. data/test/models/family.rb +6 -0
  621. data/test/models/family_tree.rb +6 -0
  622. data/test/models/friendship.rb +8 -0
  623. data/test/models/frog.rb +8 -0
  624. data/test/models/guid.rb +4 -0
  625. data/test/models/guitar.rb +6 -0
  626. data/test/models/hotel.rb +13 -0
  627. data/test/models/human.rb +39 -0
  628. data/test/models/image.rb +5 -0
  629. data/test/models/interest.rb +16 -0
  630. data/test/models/invoice.rb +6 -0
  631. data/test/models/item.rb +9 -0
  632. data/test/models/job.rb +9 -0
  633. data/test/models/joke.rb +9 -0
  634. data/test/models/keyboard.rb +5 -0
  635. data/test/models/legacy_thing.rb +5 -0
  636. data/test/models/lesson.rb +13 -0
  637. data/test/models/line_item.rb +5 -0
  638. data/test/models/liquid.rb +6 -0
  639. data/test/models/man.rb +11 -0
  640. data/test/models/matey.rb +6 -0
  641. data/test/models/measurement.rb +4 -0
  642. data/test/models/member.rb +45 -0
  643. data/test/models/member_detail.rb +11 -0
  644. data/test/models/member_type.rb +5 -0
  645. data/test/models/membership.rb +38 -0
  646. data/test/models/mentor.rb +5 -0
  647. data/test/models/message.rb +5 -0
  648. data/test/models/minimalistic.rb +4 -0
  649. data/test/models/minivan.rb +10 -0
  650. data/test/models/mixed_case_monkey.rb +5 -0
  651. data/test/models/mocktail_designer.rb +2 -0
  652. data/test/models/molecule.rb +8 -0
  653. data/test/models/mouse.rb +6 -0
  654. data/test/models/movie.rb +7 -0
  655. data/test/models/node.rb +7 -0
  656. data/test/models/non_primary_key.rb +4 -0
  657. data/test/models/notification.rb +5 -0
  658. data/test/models/numeric_data.rb +12 -0
  659. data/test/models/order.rb +6 -0
  660. data/test/models/organization.rb +16 -0
  661. data/test/models/other_dog.rb +7 -0
  662. data/test/models/owner.rb +39 -0
  663. data/test/models/parrot.rb +36 -0
  664. data/test/models/person.rb +147 -0
  665. data/test/models/personal_legacy_thing.rb +6 -0
  666. data/test/models/pet.rb +20 -0
  667. data/test/models/pet_treasure.rb +8 -0
  668. data/test/models/pirate.rb +116 -0
  669. data/test/models/possession.rb +5 -0
  670. data/test/models/post.rb +371 -0
  671. data/test/models/price_estimate.rb +14 -0
  672. data/test/models/professor.rb +7 -0
  673. data/test/models/project.rb +42 -0
  674. data/test/models/publisher/article.rb +6 -0
  675. data/test/models/publisher/magazine.rb +5 -0
  676. data/test/models/publisher.rb +4 -0
  677. data/test/models/randomly_named_c1.rb +5 -0
  678. data/test/models/rating.rb +8 -0
  679. data/test/models/reader.rb +25 -0
  680. data/test/models/recipe.rb +5 -0
  681. data/test/models/record.rb +4 -0
  682. data/test/models/reference.rb +25 -0
  683. data/test/models/reply.rb +79 -0
  684. data/test/models/room.rb +6 -0
  685. data/test/models/section.rb +6 -0
  686. data/test/models/seminar.rb +6 -0
  687. data/test/models/session.rb +6 -0
  688. data/test/models/ship.rb +42 -0
  689. data/test/models/ship_part.rb +10 -0
  690. data/test/models/shop.rb +19 -0
  691. data/test/models/shop_account.rb +8 -0
  692. data/test/models/speedometer.rb +8 -0
  693. data/test/models/sponsor.rb +10 -0
  694. data/test/models/squeak.rb +6 -0
  695. data/test/models/strict_zine.rb +7 -0
  696. data/test/models/string_key_object.rb +5 -0
  697. data/test/models/student.rb +6 -0
  698. data/test/models/subject.rb +16 -0
  699. data/test/models/subscriber.rb +10 -0
  700. data/test/models/subscription.rb +8 -0
  701. data/test/models/tag.rb +16 -0
  702. data/test/models/tagging.rb +20 -0
  703. data/test/models/task.rb +7 -0
  704. data/test/models/topic.rb +153 -0
  705. data/test/models/toy.rb +10 -0
  706. data/test/models/traffic_light.rb +6 -0
  707. data/test/models/treasure.rb +16 -0
  708. data/test/models/treaty.rb +5 -0
  709. data/test/models/tree.rb +5 -0
  710. data/test/models/tuning_peg.rb +6 -0
  711. data/test/models/tyre.rb +13 -0
  712. data/test/models/user.rb +22 -0
  713. data/test/models/uuid_child.rb +5 -0
  714. data/test/models/uuid_item.rb +8 -0
  715. data/test/models/uuid_parent.rb +5 -0
  716. data/test/models/vegetables.rb +33 -0
  717. data/test/models/vehicle.rb +7 -0
  718. data/test/models/vertex.rb +11 -0
  719. data/test/models/warehouse_thing.rb +7 -0
  720. data/test/models/wheel.rb +5 -0
  721. data/test/models/without_table.rb +5 -0
  722. data/test/models/zine.rb +5 -0
  723. data/test/schema/i5/ibm_db_specific_schema.rb +137 -0
  724. data/test/schema/ids/ibm_db_specific_schema.rb +140 -0
  725. data/test/schema/luw/ibm_db_specific_schema.rb +137 -0
  726. data/test/schema/mysql2_specific_schema.rb +82 -0
  727. data/test/schema/oracle_specific_schema.rb +38 -0
  728. data/test/schema/postgresql_specific_schema.rb +125 -0
  729. data/test/schema/schema.rb +1237 -0
  730. data/test/schema/schema.rb.original +1057 -0
  731. data/test/schema/sqlite_specific_schema.rb +11 -0
  732. data/test/schema/zOS/ibm_db_specific_schema.rb +208 -0
  733. data/test/support/config.rb +43 -0
  734. data/test/support/connection.rb +29 -0
  735. data/test/support/connection_helper.rb +16 -0
  736. data/test/support/ddl_helper.rb +10 -0
  737. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_0_topic.dump +0 -0
  738. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_0_topic_associations.dump +0 -0
  739. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_0_topic.dump +0 -0
  740. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_0_topic_associations.dump +0 -0
  741. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_0_topic.dump +0 -0
  742. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_0_topic_associations.dump +0 -0
  743. data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_0_topic.dump +0 -0
  744. data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_0_topic_associations.dump +0 -0
  745. data/test/support/marshal_compatibility_fixtures/legacy_6_0_record_mysql.dump +0 -0
  746. data/test/support/marshal_compatibility_fixtures/legacy_relation.dump +0 -0
  747. data/test/support/schema_dumping_helper.rb +22 -0
  748. data/test/support/stubs/strong_parameters.rb +40 -0
  749. data/test/support/yaml_compatibility_fixtures/rails_4_1.yml +22 -0
  750. data/test/support/yaml_compatibility_fixtures/rails_4_2_0.yml +182 -0
  751. data/test/support/yaml_compatibility_fixtures/rails_v1_mysql.yml +206 -0
  752. data/test/support/yaml_compatibility_fixtures/rails_v2.yml +55 -0
  753. metadata +876 -0
@@ -0,0 +1,1525 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/helper"
4
+ require "cases/migration/helper"
5
+ require "bigdecimal/util"
6
+ require "concurrent/atomic/count_down_latch"
7
+
8
+ require "models/person"
9
+ require "models/topic"
10
+ require "models/developer"
11
+ require "models/computer"
12
+
13
+ require MIGRATIONS_ROOT + "/valid/2_we_need_reminders"
14
+ require MIGRATIONS_ROOT + "/rename/1_we_need_things"
15
+ require MIGRATIONS_ROOT + "/rename/2_rename_things"
16
+ require MIGRATIONS_ROOT + "/decimal/1_give_me_big_numbers"
17
+
18
+ class BigNumber < ActiveRecord::Base
19
+ unless current_adapter?(:PostgreSQLAdapter, :SQLite3Adapter)
20
+ attribute :value_of_e, :integer
21
+ end
22
+ attribute :my_house_population, :integer
23
+ end
24
+
25
+ class Reminder < ActiveRecord::Base; end
26
+
27
+ class Thing < ActiveRecord::Base; end
28
+
29
+ class MigrationTest < ActiveRecord::TestCase
30
+ self.use_transactional_tests = false
31
+
32
+ fixtures :people
33
+
34
+ def setup
35
+ super
36
+ %w(reminders people_reminders prefix_reminders_suffix p_things_s).each do |table|
37
+ Reminder.connection.drop_table(table) rescue nil
38
+ end
39
+ Reminder.reset_column_information
40
+ @verbose_was, ActiveRecord::Migration.verbose = ActiveRecord::Migration.verbose, false
41
+ @schema_migration = ActiveRecord::Base.connection.schema_migration
42
+ ActiveRecord::Base.connection.schema_cache.clear!
43
+ end
44
+
45
+ teardown do
46
+ ActiveRecord::Base.table_name_prefix = ""
47
+ ActiveRecord::Base.table_name_suffix = ""
48
+
49
+ ActiveRecord::SchemaMigration.create_table
50
+ ActiveRecord::SchemaMigration.delete_all
51
+
52
+ %w(things awesome_things prefix_things_suffix p_awesome_things_s).each do |table|
53
+ Thing.connection.drop_table(table) rescue nil
54
+ end
55
+ Thing.reset_column_information
56
+
57
+ %w(reminders people_reminders prefix_reminders_suffix).each do |table|
58
+ Reminder.connection.drop_table(table) rescue nil
59
+ end
60
+ Reminder.reset_table_name
61
+ Reminder.reset_column_information
62
+
63
+ %w(last_name key bio age height wealth birthday favorite_day
64
+ moment_of_truth male administrator funny).each do |column|
65
+ Person.connection.remove_column("people", column) rescue nil
66
+ end
67
+ Person.connection.remove_column("people", "first_name") rescue nil
68
+ Person.connection.remove_column("people", "middle_name") rescue nil
69
+ Person.connection.add_column("people", "first_name", :string)
70
+ Person.reset_column_information
71
+
72
+ ActiveRecord::Migration.verbose = @verbose_was
73
+ end
74
+
75
+ def test_migration_version_matches_component_version
76
+ assert_equal ActiveRecord::VERSION::STRING.to_f, ActiveRecord::Migration.current_version
77
+ end
78
+
79
+ def test_migrator_versions
80
+ migrations_path = MIGRATIONS_ROOT + "/valid"
81
+ migrator = ActiveRecord::MigrationContext.new(migrations_path, @schema_migration)
82
+
83
+ migrator.up
84
+ assert_equal 3, migrator.current_version
85
+ assert_equal false, migrator.needs_migration?
86
+
87
+ migrator.down
88
+ assert_equal 0, migrator.current_version
89
+ assert_equal true, migrator.needs_migration?
90
+
91
+ ActiveRecord::SchemaMigration.create!(version: 3)
92
+ assert_equal true, migrator.needs_migration?
93
+ end
94
+
95
+ def test_migration_detection_without_schema_migration_table
96
+ ActiveRecord::Base.connection.drop_table "schema_migrations", if_exists: true
97
+
98
+ migrations_path = MIGRATIONS_ROOT + "/valid"
99
+ migrator = ActiveRecord::MigrationContext.new(migrations_path, @schema_migration)
100
+
101
+ assert_equal true, migrator.needs_migration?
102
+ end
103
+
104
+ def test_any_migrations
105
+ migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid", @schema_migration)
106
+
107
+ assert_predicate migrator, :any_migrations?
108
+
109
+ migrator_empty = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/empty", @schema_migration)
110
+
111
+ assert_not_predicate migrator_empty, :any_migrations?
112
+ end
113
+
114
+ def test_migration_version
115
+ migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/version_check", @schema_migration)
116
+ assert_equal 0, migrator.current_version
117
+ migrator.up(20131219224947)
118
+ assert_equal 20131219224947, migrator.current_version
119
+ end
120
+
121
+ def test_create_table_raises_if_already_exists
122
+ connection = Person.connection
123
+ connection.create_table :testings, force: true do |t|
124
+ t.string :foo
125
+ end
126
+
127
+ assert_raise(ActiveRecord::StatementInvalid) do
128
+ connection.create_table :testings do |t|
129
+ t.string :foo
130
+ end
131
+ end
132
+ ensure
133
+ connection.drop_table :testings, if_exists: true
134
+ end
135
+
136
+ def test_create_table_with_if_not_exists_true
137
+ connection = Person.connection
138
+ connection.create_table :testings, force: true do |t|
139
+ t.string :foo
140
+ end
141
+
142
+ assert_nothing_raised do
143
+ connection.create_table :testings, if_not_exists: true do |t|
144
+ t.string :foo
145
+ end
146
+ end
147
+ ensure
148
+ connection.drop_table :testings, if_exists: true
149
+ end
150
+
151
+ def test_create_table_with_indexes_and_if_not_exists_true
152
+ connection = Person.connection
153
+ connection.create_table :testings, force: true do |t|
154
+ t.references :people
155
+ t.string :foo
156
+ end
157
+
158
+ assert_nothing_raised do
159
+ connection.create_table :testings, if_not_exists: true do |t|
160
+ t.references :people
161
+ t.string :foo
162
+ end
163
+ end
164
+ ensure
165
+ connection.drop_table :testings, if_exists: true
166
+ end
167
+
168
+ def test_create_table_with_force_true_does_not_drop_nonexisting_table
169
+ # using a copy as we need the drop_table method to
170
+ # continue to work for the ensure block of the test
171
+ temp_conn = Person.connection.dup
172
+
173
+ assert_not_equal temp_conn, Person.connection
174
+
175
+ temp_conn.create_table :testings2, force: true do |t|
176
+ t.column :foo, :string
177
+ end
178
+ ensure
179
+ Person.connection.drop_table :testings2, if_exists: true
180
+ end
181
+
182
+ def test_remove_column_with_if_not_exists_not_set
183
+ migration_a = Class.new(ActiveRecord::Migration::Current) {
184
+ def version; 100 end
185
+ def migrate(x)
186
+ add_column "people", "last_name", :string
187
+ end
188
+ }.new
189
+
190
+ migration_b = Class.new(ActiveRecord::Migration::Current) {
191
+ def version; 101 end
192
+ def migrate(x)
193
+ remove_column "people", "last_name"
194
+ end
195
+ }.new
196
+
197
+ migration_c = Class.new(ActiveRecord::Migration::Current) {
198
+ def version; 102 end
199
+ def migrate(x)
200
+ remove_column "people", "last_name"
201
+ end
202
+ }.new
203
+
204
+ ActiveRecord::Migrator.new(:up, [migration_a], @schema_migration, 100).migrate
205
+ assert_column Person, :last_name, "migration_a should have added the last_name column on people"
206
+
207
+ ActiveRecord::Migrator.new(:up, [migration_b], @schema_migration, 101).migrate
208
+ assert_no_column Person, :last_name, "migration_b should have dropped the last_name column on people"
209
+
210
+ migrator = ActiveRecord::Migrator.new(:up, [migration_c], @schema_migration, 102)
211
+
212
+ if current_adapter?(:SQLite3Adapter)
213
+ assert_nothing_raised do
214
+ migrator.migrate
215
+ end
216
+ else
217
+ error = assert_raises do
218
+ migrator.migrate
219
+ end
220
+
221
+ if current_adapter?(:Mysql2Adapter)
222
+ if ActiveRecord::Base.connection.mariadb?
223
+ assert_match(/Can't DROP COLUMN `last_name`; check that it exists/, error.message)
224
+ else
225
+ assert_match(/check that column\/key exists/, error.message)
226
+ end
227
+ elsif current_adapter?(:PostgreSQLAdapter)
228
+ assert_match(/column \"last_name\" of relation \"people\" does not exist/, error.message)
229
+ end
230
+ end
231
+ ensure
232
+ Person.reset_column_information
233
+ end
234
+
235
+ def test_remove_column_with_if_exists_set
236
+ migration_a = Class.new(ActiveRecord::Migration::Current) {
237
+ def version; 100 end
238
+ def migrate(x)
239
+ add_column "people", "last_name", :string
240
+ end
241
+ }.new
242
+
243
+ migration_b = Class.new(ActiveRecord::Migration::Current) {
244
+ def version; 101 end
245
+ def migrate(x)
246
+ remove_column "people", "last_name"
247
+ end
248
+ }.new
249
+
250
+ migration_c = Class.new(ActiveRecord::Migration::Current) {
251
+ def version; 102 end
252
+ def migrate(x)
253
+ remove_column "people", "last_name", if_exists: true
254
+ end
255
+ }.new
256
+
257
+ ActiveRecord::Migrator.new(:up, [migration_a], @schema_migration, 100).migrate
258
+ assert_column Person, :last_name, "migration_a should have added the last_name column on people"
259
+
260
+ ActiveRecord::Migrator.new(:up, [migration_b], @schema_migration, 101).migrate
261
+ assert_no_column Person, :last_name, "migration_b should have dropped the last_name column on people"
262
+
263
+ migrator = ActiveRecord::Migrator.new(:up, [migration_c], @schema_migration, 102)
264
+
265
+ assert_nothing_raised do
266
+ migrator.migrate
267
+ end
268
+ ensure
269
+ Person.reset_column_information
270
+ end
271
+
272
+ def test_add_column_with_if_not_exists_not_set
273
+ migration_a = Class.new(ActiveRecord::Migration::Current) {
274
+ def version; 100 end
275
+ def migrate(x)
276
+ add_column "people", "last_name", :string
277
+ end
278
+ }.new
279
+
280
+ migration_b = Class.new(ActiveRecord::Migration::Current) {
281
+ def version; 101 end
282
+ def migrate(x)
283
+ add_column "people", "last_name", :string
284
+ end
285
+ }.new
286
+
287
+ ActiveRecord::Migrator.new(:up, [migration_a], @schema_migration, 100).migrate
288
+ assert_column Person, :last_name, "migration_a should have created the last_name column on people"
289
+
290
+ assert_raises do
291
+ ActiveRecord::Migrator.new(:up, [migration_b], @schema_migration, 101).migrate
292
+ end
293
+ ensure
294
+ Person.reset_column_information
295
+ if Person.column_names.include?("last_name")
296
+ Person.connection.remove_column("people", "last_name")
297
+ end
298
+ end
299
+
300
+ def test_add_column_with_if_not_exists_set_to_true
301
+ migration_a = Class.new(ActiveRecord::Migration::Current) {
302
+ def version; 100 end
303
+ def migrate(x)
304
+ add_column "people", "last_name", :string
305
+ end
306
+ }.new
307
+
308
+ migration_b = Class.new(ActiveRecord::Migration::Current) {
309
+ def version; 101 end
310
+ def migrate(x)
311
+ add_column "people", "last_name", :string, if_not_exists: true
312
+ end
313
+ }.new
314
+
315
+ ActiveRecord::Migrator.new(:up, [migration_a], @schema_migration, 100).migrate
316
+ assert_column Person, :last_name, "migration_a should have created the last_name column on people"
317
+
318
+ assert_nothing_raised do
319
+ ActiveRecord::Migrator.new(:up, [migration_b], @schema_migration, 101).migrate
320
+ end
321
+ ensure
322
+ Person.reset_column_information
323
+ if Person.column_names.include?("last_name")
324
+ Person.connection.remove_column("people", "last_name")
325
+ end
326
+ end
327
+
328
+ def test_add_column_with_if_not_exists_set_to_true_still_raises_if_type_is_different
329
+ migration_a = Class.new(ActiveRecord::Migration::Current) {
330
+ def version; 100 end
331
+ def migrate(x)
332
+ add_column "people", "last_name", :string
333
+ end
334
+ }.new
335
+
336
+ migration_b = Class.new(ActiveRecord::Migration::Current) {
337
+ def version; 101 end
338
+ def migrate(x)
339
+ add_column "people", "last_name", :boolean, if_not_exists: true
340
+ end
341
+ }.new
342
+
343
+ ActiveRecord::Migrator.new(:up, [migration_a], @schema_migration, 100).migrate
344
+ assert_column Person, :last_name, "migration_a should have created the last_name column on people"
345
+
346
+ assert_raises do
347
+ ActiveRecord::Migrator.new(:up, [migration_b], @schema_migration, 101).migrate
348
+ end
349
+ ensure
350
+ Person.reset_column_information
351
+ if Person.column_names.include?("last_name")
352
+ Person.connection.remove_column("people", "last_name")
353
+ end
354
+ end
355
+
356
+ def test_migration_instance_has_connection
357
+ migration = Class.new(ActiveRecord::Migration::Current).new
358
+ assert_equal ActiveRecord::Base.connection, migration.connection
359
+ end
360
+
361
+ def test_method_missing_delegates_to_connection
362
+ migration = Class.new(ActiveRecord::Migration::Current) {
363
+ def connection
364
+ Class.new {
365
+ def create_table; "hi mom!"; end
366
+ }.new
367
+ end
368
+ }.new
369
+
370
+ assert_equal "hi mom!", migration.method_missing(:create_table)
371
+ end
372
+
373
+ def test_add_table_with_decimals
374
+ Person.connection.drop_table :big_numbers rescue nil
375
+
376
+ assert_not_predicate BigNumber, :table_exists?
377
+ GiveMeBigNumbers.up
378
+ assert_predicate BigNumber, :table_exists?
379
+ BigNumber.reset_column_information
380
+
381
+ assert BigNumber.create(
382
+ bank_balance: 1586.43,
383
+ big_bank_balance: BigDecimal("1000234000567.95"),
384
+ world_population: 2**62,
385
+ my_house_population: 3,
386
+ value_of_e: BigDecimal("2.7182818284590452353602875")
387
+ )
388
+
389
+ b = BigNumber.first
390
+ assert_not_nil b
391
+
392
+ assert_not_nil b.bank_balance
393
+ assert_not_nil b.big_bank_balance
394
+ assert_not_nil b.world_population
395
+ assert_not_nil b.my_house_population
396
+ assert_not_nil b.value_of_e
397
+
398
+ assert_kind_of Integer, b.world_population
399
+ assert_equal 2**62, b.world_population
400
+ assert_kind_of Integer, b.my_house_population
401
+ assert_equal 3, b.my_house_population
402
+ assert_kind_of BigDecimal, b.bank_balance
403
+ assert_equal BigDecimal("1586.43"), b.bank_balance
404
+ assert_kind_of BigDecimal, b.big_bank_balance
405
+ assert_equal BigDecimal("1000234000567.95"), b.big_bank_balance
406
+
407
+ # This one is fun. The 'value_of_e' field is defined as 'DECIMAL' with
408
+ # precision/scale explicitly left out. By the SQL standard, numbers
409
+ # assigned to this field should be truncated but that's seldom respected.
410
+ if current_adapter?(:PostgreSQLAdapter)
411
+ # - PostgreSQL changes the SQL spec on columns declared simply as
412
+ # "decimal" to something more useful: instead of being given a scale
413
+ # of 0, they take on the compile-time limit for precision and scale,
414
+ # so the following should succeed unless you have used really wacky
415
+ # compilation options
416
+ assert_kind_of BigDecimal, b.value_of_e
417
+ assert_equal BigDecimal("2.7182818284590452353602875"), b.value_of_e
418
+ elsif current_adapter?(:SQLite3Adapter)
419
+ # - SQLite3 stores a float, in violation of SQL
420
+ assert_kind_of BigDecimal, b.value_of_e
421
+ assert_in_delta BigDecimal("2.71828182845905"), b.value_of_e, 0.00000000000001
422
+ else
423
+ # - SQL standard is an integer
424
+ assert_kind_of Integer, b.value_of_e
425
+ assert_equal 2, b.value_of_e
426
+ end
427
+
428
+ GiveMeBigNumbers.down
429
+ assert_raise(ActiveRecord::StatementInvalid) { BigNumber.first }
430
+ end
431
+
432
+ def test_filtering_migrations
433
+ assert_no_column Person, :last_name
434
+ assert_not_predicate Reminder, :table_exists?
435
+
436
+ name_filter = lambda { |migration| migration.name == "ValidPeopleHaveLastNames" }
437
+ migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid", @schema_migration)
438
+ migrator.up(&name_filter)
439
+
440
+ assert_column Person, :last_name
441
+ assert_raise(ActiveRecord::StatementInvalid) { Reminder.first }
442
+
443
+ migrator.down(&name_filter)
444
+
445
+ assert_no_column Person, :last_name
446
+ assert_raise(ActiveRecord::StatementInvalid) { Reminder.first }
447
+ end
448
+
449
+ class MockMigration < ActiveRecord::Migration::Current
450
+ attr_reader :went_up, :went_down
451
+ def initialize
452
+ @went_up = false
453
+ @went_down = false
454
+ end
455
+
456
+ def up
457
+ @went_up = true
458
+ super
459
+ end
460
+
461
+ def down
462
+ @went_down = true
463
+ super
464
+ end
465
+ end
466
+
467
+ def test_instance_based_migration_up
468
+ migration = MockMigration.new
469
+ assert_not migration.went_up, "have not gone up"
470
+ assert_not migration.went_down, "have not gone down"
471
+
472
+ migration.migrate :up
473
+ assert migration.went_up, "have gone up"
474
+ assert_not migration.went_down, "have not gone down"
475
+ end
476
+
477
+ def test_instance_based_migration_down
478
+ migration = MockMigration.new
479
+ assert_not migration.went_up, "have not gone up"
480
+ assert_not migration.went_down, "have not gone down"
481
+
482
+ migration.migrate :down
483
+ assert_not migration.went_up, "have gone up"
484
+ assert migration.went_down, "have not gone down"
485
+ end
486
+
487
+ if ActiveRecord::Base.connection.supports_ddl_transactions?
488
+ def test_migrator_one_up_with_exception_and_rollback
489
+ assert_no_column Person, :last_name
490
+
491
+ migration = Class.new(ActiveRecord::Migration::Current) {
492
+ def version; 100 end
493
+ def migrate(x)
494
+ add_column "people", "last_name", :string
495
+ raise "Something broke"
496
+ end
497
+ }.new
498
+
499
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100)
500
+
501
+ e = assert_raise(StandardError) { migrator.migrate }
502
+
503
+ assert_equal "An error has occurred, this and all later migrations canceled:\n\nSomething broke", e.message
504
+
505
+ assert_no_column Person, :last_name,
506
+ "On error, the Migrator should revert schema changes but it did not."
507
+ end
508
+
509
+ def test_migrator_one_up_with_exception_and_rollback_using_run
510
+ assert_no_column Person, :last_name
511
+
512
+ migration = Class.new(ActiveRecord::Migration::Current) {
513
+ def version; 100 end
514
+ def migrate(x)
515
+ add_column "people", "last_name", :string
516
+ raise "Something broke"
517
+ end
518
+ }.new
519
+
520
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100)
521
+
522
+ e = assert_raise(StandardError) { migrator.run }
523
+
524
+ assert_equal "An error has occurred, this and all later migrations canceled:\n\nSomething broke", e.message
525
+
526
+ assert_no_column Person, :last_name,
527
+ "On error, the Migrator should revert schema changes but it did not."
528
+ end
529
+
530
+ def test_migration_without_transaction
531
+ assert_no_column Person, :last_name
532
+
533
+ migration = Class.new(ActiveRecord::Migration::Current) {
534
+ disable_ddl_transaction!
535
+
536
+ def version; 101 end
537
+ def migrate(x)
538
+ add_column "people", "last_name", :string
539
+ raise "Something broke"
540
+ end
541
+ }.new
542
+
543
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 101)
544
+ e = assert_raise(StandardError) { migrator.migrate }
545
+ assert_equal "An error has occurred, all later migrations canceled:\n\nSomething broke", e.message
546
+
547
+ assert_column Person, :last_name,
548
+ "without ddl transactions, the Migrator should not rollback on error but it did."
549
+ ensure
550
+ Person.reset_column_information
551
+ if Person.column_names.include?("last_name")
552
+ Person.connection.remove_column("people", "last_name")
553
+ end
554
+ end
555
+ end
556
+
557
+ def test_schema_migrations_table_name
558
+ original_schema_migrations_table_name = ActiveRecord::Base.schema_migrations_table_name
559
+
560
+ assert_equal "schema_migrations", ActiveRecord::SchemaMigration.table_name
561
+ ActiveRecord::Base.table_name_prefix = "prefix_"
562
+ ActiveRecord::Base.table_name_suffix = "_suffix"
563
+ Reminder.reset_table_name
564
+ assert_equal "prefix_schema_migrations_suffix", ActiveRecord::SchemaMigration.table_name
565
+ ActiveRecord::Base.schema_migrations_table_name = "changed"
566
+ Reminder.reset_table_name
567
+ assert_equal "prefix_changed_suffix", ActiveRecord::SchemaMigration.table_name
568
+ ActiveRecord::Base.table_name_prefix = ""
569
+ ActiveRecord::Base.table_name_suffix = ""
570
+ Reminder.reset_table_name
571
+ assert_equal "changed", ActiveRecord::SchemaMigration.table_name
572
+ ensure
573
+ ActiveRecord::Base.schema_migrations_table_name = original_schema_migrations_table_name
574
+ ActiveRecord::SchemaMigration.reset_table_name
575
+ Reminder.reset_table_name
576
+ end
577
+
578
+ def test_internal_metadata_table_name
579
+ original_internal_metadata_table_name = ActiveRecord::Base.internal_metadata_table_name
580
+
581
+ assert_equal "ar_internal_metadata", ActiveRecord::InternalMetadata.table_name
582
+ ActiveRecord::Base.table_name_prefix = "p_"
583
+ ActiveRecord::Base.table_name_suffix = "_s"
584
+ Reminder.reset_table_name
585
+ assert_equal "p_ar_internal_metadata_s", ActiveRecord::InternalMetadata.table_name
586
+ ActiveRecord::Base.internal_metadata_table_name = "changed"
587
+ Reminder.reset_table_name
588
+ assert_equal "p_changed_s", ActiveRecord::InternalMetadata.table_name
589
+ ActiveRecord::Base.table_name_prefix = ""
590
+ ActiveRecord::Base.table_name_suffix = ""
591
+ Reminder.reset_table_name
592
+ assert_equal "changed", ActiveRecord::InternalMetadata.table_name
593
+ ensure
594
+ ActiveRecord::Base.internal_metadata_table_name = original_internal_metadata_table_name
595
+ ActiveRecord::InternalMetadata.reset_table_name
596
+ Reminder.reset_table_name
597
+ end
598
+
599
+ def test_internal_metadata_stores_environment
600
+ current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
601
+ migrations_path = MIGRATIONS_ROOT + "/valid"
602
+ migrator = ActiveRecord::MigrationContext.new(migrations_path, @schema_migration)
603
+
604
+ migrator.up
605
+ assert_equal current_env, ActiveRecord::InternalMetadata[:environment]
606
+
607
+ original_rails_env = ENV["RAILS_ENV"]
608
+ original_rack_env = ENV["RACK_ENV"]
609
+ ENV["RAILS_ENV"] = ENV["RACK_ENV"] = "foofoo"
610
+ new_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
611
+
612
+ assert_not_equal current_env, new_env
613
+
614
+ sleep 1 # mysql by default does not store fractional seconds in the database
615
+ migrator.up
616
+ assert_equal new_env, ActiveRecord::InternalMetadata[:environment]
617
+ ensure
618
+ ENV["RAILS_ENV"] = original_rails_env
619
+ ENV["RACK_ENV"] = original_rack_env
620
+ migrator.up
621
+ end
622
+
623
+ def test_internal_metadata_stores_environment_when_other_data_exists
624
+ ActiveRecord::InternalMetadata.delete_all
625
+ ActiveRecord::InternalMetadata[:foo] = "bar"
626
+
627
+ current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
628
+ migrations_path = MIGRATIONS_ROOT + "/valid"
629
+
630
+ migrator = ActiveRecord::MigrationContext.new(migrations_path, @schema_migration)
631
+ migrator.up
632
+ assert_equal current_env, ActiveRecord::InternalMetadata[:environment]
633
+ assert_equal "bar", ActiveRecord::InternalMetadata[:foo]
634
+ end
635
+
636
+ def test_internal_metadata_not_used_when_not_enabled
637
+ ActiveRecord::InternalMetadata.drop_table
638
+ original_config = ActiveRecord::Base.connection.instance_variable_get("@config")
639
+
640
+ modified_config = original_config.dup.merge(use_metadata_table: false)
641
+
642
+ ActiveRecord::Base.connection
643
+ .instance_variable_set("@config", modified_config)
644
+
645
+ assert_not ActiveRecord::InternalMetadata.enabled?
646
+ assert_not ActiveRecord::InternalMetadata.table_exists?
647
+
648
+ migrations_path = MIGRATIONS_ROOT + "/valid"
649
+ migrator = ActiveRecord::MigrationContext.new(migrations_path, @schema_migration)
650
+ migrator.up
651
+
652
+ assert_not ActiveRecord::InternalMetadata[:environment]
653
+ assert_not ActiveRecord::InternalMetadata.table_exists?
654
+ ensure
655
+ ActiveRecord::Base.connection.instance_variable_set("@config", original_config)
656
+ ActiveRecord::InternalMetadata.create_table
657
+ end
658
+
659
+ def test_internal_metadata_create_table_wont_be_affected_by_schema_cache
660
+ ActiveRecord::InternalMetadata.drop_table
661
+ assert_not_predicate ActiveRecord::InternalMetadata, :table_exists?
662
+
663
+ ActiveRecord::InternalMetadata.connection.transaction do
664
+ ActiveRecord::InternalMetadata.create_table
665
+ assert_predicate ActiveRecord::InternalMetadata, :table_exists?
666
+
667
+ ActiveRecord::InternalMetadata[:version] = "foo"
668
+ assert_equal "foo", ActiveRecord::InternalMetadata[:version]
669
+ raise ActiveRecord::Rollback
670
+ end
671
+
672
+ ActiveRecord::InternalMetadata.connection.transaction do
673
+ ActiveRecord::InternalMetadata.create_table
674
+ assert_predicate ActiveRecord::InternalMetadata, :table_exists?
675
+
676
+ ActiveRecord::InternalMetadata[:version] = "bar"
677
+ assert_equal "bar", ActiveRecord::InternalMetadata[:version]
678
+ raise ActiveRecord::Rollback
679
+ end
680
+ ensure
681
+ ActiveRecord::InternalMetadata.create_table
682
+ end
683
+
684
+ def test_schema_migration_create_table_wont_be_affected_by_schema_cache
685
+ ActiveRecord::SchemaMigration.drop_table
686
+ assert_not_predicate ActiveRecord::SchemaMigration, :table_exists?
687
+
688
+ ActiveRecord::SchemaMigration.connection.transaction do
689
+ ActiveRecord::SchemaMigration.create_table
690
+ assert_predicate ActiveRecord::SchemaMigration, :table_exists?
691
+
692
+ schema_migration = ActiveRecord::SchemaMigration.create!(version: "foo")
693
+ assert_equal "foo", schema_migration[:version]
694
+ raise ActiveRecord::Rollback
695
+ end
696
+
697
+ ActiveRecord::SchemaMigration.connection.transaction do
698
+ ActiveRecord::SchemaMigration.create_table
699
+ assert_predicate ActiveRecord::SchemaMigration, :table_exists?
700
+
701
+ schema_migration = ActiveRecord::SchemaMigration.create!(version: "bar")
702
+ assert_equal "bar", schema_migration[:version]
703
+ raise ActiveRecord::Rollback
704
+ end
705
+ ensure
706
+ ActiveRecord::SchemaMigration.create_table
707
+ end
708
+
709
+ def test_proper_table_name_on_migration
710
+ reminder_class = new_isolated_reminder_class
711
+ migration = ActiveRecord::Migration.new
712
+ assert_equal "table", migration.proper_table_name("table")
713
+ assert_equal "table", migration.proper_table_name(:table)
714
+ assert_equal "reminders", migration.proper_table_name(reminder_class)
715
+ reminder_class.reset_table_name
716
+ assert_equal reminder_class.table_name, migration.proper_table_name(reminder_class)
717
+
718
+ # Use the model's own prefix/suffix if a model is given
719
+ ActiveRecord::Base.table_name_prefix = "ARprefix_"
720
+ ActiveRecord::Base.table_name_suffix = "_ARsuffix"
721
+ reminder_class.table_name_prefix = "prefix_"
722
+ reminder_class.table_name_suffix = "_suffix"
723
+ reminder_class.reset_table_name
724
+ assert_equal "prefix_reminders_suffix", migration.proper_table_name(reminder_class)
725
+ reminder_class.table_name_prefix = ""
726
+ reminder_class.table_name_suffix = ""
727
+ reminder_class.reset_table_name
728
+
729
+ # Use AR::Base's prefix/suffix if string or symbol is given
730
+ ActiveRecord::Base.table_name_prefix = "prefix_"
731
+ ActiveRecord::Base.table_name_suffix = "_suffix"
732
+ reminder_class.reset_table_name
733
+ assert_equal "prefix_table_suffix", migration.proper_table_name("table", migration.table_name_options)
734
+ assert_equal "prefix_table_suffix", migration.proper_table_name(:table, migration.table_name_options)
735
+ end
736
+
737
+ def test_rename_table_with_prefix_and_suffix
738
+ assert_not_predicate Thing, :table_exists?
739
+ ActiveRecord::Base.table_name_prefix = "p_"
740
+ ActiveRecord::Base.table_name_suffix = "_s"
741
+ Thing.reset_table_name
742
+ Thing.reset_sequence_name
743
+ WeNeedThings.up
744
+ assert_predicate Thing, :table_exists?
745
+ Thing.reset_column_information
746
+
747
+ assert Thing.create("content" => "hello world")
748
+ assert_equal "hello world", Thing.first.content
749
+
750
+ RenameThings.up
751
+ Thing.table_name = "p_awesome_things_s"
752
+
753
+ assert_equal "hello world", Thing.first.content
754
+ ensure
755
+ Thing.reset_table_name
756
+ Thing.reset_sequence_name
757
+ end
758
+
759
+ def test_add_drop_table_with_prefix_and_suffix
760
+ assert_not_predicate Reminder, :table_exists?
761
+ ActiveRecord::Base.table_name_prefix = "prefix_"
762
+ ActiveRecord::Base.table_name_suffix = "_suffix"
763
+ Reminder.reset_table_name
764
+ Reminder.reset_sequence_name
765
+ WeNeedReminders.up
766
+ assert_predicate Reminder, :table_exists?
767
+ Reminder.reset_column_information
768
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
769
+ assert_equal "hello world", Reminder.first.content
770
+
771
+ WeNeedReminders.down
772
+ assert_raise(ActiveRecord::StatementInvalid) { Reminder.first }
773
+ ensure
774
+ Reminder.reset_sequence_name
775
+ end
776
+
777
+ def test_create_table_with_binary_column
778
+ assert_nothing_raised {
779
+ Person.connection.create_table :binary_testings do |t|
780
+ t.column "data", :binary, null: false
781
+ end
782
+ }
783
+
784
+ columns = Person.connection.columns(:binary_testings)
785
+ data_column = columns.detect { |c| c.name == "data" }
786
+
787
+ assert_nil data_column.default
788
+ ensure
789
+ Person.connection.drop_table :binary_testings, if_exists: true
790
+ end
791
+
792
+ unless mysql_enforcing_gtid_consistency?
793
+ def test_create_table_with_query
794
+ Person.connection.create_table :table_from_query_testings, as: "SELECT id FROM people WHERE id = 1"
795
+
796
+ columns = Person.connection.columns(:table_from_query_testings)
797
+ assert_equal [1], Person.connection.select_values("SELECT * FROM table_from_query_testings")
798
+ assert_equal 1, columns.length
799
+ assert_equal "id", columns.first.name
800
+ ensure
801
+ Person.connection.drop_table :table_from_query_testings rescue nil
802
+ end
803
+
804
+ def test_create_table_with_query_from_relation
805
+ Person.connection.create_table :table_from_query_testings, as: Person.select(:id).where(id: 1)
806
+
807
+ columns = Person.connection.columns(:table_from_query_testings)
808
+ assert_equal [1], Person.connection.select_values("SELECT * FROM table_from_query_testings")
809
+ assert_equal 1, columns.length
810
+ assert_equal "id", columns.first.name
811
+ ensure
812
+ Person.connection.drop_table :table_from_query_testings rescue nil
813
+ end
814
+ end
815
+
816
+ if current_adapter?(:SQLite3Adapter)
817
+ def test_allows_sqlite3_rollback_on_invalid_column_type
818
+ Person.connection.create_table :something, force: true do |t|
819
+ t.column :number, :integer
820
+ t.column :name, :string
821
+ t.column :foo, :bar
822
+ end
823
+ assert Person.connection.column_exists?(:something, :foo)
824
+ assert_nothing_raised { Person.connection.remove_column :something, :foo, :bar }
825
+ assert_not Person.connection.column_exists?(:something, :foo)
826
+ assert Person.connection.column_exists?(:something, :name)
827
+ assert Person.connection.column_exists?(:something, :number)
828
+ ensure
829
+ Person.connection.drop_table :something, if_exists: true
830
+ end
831
+ end
832
+
833
+ def test_decimal_scale_without_precision_should_raise
834
+ e = assert_raise(ArgumentError) do
835
+ Person.connection.create_table :test_decimal_scales, force: true do |t|
836
+ t.decimal :scaleonly, scale: 10
837
+ end
838
+ end
839
+
840
+ assert_equal "Error adding decimal column: precision cannot be empty if scale is specified", e.message
841
+ ensure
842
+ Person.connection.drop_table :test_decimal_scales, if_exists: true
843
+ end
844
+
845
+ if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter)
846
+ def test_out_of_range_integer_limit_should_raise
847
+ e = assert_raise(ArgumentError) do
848
+ Person.connection.create_table :test_integer_limits, force: true do |t|
849
+ t.column :bigone, :integer, limit: 10
850
+ end
851
+ end
852
+
853
+ assert_includes e.message, "No integer type has byte size 10"
854
+ ensure
855
+ Person.connection.drop_table :test_integer_limits, if_exists: true
856
+ end
857
+
858
+ def test_out_of_range_text_limit_should_raise
859
+ e = assert_raise(ArgumentError) do
860
+ Person.connection.create_table :test_text_limits, force: true do |t|
861
+ t.text :bigtext, limit: 0xfffffffff
862
+ end
863
+ end
864
+
865
+ assert_includes e.message, "No text type has byte size #{0xfffffffff}"
866
+ ensure
867
+ Person.connection.drop_table :test_text_limits, if_exists: true
868
+ end
869
+
870
+ def test_out_of_range_binary_limit_should_raise
871
+ e = assert_raise(ArgumentError) do
872
+ Person.connection.create_table :test_binary_limits, force: true do |t|
873
+ t.binary :bigbinary, limit: 0xfffffffff
874
+ end
875
+ end
876
+
877
+ assert_includes e.message, "No binary type has byte size #{0xfffffffff}"
878
+ ensure
879
+ Person.connection.drop_table :test_binary_limits, if_exists: true
880
+ end
881
+ end
882
+
883
+ if current_adapter?(:Mysql2Adapter)
884
+ def test_invalid_text_size_should_raise
885
+ e = assert_raise(ArgumentError) do
886
+ Person.connection.create_table :test_text_sizes, force: true do |t|
887
+ t.text :bigtext, size: 0xfffffffff
888
+ end
889
+ end
890
+
891
+ assert_equal "#{0xfffffffff} is invalid :size value. Only :tiny, :medium, and :long are allowed.", e.message
892
+ ensure
893
+ Person.connection.drop_table :test_text_sizes, if_exists: true
894
+ end
895
+ end
896
+
897
+ if ActiveRecord::Base.connection.supports_advisory_locks?
898
+ def test_migrator_generates_valid_lock_id
899
+ migration = Class.new(ActiveRecord::Migration::Current).new
900
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100)
901
+
902
+ lock_id = migrator.send(:generate_migrator_advisory_lock_id)
903
+
904
+ assert ActiveRecord::Base.connection.get_advisory_lock(lock_id),
905
+ "the Migrator should have generated a valid lock id, but it didn't"
906
+ assert ActiveRecord::Base.connection.release_advisory_lock(lock_id),
907
+ "the Migrator should have generated a valid lock id, but it didn't"
908
+ end
909
+
910
+ def test_generate_migrator_advisory_lock_id
911
+ # It is important we are consistent with how we generate this so that
912
+ # exclusive locking works across migrator versions
913
+ migration = Class.new(ActiveRecord::Migration::Current).new
914
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100)
915
+
916
+ lock_id = migrator.send(:generate_migrator_advisory_lock_id)
917
+
918
+ current_database = ActiveRecord::Base.connection.current_database
919
+ salt = ActiveRecord::Migrator::MIGRATOR_SALT
920
+ expected_id = Zlib.crc32(current_database) * salt
921
+
922
+ assert lock_id == expected_id, "expected lock id generated by the migrator to be #{expected_id}, but it was #{lock_id} instead"
923
+ assert lock_id.bit_length <= 63, "lock id must be a signed integer of max 63 bits magnitude"
924
+ end
925
+
926
+ def test_migrator_one_up_with_unavailable_lock
927
+ assert_no_column Person, :last_name
928
+
929
+ migration = Class.new(ActiveRecord::Migration::Current) {
930
+ def version; 100 end
931
+ def migrate(x)
932
+ add_column "people", "last_name", :string
933
+ end
934
+ }.new
935
+
936
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100)
937
+ lock_id = migrator.send(:generate_migrator_advisory_lock_id)
938
+
939
+ with_another_process_holding_lock(lock_id) do
940
+ assert_raise(ActiveRecord::ConcurrentMigrationError) { migrator.migrate }
941
+ end
942
+
943
+ assert_no_column Person, :last_name,
944
+ "without an advisory lock, the Migrator should not make any changes, but it did."
945
+ end
946
+
947
+ def test_migrator_one_up_with_unavailable_lock_using_run
948
+ assert_no_column Person, :last_name
949
+
950
+ migration = Class.new(ActiveRecord::Migration::Current) {
951
+ def version; 100 end
952
+ def migrate(x)
953
+ add_column "people", "last_name", :string
954
+ end
955
+ }.new
956
+
957
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100)
958
+ lock_id = migrator.send(:generate_migrator_advisory_lock_id)
959
+
960
+ with_another_process_holding_lock(lock_id) do
961
+ assert_raise(ActiveRecord::ConcurrentMigrationError) { migrator.run }
962
+ end
963
+
964
+ assert_no_column Person, :last_name,
965
+ "without an advisory lock, the Migrator should not make any changes, but it did."
966
+ end
967
+
968
+ def test_with_advisory_lock_doesnt_release_closed_connections
969
+ migration = Class.new(ActiveRecord::Migration::Current).new
970
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100)
971
+
972
+ silence_stream($stderr) do
973
+ migrator.send(:with_advisory_lock) do
974
+ ActiveRecord::Base.establish_connection :arunit
975
+ end
976
+ end
977
+ end
978
+
979
+ if current_adapter?(:PostgreSQLAdapter)
980
+ def test_with_advisory_lock_closes_connection
981
+ migration = Class.new(ActiveRecord::Migration::Current) {
982
+ def version; 100 end
983
+ def migrate(x)
984
+ end
985
+ }.new
986
+
987
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100)
988
+ lock_id = migrator.send(:generate_migrator_advisory_lock_id)
989
+
990
+ query = <<~SQL
991
+ SELECT query
992
+ FROM pg_stat_activity
993
+ WHERE datname = '#{ActiveRecord::Base.connection_db_config.database}'
994
+ AND state = 'idle'
995
+ AND query LIKE '%#{lock_id}%'
996
+ SQL
997
+
998
+ assert_no_changes -> { ActiveRecord::Base.connection.exec_query(query).rows.flatten } do
999
+ migrator.migrate
1000
+ end
1001
+ end
1002
+ end
1003
+
1004
+ def test_with_advisory_lock_raises_the_right_error_when_it_fails_to_release_lock
1005
+ migration = Class.new(ActiveRecord::Migration::Current).new
1006
+ migrator = ActiveRecord::Migrator.new(:up, [migration], @schema_migration, 100)
1007
+ lock_id = migrator.send(:generate_migrator_advisory_lock_id)
1008
+
1009
+ e = assert_raises(ActiveRecord::ConcurrentMigrationError) do
1010
+ silence_stream($stderr) do
1011
+ migrator.stub(:with_advisory_lock_connection, ->(&block) { block.call(ActiveRecord::Base.connection) }) do
1012
+ migrator.send(:with_advisory_lock) do
1013
+ ActiveRecord::Base.connection.release_advisory_lock(lock_id)
1014
+ end
1015
+ end
1016
+ end
1017
+ end
1018
+
1019
+ assert_match(
1020
+ /#{ActiveRecord::ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE}/,
1021
+ e.message
1022
+ )
1023
+ end
1024
+ end
1025
+
1026
+ private
1027
+ # This is needed to isolate class_attribute assignments like `table_name_prefix`
1028
+ # for each test case.
1029
+ def new_isolated_reminder_class
1030
+ Class.new(Reminder) {
1031
+ def self.name; "Reminder"; end
1032
+ def self.base_class; self; end
1033
+ }
1034
+ end
1035
+
1036
+ def with_another_process_holding_lock(lock_id)
1037
+ thread_lock = Concurrent::CountDownLatch.new
1038
+ test_terminated = Concurrent::CountDownLatch.new
1039
+
1040
+ other_process = Thread.new do
1041
+ conn = ActiveRecord::Base.connection_pool.checkout
1042
+ conn.get_advisory_lock(lock_id)
1043
+ thread_lock.count_down
1044
+ test_terminated.wait # hold the lock open until we tested everything
1045
+ ensure
1046
+ conn.release_advisory_lock(lock_id)
1047
+ ActiveRecord::Base.connection_pool.checkin(conn)
1048
+ end
1049
+
1050
+ thread_lock.wait # wait until the 'other process' has the lock
1051
+
1052
+ yield
1053
+
1054
+ test_terminated.count_down
1055
+ other_process.join
1056
+ end
1057
+ end
1058
+
1059
+ class ReservedWordsMigrationTest < ActiveRecord::TestCase
1060
+ def test_drop_index_from_table_named_values
1061
+ connection = Person.connection
1062
+ connection.create_table :values, force: true do |t|
1063
+ t.integer :value
1064
+ end
1065
+
1066
+ assert_nothing_raised do
1067
+ connection.add_index :values, :value
1068
+ connection.remove_index :values, :value
1069
+ end
1070
+ ensure
1071
+ connection.drop_table :values rescue nil
1072
+ end
1073
+ end
1074
+
1075
+ class ExplicitlyNamedIndexMigrationTest < ActiveRecord::TestCase
1076
+ def test_drop_index_by_name
1077
+ connection = Person.connection
1078
+ connection.create_table :values, force: true do |t|
1079
+ t.integer :value
1080
+ end
1081
+
1082
+ assert_nothing_raised do
1083
+ connection.add_index :values, :value, name: "a_different_name"
1084
+ connection.remove_index :values, :value, name: "a_different_name"
1085
+ end
1086
+ ensure
1087
+ connection.drop_table :values rescue nil
1088
+ end
1089
+ end
1090
+
1091
+ if ActiveRecord::Base.connection.supports_bulk_alter?
1092
+ class BulkAlterTableMigrationsTest < ActiveRecord::TestCase
1093
+ def setup
1094
+ @connection = Person.connection
1095
+ @connection.create_table(:delete_me, force: true) { |t| }
1096
+ Person.reset_column_information
1097
+ Person.reset_sequence_name
1098
+ end
1099
+
1100
+ teardown do
1101
+ Person.connection.drop_table(:delete_me) rescue nil
1102
+ end
1103
+
1104
+ def test_adding_multiple_columns
1105
+ classname = ActiveRecord::Base.connection.class.name[/[^:]*$/]
1106
+ expected_query_count = {
1107
+ "Mysql2Adapter" => 1,
1108
+ "PostgreSQLAdapter" => 2, # one for bulk change, one for comment
1109
+ }.fetch(classname) {
1110
+ raise "need an expected query count for #{classname}"
1111
+ }
1112
+
1113
+ assert_queries(expected_query_count) do
1114
+ with_bulk_change_table do |t|
1115
+ t.column :name, :string
1116
+ t.string :qualification, :experience
1117
+ t.integer :age, default: 0
1118
+ t.date :birthdate, comment: "This is a comment"
1119
+ t.timestamps null: true
1120
+ end
1121
+ end
1122
+
1123
+ assert_equal 8, columns.size
1124
+ [:name, :qualification, :experience].each { |s| assert_equal :string, column(s).type }
1125
+ assert_equal "0", column(:age).default
1126
+ assert_equal "This is a comment", column(:birthdate).comment
1127
+ end
1128
+
1129
+ def test_rename_columns
1130
+ with_bulk_change_table do |t|
1131
+ t.string :qualification
1132
+ end
1133
+
1134
+ assert column(:qualification)
1135
+
1136
+ with_bulk_change_table do |t|
1137
+ t.rename :qualification, :experience
1138
+ t.string :qualification_experience
1139
+ end
1140
+
1141
+ assert_not column(:qualification)
1142
+ assert column(:experience)
1143
+ assert column(:qualification_experience)
1144
+ end
1145
+
1146
+ def test_removing_columns
1147
+ with_bulk_change_table do |t|
1148
+ t.string :qualification, :experience
1149
+ end
1150
+
1151
+ [:qualification, :experience].each { |c| assert column(c) }
1152
+
1153
+ assert_queries(1) do
1154
+ with_bulk_change_table do |t|
1155
+ t.remove :qualification, :experience
1156
+ t.string :qualification_experience
1157
+ end
1158
+ end
1159
+
1160
+ [:qualification, :experience].each { |c| assert_not column(c) }
1161
+ assert column(:qualification_experience)
1162
+ end
1163
+
1164
+ def test_adding_indexes
1165
+ with_bulk_change_table do |t|
1166
+ t.string :username
1167
+ t.string :name
1168
+ t.integer :age
1169
+ end
1170
+
1171
+ classname = ActiveRecord::Base.connection.class.name[/[^:]*$/]
1172
+ expected_query_count = {
1173
+ "Mysql2Adapter" => 1, # mysql2 supports creating two indexes using one statement
1174
+ "PostgreSQLAdapter" => 3,
1175
+ }.fetch(classname) {
1176
+ raise "need an expected query count for #{classname}"
1177
+ }
1178
+
1179
+ assert_queries(expected_query_count) do
1180
+ with_bulk_change_table do |t|
1181
+ t.index :username, unique: true, name: :awesome_username_index
1182
+ t.index [:name, :age], comment: "This is a comment"
1183
+ end
1184
+ end
1185
+
1186
+ assert_equal 2, indexes.size
1187
+
1188
+ name_age_index = index(:index_delete_me_on_name_and_age)
1189
+ assert_equal ["name", "age"].sort, name_age_index.columns.sort
1190
+ assert_equal "This is a comment", name_age_index.comment
1191
+ assert_not name_age_index.unique
1192
+
1193
+ assert index(:awesome_username_index).unique
1194
+ end
1195
+
1196
+ def test_removing_index
1197
+ with_bulk_change_table do |t|
1198
+ t.string :name
1199
+ t.index :name
1200
+ end
1201
+
1202
+ assert index(:index_delete_me_on_name)
1203
+
1204
+ classname = ActiveRecord::Base.connection.class.name[/[^:]*$/]
1205
+ expected_query_count = {
1206
+ "Mysql2Adapter" => 1, # mysql2 supports dropping and creating two indexes using one statement
1207
+ "PostgreSQLAdapter" => 2,
1208
+ }.fetch(classname) {
1209
+ raise "need an expected query count for #{classname}"
1210
+ }
1211
+
1212
+ assert_queries(expected_query_count) do
1213
+ with_bulk_change_table do |t|
1214
+ t.remove_index :name
1215
+ t.index :name, name: :new_name_index, unique: true
1216
+ end
1217
+ end
1218
+
1219
+ assert_not index(:index_delete_me_on_name)
1220
+
1221
+ new_name_index = index(:new_name_index)
1222
+ assert new_name_index.unique
1223
+ end
1224
+
1225
+ def test_changing_columns
1226
+ with_bulk_change_table do |t|
1227
+ t.string :name
1228
+ t.date :birthdate
1229
+ end
1230
+
1231
+ assert_not column(:name).default
1232
+ assert_equal :date, column(:birthdate).type
1233
+
1234
+ classname = ActiveRecord::Base.connection.class.name[/[^:]*$/]
1235
+ expected_query_count = {
1236
+ "Mysql2Adapter" => 3, # one query for columns, one query for primary key, one query to do the bulk change
1237
+ "PostgreSQLAdapter" => 3, # one query for columns, one for bulk change, one for comment
1238
+ }.fetch(classname) {
1239
+ raise "need an expected query count for #{classname}"
1240
+ }
1241
+
1242
+ assert_queries(expected_query_count, ignore_none: true) do
1243
+ with_bulk_change_table do |t|
1244
+ t.change :name, :string, default: "NONAME"
1245
+ t.change :birthdate, :datetime, comment: "This is a comment"
1246
+ end
1247
+ end
1248
+
1249
+ assert_equal "NONAME", column(:name).default
1250
+ assert_equal :datetime, column(:birthdate).type
1251
+ assert_equal "This is a comment", column(:birthdate).comment
1252
+ end
1253
+
1254
+ def test_changing_index
1255
+ with_bulk_change_table do |t|
1256
+ t.string :username
1257
+ t.index :username, name: :username_index
1258
+ end
1259
+
1260
+ assert index(:username_index)
1261
+ assert_not index(:username_index).unique
1262
+
1263
+ classname = ActiveRecord::Base.connection.class.name[/[^:]*$/]
1264
+ expected_query_count = {
1265
+ "Mysql2Adapter" => 1, # mysql2 supports dropping and creating two indexes using one statement
1266
+ "PostgreSQLAdapter" => 2,
1267
+ }.fetch(classname) {
1268
+ raise "need an expected query count for #{classname}"
1269
+ }
1270
+
1271
+ assert_queries(expected_query_count) do
1272
+ with_bulk_change_table do |t|
1273
+ t.remove_index name: :username_index
1274
+ t.index :username, name: :username_index, unique: true
1275
+ end
1276
+ end
1277
+
1278
+ assert index(:username_index)
1279
+ assert index(:username_index).unique
1280
+ end
1281
+
1282
+ private
1283
+ def with_bulk_change_table
1284
+ # Reset columns/indexes cache as we're changing the table
1285
+ @columns = @indexes = nil
1286
+
1287
+ Person.connection.change_table(:delete_me, bulk: true) do |t|
1288
+ yield t
1289
+ end
1290
+ end
1291
+
1292
+ def column(name)
1293
+ columns.detect { |c| c.name == name.to_s }
1294
+ end
1295
+
1296
+ def columns
1297
+ @columns ||= Person.connection.columns("delete_me")
1298
+ end
1299
+
1300
+ def index(name)
1301
+ indexes.detect { |i| i.name == name.to_s }
1302
+ end
1303
+
1304
+ def indexes
1305
+ @indexes ||= Person.connection.indexes("delete_me")
1306
+ end
1307
+ end # AlterTableMigrationsTest
1308
+ end
1309
+
1310
+ class CopyMigrationsTest < ActiveRecord::TestCase
1311
+ include ActiveSupport::Testing::Stream
1312
+
1313
+ def setup
1314
+ end
1315
+
1316
+ def clear
1317
+ ActiveRecord::Base.timestamped_migrations = true
1318
+ to_delete = Dir[@migrations_path + "/*.rb"] - @existing_migrations
1319
+ File.delete(*to_delete)
1320
+ end
1321
+
1322
+ def test_copying_migrations_without_timestamps
1323
+ ActiveRecord::Base.timestamped_migrations = false
1324
+ @migrations_path = MIGRATIONS_ROOT + "/valid"
1325
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
1326
+
1327
+ copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/to_copy")
1328
+ assert File.exist?(@migrations_path + "/4_people_have_hobbies.bukkits.rb")
1329
+ assert File.exist?(@migrations_path + "/5_people_have_descriptions.bukkits.rb")
1330
+ assert_equal [@migrations_path + "/4_people_have_hobbies.bukkits.rb", @migrations_path + "/5_people_have_descriptions.bukkits.rb"], copied.map(&:filename)
1331
+
1332
+ expected = "# This migration comes from bukkits (originally 1)"
1333
+ assert_equal expected, IO.readlines(@migrations_path + "/4_people_have_hobbies.bukkits.rb")[1].chomp
1334
+
1335
+ files_count = Dir[@migrations_path + "/*.rb"].length
1336
+ copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/to_copy")
1337
+ assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
1338
+ assert_empty copied
1339
+ ensure
1340
+ clear
1341
+ end
1342
+
1343
+ def test_copying_migrations_without_timestamps_from_2_sources
1344
+ ActiveRecord::Base.timestamped_migrations = false
1345
+ @migrations_path = MIGRATIONS_ROOT + "/valid"
1346
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
1347
+
1348
+ sources = {}
1349
+ sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy"
1350
+ sources[:omg] = MIGRATIONS_ROOT + "/to_copy2"
1351
+ ActiveRecord::Migration.copy(@migrations_path, sources)
1352
+ assert File.exist?(@migrations_path + "/4_people_have_hobbies.bukkits.rb")
1353
+ assert File.exist?(@migrations_path + "/5_people_have_descriptions.bukkits.rb")
1354
+ assert File.exist?(@migrations_path + "/6_create_articles.omg.rb")
1355
+ assert File.exist?(@migrations_path + "/7_create_comments.omg.rb")
1356
+
1357
+ files_count = Dir[@migrations_path + "/*.rb"].length
1358
+ ActiveRecord::Migration.copy(@migrations_path, sources)
1359
+ assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
1360
+ ensure
1361
+ clear
1362
+ end
1363
+
1364
+ def test_copying_migrations_with_timestamps
1365
+ @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
1366
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
1367
+
1368
+ travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
1369
+ copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/to_copy_with_timestamps")
1370
+ assert File.exist?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
1371
+ assert File.exist?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
1372
+ expected = [@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb",
1373
+ @migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb"]
1374
+ assert_equal expected, copied.map(&:filename)
1375
+
1376
+ files_count = Dir[@migrations_path + "/*.rb"].length
1377
+ copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/to_copy_with_timestamps")
1378
+ assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
1379
+ assert_empty copied
1380
+ end
1381
+ ensure
1382
+ clear
1383
+ end
1384
+
1385
+ def test_copying_migrations_with_timestamps_from_2_sources
1386
+ @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
1387
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
1388
+
1389
+ sources = {}
1390
+ sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
1391
+ sources[:omg] = MIGRATIONS_ROOT + "/to_copy_with_timestamps2"
1392
+
1393
+ travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
1394
+ copied = ActiveRecord::Migration.copy(@migrations_path, sources)
1395
+ assert File.exist?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
1396
+ assert File.exist?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
1397
+ assert File.exist?(@migrations_path + "/20100726101012_create_articles.omg.rb")
1398
+ assert File.exist?(@migrations_path + "/20100726101013_create_comments.omg.rb")
1399
+ assert_equal 4, copied.length
1400
+
1401
+ files_count = Dir[@migrations_path + "/*.rb"].length
1402
+ ActiveRecord::Migration.copy(@migrations_path, sources)
1403
+ assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
1404
+ end
1405
+ ensure
1406
+ clear
1407
+ end
1408
+
1409
+ def test_copying_migrations_with_timestamps_to_destination_with_timestamps_in_future
1410
+ @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
1411
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
1412
+
1413
+ travel_to(Time.utc(2010, 2, 20, 10, 10, 10)) do
1414
+ ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/to_copy_with_timestamps")
1415
+ assert File.exist?(@migrations_path + "/20100301010102_people_have_hobbies.bukkits.rb")
1416
+ assert File.exist?(@migrations_path + "/20100301010103_people_have_descriptions.bukkits.rb")
1417
+
1418
+ files_count = Dir[@migrations_path + "/*.rb"].length
1419
+ copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/to_copy_with_timestamps")
1420
+ assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
1421
+ assert_empty copied
1422
+ end
1423
+ ensure
1424
+ clear
1425
+ end
1426
+
1427
+ def test_copying_migrations_preserving_magic_comments
1428
+ ActiveRecord::Base.timestamped_migrations = false
1429
+ @migrations_path = MIGRATIONS_ROOT + "/valid"
1430
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
1431
+
1432
+ copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/magic")
1433
+ assert File.exist?(@migrations_path + "/4_currencies_have_symbols.bukkits.rb")
1434
+ assert_equal [@migrations_path + "/4_currencies_have_symbols.bukkits.rb"], copied.map(&:filename)
1435
+
1436
+ expected = "# frozen_string_literal: true\n# coding: ISO-8859-15\n# This migration comes from bukkits (originally 1)"
1437
+ assert_equal expected, IO.readlines(@migrations_path + "/4_currencies_have_symbols.bukkits.rb")[0..2].join.chomp
1438
+
1439
+ files_count = Dir[@migrations_path + "/*.rb"].length
1440
+ copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/magic")
1441
+ assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
1442
+ assert_empty copied
1443
+ ensure
1444
+ clear
1445
+ end
1446
+
1447
+ def test_skipping_migrations
1448
+ @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
1449
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
1450
+
1451
+ sources = {}
1452
+ sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
1453
+ sources[:omg] = MIGRATIONS_ROOT + "/to_copy_with_name_collision"
1454
+
1455
+ skipped = []
1456
+ on_skip = Proc.new { |name, migration| skipped << "#{name} #{migration.name}" }
1457
+ copied = ActiveRecord::Migration.copy(@migrations_path, sources, on_skip: on_skip)
1458
+ assert_equal 2, copied.length
1459
+
1460
+ assert_equal 1, skipped.length
1461
+ assert_equal ["omg PeopleHaveHobbies"], skipped
1462
+ ensure
1463
+ clear
1464
+ end
1465
+
1466
+ def test_skip_is_not_called_if_migrations_are_from_the_same_plugin
1467
+ @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
1468
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
1469
+
1470
+ sources = {}
1471
+ sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
1472
+
1473
+ skipped = []
1474
+ on_skip = Proc.new { |name, migration| skipped << "#{name} #{migration.name}" }
1475
+ copied = ActiveRecord::Migration.copy(@migrations_path, sources, on_skip: on_skip)
1476
+ ActiveRecord::Migration.copy(@migrations_path, sources, on_skip: on_skip)
1477
+
1478
+ assert_equal 2, copied.length
1479
+ assert_equal 0, skipped.length
1480
+ ensure
1481
+ clear
1482
+ end
1483
+
1484
+ def test_copying_migrations_to_non_existing_directory
1485
+ @migrations_path = MIGRATIONS_ROOT + "/non_existing"
1486
+ @existing_migrations = []
1487
+
1488
+ travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
1489
+ copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/to_copy_with_timestamps")
1490
+ assert File.exist?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
1491
+ assert File.exist?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
1492
+ assert_equal 2, copied.length
1493
+ end
1494
+ ensure
1495
+ clear
1496
+ Dir.delete(@migrations_path)
1497
+ end
1498
+
1499
+ def test_copying_migrations_to_empty_directory
1500
+ @migrations_path = MIGRATIONS_ROOT + "/empty"
1501
+ @existing_migrations = []
1502
+
1503
+ travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
1504
+ copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/to_copy_with_timestamps")
1505
+ assert File.exist?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
1506
+ assert File.exist?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
1507
+ assert_equal 2, copied.length
1508
+ end
1509
+ ensure
1510
+ clear
1511
+ end
1512
+
1513
+ def test_check_pending_with_stdlib_logger
1514
+ old, ActiveRecord::Base.logger = ActiveRecord::Base.logger, ::Logger.new($stdout)
1515
+ quietly do
1516
+ assert_nothing_raised { ActiveRecord::Migration::CheckPending.new(Proc.new { }).call({}) }
1517
+ end
1518
+ ensure
1519
+ ActiveRecord::Base.logger = old
1520
+ end
1521
+
1522
+ def test_unknown_migration_version_should_raise_an_argument_error
1523
+ assert_raise(ArgumentError) { ActiveRecord::Migration[1.0] }
1524
+ end
1525
+ end