1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00
rails--rails/railties/test/application/rake/migrations_test.rb

460 lines
17 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
require "isolation/abstract_unit"
module ApplicationTests
module RakeTests
2012-01-05 20:30:17 -05:00
class RakeMigrationsTest < ActiveSupport::TestCase
def setup
build_app
FileUtils.rm_rf("#{app_path}/config/environments")
end
def teardown
teardown_app
end
test "running migrations with given scope" do
rails "generate", "model", "user", "username:string", "password:string"
app_file "db/migrate/01_a_migration.bukkits.rb", <<-MIGRATION
class AMigration < ActiveRecord::Migration::Current
end
MIGRATION
output = rails("db:migrate", "SCOPE=bukkits")
assert_no_match(/create_table\(:users\)/, output)
assert_no_match(/CreateUsers/, output)
assert_no_match(/add_column\(:users, :email, :string\)/, output)
assert_match(/AMigration: migrated/, output)
# run all the migrations to test scope for down
output = rails("db:migrate")
assert_match(/CreateUsers: migrated/, output)
output = rails("db:migrate", "SCOPE=bukkits", "VERSION=0")
assert_no_match(/drop_table\(:users\)/, output)
assert_no_match(/CreateUsers/, output)
assert_no_match(/remove_column\(:users, :email\)/, output)
assert_match(/AMigration: reverted/, output)
output = rails("db:migrate", "VERSION=0")
assert_match(/CreateUsers: reverted/, output)
end
2011-12-09 15:19:49 -05:00
Refactor migration to move migrations paths to connection Rails has some support for multiple databases but it can be hard to handle migrations with those. The easiest way to implement multiple databases is to contain migrations into their own folder ("db/migrate" for the primary db and "db/seconddb_migrate" for the second db). Without this you would need to write code that allowed you to switch connections in migrations. I can tell you from experience that is not a fun way to implement multiple databases. This refactoring is a pre-requisite for implementing other features related to parallel testing and improved handling for multiple databases. The refactoring here moves the class methods from the `Migrator` class into it's own new class `MigrationContext`. The goal was to move the `migrations_paths` method off of the `Migrator` class and onto the connection. This allows users to do the following in their `database.yml`: ``` development: adapter: mysql2 username: root password: development_seconddb: adapter: mysql2 username: root password: migrations_paths: "db/second_db_migrate" ``` Migrations for the `seconddb` can now be store in the `db/second_db_migrate` directory. Migrations for the primary database are stored in `db/migrate`". The refactoring here drastically reduces the internal API for migrations since we don't need to pass `migrations_paths` around to every single method. Additionally this change does not require any Rails applications to make changes unless they want to use the new public API. All of the class methods from the `Migrator` class were `nodoc`'d except for the `migrations_paths` and `migrations_path` getter/setters respectively.
2018-01-10 10:25:13 -05:00
test "version outputs current version" do
app_file "db/migrate/01_one_migration.rb", <<-MIGRATION
class OneMigration < ActiveRecord::Migration::Current
end
MIGRATION
rails "db:migrate"
output = rails("db:version")
assert_match(/Current version: 1/, output)
end
test "migrate with specified VERSION in different formats" do
app_file "db/migrate/01_one_migration.rb", <<-MIGRATION
class OneMigration < ActiveRecord::Migration::Current
end
MIGRATION
app_file "db/migrate/02_two_migration.rb", <<-MIGRATION
class TwoMigration < ActiveRecord::Migration::Current
end
MIGRATION
app_file "db/migrate/03_three_migration.rb", <<-MIGRATION
class ThreeMigration < ActiveRecord::Migration::Current
end
MIGRATION
rails "db:migrate"
output = rails("db:migrate:status")
assert_match(/up\s+001\s+One migration/, output)
assert_match(/up\s+002\s+Two migration/, output)
assert_match(/up\s+003\s+Three migration/, output)
rails "db:migrate", "VERSION=01_one_migration.rb"
output = rails("db:migrate:status")
assert_match(/up\s+001\s+One migration/, output)
assert_match(/down\s+002\s+Two migration/, output)
assert_match(/down\s+003\s+Three migration/, output)
rails "db:migrate", "VERSION=3"
output = rails("db:migrate:status")
assert_match(/up\s+001\s+One migration/, output)
assert_match(/up\s+002\s+Two migration/, output)
assert_match(/up\s+003\s+Three migration/, output)
rails "db:migrate", "VERSION=001"
output = rails("db:migrate:status")
assert_match(/up\s+001\s+One migration/, output)
assert_match(/down\s+002\s+Two migration/, output)
assert_match(/down\s+003\s+Three migration/, output)
end
test "migration with empty version" do
app_file "db/migrate/01_one_migration.rb", <<-MIGRATION
class OneMigration < ActiveRecord::Migration::Current
end
MIGRATION
app_file "db/migrate/02_two_migration.rb", <<-MIGRATION
class TwoMigration < ActiveRecord::Migration::Current
end
MIGRATION
rails("db:migrate", "VERSION=")
output = rails("db:migrate:status")
assert_match(/up\s+001\s+One migration/, output)
assert_match(/up\s+002\s+Two migration/, output)
output = rails("db:migrate:redo", "VERSION=", allow_failure: true)
assert_match(/Empty VERSION provided/, output)
output = rails("db:migrate:up", "VERSION=", allow_failure: true)
assert_match(/VERSION is required/, output)
output = rails("db:migrate:up", allow_failure: true)
assert_match(/VERSION is required/, output)
output = rails("db:migrate:down", "VERSION=", allow_failure: true)
assert_match(/VERSION is required - To go down one migration, use db:rollback/, output)
output = rails("db:migrate:down", allow_failure: true)
assert_match(/VERSION is required - To go down one migration, use db:rollback/, output)
output = rails("db:migrate:status")
assert_match(/up\s+001\s+One migration/, output)
assert_match(/up\s+002\s+Two migration/, output)
end
test "migration with 0 version" do
app_file "db/migrate/01_one_migration.rb", <<-MIGRATION
class OneMigration < ActiveRecord::Migration::Current
end
MIGRATION
app_file "db/migrate/02_two_migration.rb", <<-MIGRATION
class TwoMigration < ActiveRecord::Migration::Current
end
MIGRATION
rails "db:migrate"
output = rails("db:migrate:status")
assert_match(/up\s+001\s+One migration/, output)
assert_match(/up\s+002\s+Two migration/, output)
rails "db:migrate", "VERSION=0"
output = rails("db:migrate:status")
assert_match(/down\s+001\s+One migration/, output)
assert_match(/down\s+002\s+Two migration/, output)
end
test "model and migration generator with change syntax" do
rails "generate", "model", "user", "username:string", "password:string"
rails "generate", "migration", "add_email_to_users", "email:string"
output = rails("db:migrate")
assert_match(/create_table\(:users\)/, output)
assert_match(/CreateUsers: migrated/, output)
assert_match(/add_column\(:users, :email, :string\)/, output)
assert_match(/AddEmailToUsers: migrated/, output)
output = rails("db:rollback", "STEP=2")
assert_match(/drop_table\(:users\)/, output)
assert_match(/CreateUsers: reverted/, output)
assert_match(/remove_column\(:users, :email, :string\)/, output)
assert_match(/AddEmailToUsers: reverted/, output)
2011-12-09 15:19:49 -05:00
end
test "migration status when schema migrations table is not present" do
output = rails("db:migrate:status", allow_failure: true)
2011-12-09 15:19:49 -05:00
assert_equal "Schema migrations table does not exist yet.\n", output
end
2017-04-06 19:40:52 -04:00
test "migration status" do
rails "generate", "model", "user", "username:string", "password:string"
rails "generate", "migration", "add_email_to_users", "email:string"
rails "db:migrate"
2011-12-09 15:19:49 -05:00
output = rails("db:migrate:status")
2011-12-09 15:19:49 -05:00
assert_match(/up\s+\d{14}\s+Create users/, output)
assert_match(/up\s+\d{14}\s+Add email to users/, output)
2011-12-09 15:19:49 -05:00
rails "db:rollback", "STEP=1"
output = rails("db:migrate:status")
2011-12-09 15:19:49 -05:00
assert_match(/up\s+\d{14}\s+Create users/, output)
assert_match(/down\s+\d{14}\s+Add email to users/, output)
2011-12-09 15:19:49 -05:00
end
test "migration status without timestamps" do
add_to_config("config.active_record.timestamped_migrations = false")
rails "generate", "model", "user", "username:string", "password:string"
rails "generate", "migration", "add_email_to_users", "email:string"
rails "db:migrate"
output = rails("db:migrate:status")
assert_match(/up\s+\d{3,}\s+Create users/, output)
assert_match(/up\s+\d{3,}\s+Add email to users/, output)
rails "db:rollback", "STEP=1"
output = rails("db:migrate:status")
assert_match(/up\s+\d{3,}\s+Create users/, output)
assert_match(/down\s+\d{3,}\s+Add email to users/, output)
end
2017-04-06 19:40:52 -04:00
test "migration status after rollback and redo" do
rails "generate", "model", "user", "username:string", "password:string"
rails "generate", "migration", "add_email_to_users", "email:string"
rails "db:migrate"
2011-12-09 15:19:49 -05:00
output = rails("db:migrate:status")
2011-12-09 15:19:49 -05:00
assert_match(/up\s+\d{14}\s+Create users/, output)
assert_match(/up\s+\d{14}\s+Add email to users/, output)
2011-12-09 15:19:49 -05:00
rails "db:rollback", "STEP=2"
output = rails("db:migrate:status")
2011-12-09 15:19:49 -05:00
assert_match(/down\s+\d{14}\s+Create users/, output)
assert_match(/down\s+\d{14}\s+Add email to users/, output)
2011-12-09 15:19:49 -05:00
rails "db:migrate:redo"
output = rails("db:migrate:status")
2011-12-09 15:19:49 -05:00
assert_match(/up\s+\d{14}\s+Create users/, output)
assert_match(/up\s+\d{14}\s+Add email to users/, output)
2011-12-09 15:19:49 -05:00
end
test "migration status after rollback and forward" do
rails "generate", "model", "user", "username:string", "password:string"
rails "generate", "migration", "add_email_to_users", "email:string"
rails "db:migrate"
output = rails("db:migrate:status")
assert_match(/up\s+\d{14}\s+Create users/, output)
assert_match(/up\s+\d{14}\s+Add email to users/, output)
rails "db:rollback", "STEP=2"
output = rails("db:migrate:status")
assert_match(/down\s+\d{14}\s+Create users/, output)
assert_match(/down\s+\d{14}\s+Add email to users/, output)
rails "db:forward", "STEP=2"
output = rails("db:migrate:status")
assert_match(/up\s+\d{14}\s+Create users/, output)
assert_match(/up\s+\d{14}\s+Add email to users/, output)
end
test "raise error on any move when current migration does not exist" do
Dir.chdir(app_path) do
rails "generate", "model", "user", "username:string", "password:string"
rails "generate", "migration", "add_email_to_users", "email:string"
rails "db:migrate"
`rm db/migrate/*email*.rb`
output = rails("db:migrate:status")
assert_match(/up\s+\d{14}\s+Create users/, output)
assert_match(/up\s+\d{14}\s+\** NO FILE \**/, output)
output = rails("db:rollback", allow_failure: true)
assert_match(/rails aborted!/, output)
assert_match(/ActiveRecord::UnknownMigrationVersionError:/, output)
assert_match(/No migration with version number\s\d{14}\./, output)
output = rails("db:migrate:status")
assert_match(/up\s+\d{14}\s+Create users/, output)
assert_match(/up\s+\d{14}\s+\** NO FILE \**/, output)
output = rails("db:forward", allow_failure: true)
assert_match(/rails aborted!/, output)
assert_match(/ActiveRecord::UnknownMigrationVersionError:/, output)
assert_match(/No migration with version number\s\d{14}\./, output)
output = rails("db:migrate:status")
assert_match(/up\s+\d{14}\s+Create users/, output)
assert_match(/up\s+\d{14}\s+\** NO FILE \**/, output)
end
end
test "raise error on any move when target migration does not exist" do
app_file "db/migrate/01_one_migration.rb", <<-MIGRATION
class OneMigration < ActiveRecord::Migration::Current
end
MIGRATION
app_file "db/migrate/02_two_migration.rb", <<-MIGRATION
class TwoMigration < ActiveRecord::Migration::Current
end
MIGRATION
rails "db:migrate"
output = rails("db:migrate:status")
assert_match(/up\s+001\s+One migration/, output)
assert_match(/up\s+002\s+Two migration/, output)
output = rails("db:migrate", "VERSION=3", allow_failure: true)
assert_match(/rails aborted!/, output)
assert_match(/ActiveRecord::UnknownMigrationVersionError:/, output)
assert_match(/No migration with version number 3/, output)
output = rails("db:migrate:status")
assert_match(/up\s+001\s+One migration/, output)
assert_match(/up\s+002\s+Two migration/, output)
end
test "raise error on any move when VERSION has invalid format" do
output = rails("db:migrate", "VERSION=unknown", allow_failure: true)
assert_match(/rails aborted!/, output)
assert_match(/Invalid format of target version/, output)
output = rails("db:migrate", "VERSION=0.1.11", allow_failure: true)
assert_match(/rails aborted!/, output)
assert_match(/Invalid format of target version/, output)
output = rails("db:migrate", "VERSION=1.1.11", allow_failure: true)
assert_match(/rails aborted!/, output)
assert_match(/Invalid format of target version/, output)
output = rails("db:migrate", "VERSION='0 '", allow_failure: true)
assert_match(/rails aborted!/, output)
assert_match(/Invalid format of target version/, output)
output = rails("db:migrate", "VERSION=1.", allow_failure: true)
assert_match(/rails aborted!/, output)
assert_match(/Invalid format of target version/, output)
output = rails("db:migrate", "VERSION=1_", allow_failure: true)
assert_match(/rails aborted!/, output)
assert_match(/Invalid format of target version/, output)
output = rails("db:migrate", "VERSION=1_name", allow_failure: true)
assert_match(/rails aborted!/, output)
assert_match(/Invalid format of target version/, output)
output = rails("db:migrate:redo", "VERSION=unknown", allow_failure: true)
assert_match(/rails aborted!/, output)
assert_match(/Invalid format of target version/, output)
output = rails("db:migrate:up", "VERSION=unknown", allow_failure: true)
assert_match(/rails aborted!/, output)
assert_match(/Invalid format of target version/, output)
output = rails("db:migrate:down", "VERSION=unknown", allow_failure: true)
assert_match(/rails aborted!/, output)
assert_match(/Invalid format of target version/, output)
end
test "migration status after rollback and redo without timestamps" do
add_to_config("config.active_record.timestamped_migrations = false")
rails "generate", "model", "user", "username:string", "password:string"
rails "generate", "migration", "add_email_to_users", "email:string"
rails "db:migrate"
output = rails("db:migrate:status")
assert_match(/up\s+\d{3,}\s+Create users/, output)
assert_match(/up\s+\d{3,}\s+Add email to users/, output)
rails "db:rollback", "STEP=2"
output = rails("db:migrate:status")
assert_match(/down\s+\d{3,}\s+Create users/, output)
assert_match(/down\s+\d{3,}\s+Add email to users/, output)
rails "db:migrate:redo"
output = rails("db:migrate:status")
assert_match(/up\s+\d{3,}\s+Create users/, output)
assert_match(/up\s+\d{3,}\s+Add email to users/, output)
end
test "running migrations with not timestamp head migration files" do
app_file "db/migrate/1_one_migration.rb", <<-MIGRATION
class OneMigration < ActiveRecord::Migration::Current
end
MIGRATION
Make `db:migrate:status` to render `1_some.rb` format migrate files. `1_valid_people_have_last_names.rb` and `20150823202140_create_users.rb` are valid migration file name. But `1_valid_people_have_last_names.rb` is rendered as `********** NO FILE **********` when `rake db:migrate:status`. Fix to this bug, this commit includes * define some API private methdos and a Constant `match_to_migration_filename?`, `parse_migration_filename`, and `MigrationFilenameRegexp` * use these methods in `db:migrate:status` task Example: These files are in `db/migrate` * 1_valid_people_have_last_names.rb * 20150819202140_irreversible_migration.rb * 20150823202140_add_admin_flag_to_users.rb * 20150823202141_migration_tests.rb * 2_we_need_reminders.rb * 3_innocent_jointable.rb we can migrate all of them. Before ```shell $ bundle exec rake db:migrate:status ... Status Migration ID Migration Name -------------------------------------------------- up 001 ********** NO FILE ********** up 002 ********** NO FILE ********** up 003 ********** NO FILE ********** up 20150819202140 Irreversible migration up 20150823202140 Add admin flag to users up 20150823202141 Migration tests ``` After ```shell $ bundle exec rake db:migrate:status ... Status Migration ID Migration Name -------------------------------------------------- up 001 Valid people have last names up 002 We need reminders up 003 Innocent jointable up 20150819202140 Irreversible migration up 20150823202140 Add admin flag to users up 20150823202141 Migration tests ```
2015-10-01 12:21:37 -04:00
app_file "db/migrate/02_two_migration.rb", <<-MIGRATION
class TwoMigration < ActiveRecord::Migration::Current
end
MIGRATION
Make `db:migrate:status` to render `1_some.rb` format migrate files. `1_valid_people_have_last_names.rb` and `20150823202140_create_users.rb` are valid migration file name. But `1_valid_people_have_last_names.rb` is rendered as `********** NO FILE **********` when `rake db:migrate:status`. Fix to this bug, this commit includes * define some API private methdos and a Constant `match_to_migration_filename?`, `parse_migration_filename`, and `MigrationFilenameRegexp` * use these methods in `db:migrate:status` task Example: These files are in `db/migrate` * 1_valid_people_have_last_names.rb * 20150819202140_irreversible_migration.rb * 20150823202140_add_admin_flag_to_users.rb * 20150823202141_migration_tests.rb * 2_we_need_reminders.rb * 3_innocent_jointable.rb we can migrate all of them. Before ```shell $ bundle exec rake db:migrate:status ... Status Migration ID Migration Name -------------------------------------------------- up 001 ********** NO FILE ********** up 002 ********** NO FILE ********** up 003 ********** NO FILE ********** up 20150819202140 Irreversible migration up 20150823202140 Add admin flag to users up 20150823202141 Migration tests ``` After ```shell $ bundle exec rake db:migrate:status ... Status Migration ID Migration Name -------------------------------------------------- up 001 Valid people have last names up 002 We need reminders up 003 Innocent jointable up 20150819202140 Irreversible migration up 20150823202140 Add admin flag to users up 20150823202141 Migration tests ```
2015-10-01 12:21:37 -04:00
rails "db:migrate"
Make `db:migrate:status` to render `1_some.rb` format migrate files. `1_valid_people_have_last_names.rb` and `20150823202140_create_users.rb` are valid migration file name. But `1_valid_people_have_last_names.rb` is rendered as `********** NO FILE **********` when `rake db:migrate:status`. Fix to this bug, this commit includes * define some API private methdos and a Constant `match_to_migration_filename?`, `parse_migration_filename`, and `MigrationFilenameRegexp` * use these methods in `db:migrate:status` task Example: These files are in `db/migrate` * 1_valid_people_have_last_names.rb * 20150819202140_irreversible_migration.rb * 20150823202140_add_admin_flag_to_users.rb * 20150823202141_migration_tests.rb * 2_we_need_reminders.rb * 3_innocent_jointable.rb we can migrate all of them. Before ```shell $ bundle exec rake db:migrate:status ... Status Migration ID Migration Name -------------------------------------------------- up 001 ********** NO FILE ********** up 002 ********** NO FILE ********** up 003 ********** NO FILE ********** up 20150819202140 Irreversible migration up 20150823202140 Add admin flag to users up 20150823202141 Migration tests ``` After ```shell $ bundle exec rake db:migrate:status ... Status Migration ID Migration Name -------------------------------------------------- up 001 Valid people have last names up 002 We need reminders up 003 Innocent jointable up 20150819202140 Irreversible migration up 20150823202140 Add admin flag to users up 20150823202141 Migration tests ```
2015-10-01 12:21:37 -04:00
output = rails("db:migrate:status")
Make `db:migrate:status` to render `1_some.rb` format migrate files. `1_valid_people_have_last_names.rb` and `20150823202140_create_users.rb` are valid migration file name. But `1_valid_people_have_last_names.rb` is rendered as `********** NO FILE **********` when `rake db:migrate:status`. Fix to this bug, this commit includes * define some API private methdos and a Constant `match_to_migration_filename?`, `parse_migration_filename`, and `MigrationFilenameRegexp` * use these methods in `db:migrate:status` task Example: These files are in `db/migrate` * 1_valid_people_have_last_names.rb * 20150819202140_irreversible_migration.rb * 20150823202140_add_admin_flag_to_users.rb * 20150823202141_migration_tests.rb * 2_we_need_reminders.rb * 3_innocent_jointable.rb we can migrate all of them. Before ```shell $ bundle exec rake db:migrate:status ... Status Migration ID Migration Name -------------------------------------------------- up 001 ********** NO FILE ********** up 002 ********** NO FILE ********** up 003 ********** NO FILE ********** up 20150819202140 Irreversible migration up 20150823202140 Add admin flag to users up 20150823202141 Migration tests ``` After ```shell $ bundle exec rake db:migrate:status ... Status Migration ID Migration Name -------------------------------------------------- up 001 Valid people have last names up 002 We need reminders up 003 Innocent jointable up 20150819202140 Irreversible migration up 20150823202140 Add admin flag to users up 20150823202141 Migration tests ```
2015-10-01 12:21:37 -04:00
assert_match(/up\s+001\s+One migration/, output)
assert_match(/up\s+002\s+Two migration/, output)
Make `db:migrate:status` to render `1_some.rb` format migrate files. `1_valid_people_have_last_names.rb` and `20150823202140_create_users.rb` are valid migration file name. But `1_valid_people_have_last_names.rb` is rendered as `********** NO FILE **********` when `rake db:migrate:status`. Fix to this bug, this commit includes * define some API private methdos and a Constant `match_to_migration_filename?`, `parse_migration_filename`, and `MigrationFilenameRegexp` * use these methods in `db:migrate:status` task Example: These files are in `db/migrate` * 1_valid_people_have_last_names.rb * 20150819202140_irreversible_migration.rb * 20150823202140_add_admin_flag_to_users.rb * 20150823202141_migration_tests.rb * 2_we_need_reminders.rb * 3_innocent_jointable.rb we can migrate all of them. Before ```shell $ bundle exec rake db:migrate:status ... Status Migration ID Migration Name -------------------------------------------------- up 001 ********** NO FILE ********** up 002 ********** NO FILE ********** up 003 ********** NO FILE ********** up 20150819202140 Irreversible migration up 20150823202140 Add admin flag to users up 20150823202141 Migration tests ``` After ```shell $ bundle exec rake db:migrate:status ... Status Migration ID Migration Name -------------------------------------------------- up 001 Valid people have last names up 002 We need reminders up 003 Innocent jointable up 20150819202140 Irreversible migration up 20150823202140 Add admin flag to users up 20150823202141 Migration tests ```
2015-10-01 12:21:37 -04:00
end
test "schema generation when dump_schema_after_migration is set" do
add_to_config("config.active_record.dump_schema_after_migration = false")
Dir.chdir(app_path) do
rails "generate", "model", "book", "title:string"
output = rails("generate", "model", "author", "name:string")
version = output =~ %r{[^/]+db/migrate/(\d+)_create_authors\.rb} && $1
rails "db:migrate", "db:rollback", "db:forward", "db:migrate:up", "db:migrate:down", "VERSION=#{version}"
assert_not File.exist?("db/schema.rb"), "should not dump schema when configured not to"
end
add_to_config("config.active_record.dump_schema_after_migration = true")
Dir.chdir(app_path) do
rails "generate", "model", "reviews", "book_id:integer"
rails "db:migrate"
structure_dump = File.read("db/schema.rb")
assert_match(/create_table "reviews"/, structure_dump)
end
end
test "default schema generation after migration" do
Dir.chdir(app_path) do
rails "generate", "model", "book", "title:string"
rails "db:migrate"
structure_dump = File.read("db/schema.rb")
assert_match(/create_table "books"/, structure_dump)
end
end
2017-04-06 19:40:52 -04:00
test "migration status migrated file is deleted" do
Dir.chdir(app_path) do
rails "generate", "model", "user", "username:string", "password:string"
rails "generate", "migration", "add_email_to_users", "email:string"
rails "db:migrate"
`rm db/migrate/*email*.rb`
output = rails("db:migrate:status")
assert_match(/up\s+\d{14}\s+Create users/, output)
assert_match(/up\s+\d{14}\s+\** NO FILE \**/, output)
end
end
end
end
end