class MigrationTest
Private Class Methods
base_class()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 689 def self.base_class; self; end
name()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 688 def self.name; "Reminder"; end
Public Instance Methods
connection()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 147 def connection Class.new { def create_table; "hi mom!"; end }.new end
create_table()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 149 def create_table; "hi mom!"; end
migrate(x)
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 277 def migrate(x) add_column "people", "last_name", :string raise "Something broke" end
setup()
click to toggle source
Calls superclass method
# File activerecord/test/cases/migration_test.rb, line 34 def setup super %w(reminders people_reminders prefix_reminders_suffix p_things_s).each do |table| Reminder.connection.drop_table(table) rescue nil end Reminder.reset_column_information @verbose_was, ActiveRecord::Migration.verbose = ActiveRecord::Migration.verbose, false ActiveRecord::Base.connection.schema_cache.clear! end
test_add_drop_table_with_prefix_and_suffix()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 473 def test_add_drop_table_with_prefix_and_suffix assert !Reminder.table_exists? ActiveRecord::Base.table_name_prefix = "prefix_" ActiveRecord::Base.table_name_suffix = "_suffix" Reminder.reset_table_name Reminder.reset_sequence_name Reminder.reset_column_information WeNeedReminders.up assert Reminder.create("content" => "hello world", "remind_at" => Time.now) assert_equal "hello world", Reminder.first.content WeNeedReminders.down assert_raise(ActiveRecord::StatementInvalid) { Reminder.first } ensure Reminder.reset_sequence_name end
test_add_table_with_decimals()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 157 def test_add_table_with_decimals Person.connection.drop_table :big_numbers rescue nil assert !BigNumber.table_exists? GiveMeBigNumbers.up BigNumber.reset_column_information assert BigNumber.create( bank_balance: 1586.43, big_bank_balance: BigDecimal("1000234000567.95"), world_population: 6000000000, my_house_population: 3, value_of_e: BigDecimal("2.7182818284590452353602875") ) b = BigNumber.first assert_not_nil b assert_not_nil b.bank_balance assert_not_nil b.big_bank_balance assert_not_nil b.world_population assert_not_nil b.my_house_population assert_not_nil b.value_of_e # TODO: set world_population >= 2**62 to cover 64-bit platforms and test # is_a?(Bignum) assert_kind_of Integer, b.world_population assert_equal 6000000000, b.world_population assert_kind_of Integer, b.my_house_population assert_equal 3, b.my_house_population assert_kind_of BigDecimal, b.bank_balance assert_equal BigDecimal("1586.43"), b.bank_balance assert_kind_of BigDecimal, b.big_bank_balance assert_equal BigDecimal("1000234000567.95"), b.big_bank_balance # This one is fun. The 'value_of_e' field is defined as 'DECIMAL' with # precision/scale explicitly left out. By the SQL standard, numbers # assigned to this field should be truncated but that's seldom respected. if current_adapter?(:PostgreSQLAdapter) # - PostgreSQL changes the SQL spec on columns declared simply as # "decimal" to something more useful: instead of being given a scale # of 0, they take on the compile-time limit for precision and scale, # so the following should succeed unless you have used really wacky # compilation options assert_kind_of BigDecimal, b.value_of_e assert_equal BigDecimal("2.7182818284590452353602875"), b.value_of_e elsif current_adapter?(:SQLite3Adapter) # - SQLite3 stores a float, in violation of SQL assert_kind_of BigDecimal, b.value_of_e assert_in_delta BigDecimal("2.71828182845905"), b.value_of_e, 0.00000000000001 else # - SQL standard is an integer assert_kind_of Integer, b.value_of_e assert_equal 2, b.value_of_e end GiveMeBigNumbers.down assert_raise(ActiveRecord::StatementInvalid) { BigNumber.first } end
test_allows_sqlite3_rollback_on_invalid_column_type()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 530 def test_allows_sqlite3_rollback_on_invalid_column_type Person.connection.create_table :something, force: true do |t| t.column :number, :integer t.column :name, :string t.column :foo, :bar end assert Person.connection.column_exists?(:something, :foo) assert_nothing_raised { Person.connection.remove_column :something, :foo, :bar } assert !Person.connection.column_exists?(:something, :foo) assert Person.connection.column_exists?(:something, :name) assert Person.connection.column_exists?(:something, :number) ensure Person.connection.drop_table :something, if_exists: true end
test_any_migrations()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 109 def test_any_migrations old_path = ActiveRecord::Migrator.migrations_paths ActiveRecord::Migrator.migrations_paths = MIGRATIONS_ROOT + "/valid" assert ActiveRecord::Migrator.any_migrations? ActiveRecord::Migrator.migrations_paths = MIGRATIONS_ROOT + "/empty" assert_not ActiveRecord::Migrator.any_migrations? ensure ActiveRecord::Migrator.migrations_paths = old_path end
test_create_table_with_binary_column()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 490 def test_create_table_with_binary_column assert_nothing_raised { Person.connection.create_table :binary_testings do |t| t.column "data", :binary, null: false end } columns = Person.connection.columns(:binary_testings) data_column = columns.detect { |c| c.name == "data" } assert_nil data_column.default ensure Person.connection.drop_table :binary_testings, if_exists: true end
test_create_table_with_custom_sequence_name()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 547 def test_create_table_with_custom_sequence_name # table name is 29 chars, the standard sequence name will # be 33 chars and should be shortened assert_nothing_raised do begin Person.connection.create_table :table_with_name_thats_just_ok do |t| t.column :foo, :string, null: false end ensure Person.connection.drop_table :table_with_name_thats_just_ok rescue nil end end # should be all good w/ a custom sequence name assert_nothing_raised do begin Person.connection.create_table :table_with_name_thats_just_ok, sequence_name: "suitably_short_seq" do |t| t.column :foo, :string, null: false end Person.connection.execute("select suitably_short_seq.nextval from dual") ensure Person.connection.drop_table :table_with_name_thats_just_ok, sequence_name: "suitably_short_seq" rescue nil end end # confirm the custom sequence got dropped assert_raise(ActiveRecord::StatementInvalid) do Person.connection.execute("select suitably_short_seq.nextval from dual") end end
test_create_table_with_force_true_does_not_drop_nonexisting_table()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 126 def test_create_table_with_force_true_does_not_drop_nonexisting_table # using a copy as we need the drop_table method to # continue to work for the ensure block of the test temp_conn = Person.connection.dup assert_not_equal temp_conn, Person.connection temp_conn.create_table :testings2, force: true do |t| t.column :foo, :string end ensure Person.connection.drop_table :testings2, if_exists: true end
test_create_table_with_query()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 506 def test_create_table_with_query Person.connection.create_table :table_from_query_testings, as: "SELECT id FROM people WHERE id = 1" columns = Person.connection.columns(:table_from_query_testings) assert_equal [1], Person.connection.select_values("SELECT * FROM table_from_query_testings") assert_equal 1, columns.length assert_equal "id", columns.first.name ensure Person.connection.drop_table :table_from_query_testings rescue nil end
test_create_table_with_query_from_relation()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 517 def test_create_table_with_query_from_relation Person.connection.create_table :table_from_query_testings, as: Person.select(:id).where(id: 1) columns = Person.connection.columns(:table_from_query_testings) assert_equal [1], Person.connection.select_values("SELECT * FROM table_from_query_testings") assert_equal 1, columns.length assert_equal "id", columns.first.name ensure Person.connection.drop_table :table_from_query_testings rescue nil end
test_filtering_migrations()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 217 def test_filtering_migrations assert_no_column Person, :last_name assert !Reminder.table_exists? name_filter = lambda { |migration| migration.name == "ValidPeopleHaveLastNames" } ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", &name_filter) assert_column Person, :last_name assert_raise(ActiveRecord::StatementInvalid) { Reminder.first } ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", &name_filter) assert_no_column Person, :last_name assert_raise(ActiveRecord::StatementInvalid) { Reminder.first } end
test_generate_migrator_advisory_lock_id()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 624 def test_generate_migrator_advisory_lock_id # It is important we are consistent with how we generate this so that # exclusive locking works across migrator versions migration = Class.new(ActiveRecord::Migration::Current).new migrator = ActiveRecord::Migrator.new(:up, [migration], 100) lock_id = migrator.send(:generate_migrator_advisory_lock_id) current_database = ActiveRecord::Base.connection.current_database salt = ActiveRecord::Migrator::MIGRATOR_SALT expected_id = Zlib.crc32(current_database) * salt assert lock_id == expected_id, "expected lock id generated by the migrator to be #{expected_id}, but it was #{lock_id} instead" assert lock_id.bit_length <= 63, "lock id must be a signed integer of max 63 bits magnitude" end
test_instance_based_migration_down()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 261 def test_instance_based_migration_down migration = MockMigration.new assert !migration.went_up, "have not gone up" assert !migration.went_down, "have not gone down" migration.migrate :down assert !migration.went_up, "have gone up" assert migration.went_down, "have not gone down" end
test_instance_based_migration_up()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 251 def test_instance_based_migration_up migration = MockMigration.new assert !migration.went_up, "have not gone up" assert !migration.went_down, "have not gone down" migration.migrate :up assert migration.went_up, "have gone up" assert !migration.went_down, "have not gone down" end
test_internal_metadata_stores_environment()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 381 def test_internal_metadata_stores_environment current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call migrations_path = MIGRATIONS_ROOT + "/valid" old_path = ActiveRecord::Migrator.migrations_paths ActiveRecord::Migrator.migrations_paths = migrations_path ActiveRecord::Migrator.up(migrations_path) assert_equal current_env, ActiveRecord::InternalMetadata[:environment] original_quails_env = ENV["RAILS_ENV"] original_rack_env = ENV["RACK_ENV"] ENV["RAILS_ENV"] = ENV["RACK_ENV"] = "foofoo" new_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call refute_equal current_env, new_env sleep 1 # mysql by default does not store fractional seconds in the database ActiveRecord::Migrator.up(migrations_path) assert_equal new_env, ActiveRecord::InternalMetadata[:environment] ensure ActiveRecord::Migrator.migrations_paths = old_path ENV["RAILS_ENV"] = original_quails_env ENV["RACK_ENV"] = original_rack_env ActiveRecord::Migrator.up(migrations_path) end
test_internal_metadata_stores_environment_when_other_data_exists()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 407 def test_internal_metadata_stores_environment_when_other_data_exists ActiveRecord::InternalMetadata.delete_all ActiveRecord::InternalMetadata[:foo] = "bar" current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call migrations_path = MIGRATIONS_ROOT + "/valid" old_path = ActiveRecord::Migrator.migrations_paths ActiveRecord::Migrator.migrations_paths = migrations_path current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call ActiveRecord::Migrator.up(migrations_path) assert_equal current_env, ActiveRecord::InternalMetadata[:environment] assert_equal "bar", ActiveRecord::InternalMetadata[:foo] ensure ActiveRecord::Migrator.migrations_paths = old_path end
test_internal_metadata_table_name()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 361 def test_internal_metadata_table_name original_internal_metadata_table_name = ActiveRecord::Base.internal_metadata_table_name assert_equal "ar_internal_metadata", ActiveRecord::InternalMetadata.table_name ActiveRecord::Base.table_name_prefix = "p_" ActiveRecord::Base.table_name_suffix = "_s" Reminder.reset_table_name assert_equal "p_ar_internal_metadata_s", ActiveRecord::InternalMetadata.table_name ActiveRecord::Base.internal_metadata_table_name = "changed" Reminder.reset_table_name assert_equal "p_changed_s", ActiveRecord::InternalMetadata.table_name ActiveRecord::Base.table_name_prefix = "" ActiveRecord::Base.table_name_suffix = "" Reminder.reset_table_name assert_equal "changed", ActiveRecord::InternalMetadata.table_name ensure ActiveRecord::Base.internal_metadata_table_name = original_internal_metadata_table_name Reminder.reset_table_name end
test_method_missing_delegates_to_connection()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 145 def test_method_missing_delegates_to_connection migration = Class.new(ActiveRecord::Migration::Current) { def connection Class.new { def create_table; "hi mom!"; end }.new end }.new assert_equal "hi mom!", migration.method_missing(:create_table) end
test_migration_detection_without_schema_migration_table()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 97 def test_migration_detection_without_schema_migration_table ActiveRecord::Base.connection.drop_table "schema_migrations", if_exists: true migrations_path = MIGRATIONS_ROOT + "/valid" old_path = ActiveRecord::Migrator.migrations_paths ActiveRecord::Migrator.migrations_paths = migrations_path assert_equal true, ActiveRecord::Migrator.needs_migration? ensure ActiveRecord::Migrator.migrations_paths = old_path end
test_migration_instance_has_connection()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 140 def test_migration_instance_has_connection migration = Class.new(ActiveRecord::Migration::Current).new assert_equal ActiveRecord::Base.connection, migration.connection end
test_migration_version()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 122 def test_migration_version assert_nothing_raised { ActiveRecord::Migrator.run(:up, MIGRATIONS_ROOT + "/version_check", 20131219224947) } end
test_migration_version_matches_component_version()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 74 def test_migration_version_matches_component_version assert_equal ActiveRecord::VERSION::STRING.to_f, ActiveRecord::Migration.current_version end
test_migration_without_transaction()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 314 def test_migration_without_transaction assert_no_column Person, :last_name migration = Class.new(ActiveRecord::Migration::Current) { disable_ddl_transaction! def version; 101 end def migrate(x) add_column "people", "last_name", :string raise "Something broke" end }.new migrator = ActiveRecord::Migrator.new(:up, [migration], 101) e = assert_raise(StandardError) { migrator.migrate } assert_equal "An error has occurred, all later migrations canceled:\n\nSomething broke", e.message assert_column Person, :last_name, "without ddl transactions, the Migrator should not rollback on error but it did." ensure Person.reset_column_information if Person.column_names.include?("last_name") Person.connection.remove_column("people", "last_name") end end
test_migrator_generates_valid_lock_id()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 612 def test_migrator_generates_valid_lock_id migration = Class.new(ActiveRecord::Migration::Current).new migrator = ActiveRecord::Migrator.new(:up, [migration], 100) lock_id = migrator.send(:generate_migrator_advisory_lock_id) assert ActiveRecord::Base.connection.get_advisory_lock(lock_id), "the Migrator should have generated a valid lock id, but it didn't" assert ActiveRecord::Base.connection.release_advisory_lock(lock_id), "the Migrator should have generated a valid lock id, but it didn't" end
test_migrator_one_up_with_exception_and_rollback()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 272 def test_migrator_one_up_with_exception_and_rollback assert_no_column Person, :last_name migration = Class.new(ActiveRecord::Migration::Current) { def version; 100 end def migrate(x) add_column "people", "last_name", :string raise "Something broke" end }.new migrator = ActiveRecord::Migrator.new(:up, [migration], 100) e = assert_raise(StandardError) { migrator.migrate } assert_equal "An error has occurred, this and all later migrations canceled:\n\nSomething broke", e.message assert_no_column Person, :last_name, "On error, the Migrator should revert schema changes but it did not." end
test_migrator_one_up_with_exception_and_rollback_using_run()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 293 def test_migrator_one_up_with_exception_and_rollback_using_run assert_no_column Person, :last_name migration = Class.new(ActiveRecord::Migration::Current) { def version; 100 end def migrate(x) add_column "people", "last_name", :string raise "Something broke" end }.new migrator = ActiveRecord::Migrator.new(:up, [migration], 100) e = assert_raise(StandardError) { migrator.run } assert_equal "An error has occurred, this and all later migrations canceled:\n\nSomething broke", e.message assert_no_column Person, :last_name, "On error, the Migrator should revert schema changes but it did not." end
test_migrator_versions()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 78 def test_migrator_versions migrations_path = MIGRATIONS_ROOT + "/valid" old_path = ActiveRecord::Migrator.migrations_paths ActiveRecord::Migrator.migrations_paths = migrations_path ActiveRecord::Migrator.up(migrations_path) assert_equal 3, ActiveRecord::Migrator.current_version assert_equal false, ActiveRecord::Migrator.needs_migration? ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid") assert_equal 0, ActiveRecord::Migrator.current_version assert_equal true, ActiveRecord::Migrator.needs_migration? ActiveRecord::SchemaMigration.create!(version: 3) assert_equal true, ActiveRecord::Migrator.needs_migration? ensure ActiveRecord::Migrator.migrations_paths = old_path end
test_out_of_range_integer_limit_should_raise()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 584 def test_out_of_range_integer_limit_should_raise e = assert_raise(ActiveRecord::ActiveRecordError, "integer limit didn't raise") do Person.connection.create_table :test_integer_limits, force: true do |t| t.column :bigone, :integer, limit: 10 end end assert_match(/No integer type has byte size 10/, e.message) ensure Person.connection.drop_table :test_integer_limits, if_exists: true end
test_out_of_range_text_limit_should_raise()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 598 def test_out_of_range_text_limit_should_raise e = assert_raise(ActiveRecord::ActiveRecordError, "text limit didn't raise") do Person.connection.create_table :test_text_limits, force: true do |t| t.text :bigtext, limit: 0xfffffffff end end assert_match(/No text type has byte length #{0xfffffffff}/, e.message) ensure Person.connection.drop_table :test_text_limits, if_exists: true end
test_proper_table_name_on_migration()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 424 def test_proper_table_name_on_migration reminder_class = new_isolated_reminder_class migration = ActiveRecord::Migration.new assert_equal "table", migration.proper_table_name("table") assert_equal "table", migration.proper_table_name(:table) assert_equal "reminders", migration.proper_table_name(reminder_class) reminder_class.reset_table_name assert_equal reminder_class.table_name, migration.proper_table_name(reminder_class) # Use the model's own prefix/suffix if a model is given ActiveRecord::Base.table_name_prefix = "ARprefix_" ActiveRecord::Base.table_name_suffix = "_ARsuffix" reminder_class.table_name_prefix = "prefix_" reminder_class.table_name_suffix = "_suffix" reminder_class.reset_table_name assert_equal "prefix_reminders_suffix", migration.proper_table_name(reminder_class) reminder_class.table_name_prefix = "" reminder_class.table_name_suffix = "" reminder_class.reset_table_name # Use AR::Base's prefix/suffix if string or symbol is given ActiveRecord::Base.table_name_prefix = "prefix_" ActiveRecord::Base.table_name_suffix = "_suffix" reminder_class.reset_table_name assert_equal "prefix_table_suffix", migration.proper_table_name("table", migration.table_name_options) assert_equal "prefix_table_suffix", migration.proper_table_name(:table, migration.table_name_options) end
test_rename_table_with_prefix_and_suffix()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 452 def test_rename_table_with_prefix_and_suffix assert !Thing.table_exists? ActiveRecord::Base.table_name_prefix = "p_" ActiveRecord::Base.table_name_suffix = "_s" Thing.reset_table_name Thing.reset_sequence_name WeNeedThings.up Thing.reset_column_information assert Thing.create("content" => "hello world") assert_equal "hello world", Thing.first.content RenameThings.up Thing.table_name = "p_awesome_things_s" assert_equal "hello world", Thing.first.content ensure Thing.reset_table_name Thing.reset_sequence_name end
test_schema_migrations_table_name()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 341 def test_schema_migrations_table_name original_schema_migrations_table_name = ActiveRecord::Base.schema_migrations_table_name assert_equal "schema_migrations", ActiveRecord::SchemaMigration.table_name ActiveRecord::Base.table_name_prefix = "prefix_" ActiveRecord::Base.table_name_suffix = "_suffix" Reminder.reset_table_name assert_equal "prefix_schema_migrations_suffix", ActiveRecord::SchemaMigration.table_name ActiveRecord::Base.schema_migrations_table_name = "changed" Reminder.reset_table_name assert_equal "prefix_changed_suffix", ActiveRecord::SchemaMigration.table_name ActiveRecord::Base.table_name_prefix = "" ActiveRecord::Base.table_name_suffix = "" Reminder.reset_table_name assert_equal "changed", ActiveRecord::SchemaMigration.table_name ensure ActiveRecord::Base.schema_migrations_table_name = original_schema_migrations_table_name Reminder.reset_table_name end
version()
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 276 def version; 100 end
Private Instance Methods
new_isolated_reminder_class()
click to toggle source
This is needed to isolate class_attribute assignments like `table_name_prefix` for each test case.
# File activerecord/test/cases/migration_test.rb, line 686 def new_isolated_reminder_class Class.new(Reminder) { def self.name; "Reminder"; end def self.base_class; self; end } end
with_another_process_holding_lock(lock_id) { || ... }
click to toggle source
# File activerecord/test/cases/migration_test.rb, line 693 def with_another_process_holding_lock(lock_id) thread_lock = Concurrent::CountDownLatch.new test_terminated = Concurrent::CountDownLatch.new other_process = Thread.new do begin conn = ActiveRecord::Base.connection_pool.checkout conn.get_advisory_lock(lock_id) thread_lock.count_down test_terminated.wait # hold the lock open until we tested everything ensure conn.release_advisory_lock(lock_id) ActiveRecord::Base.connection_pool.checkin(conn) end end thread_lock.wait # wait until the 'other process' has the lock yield test_terminated.count_down other_process.join end