未验证 提交 6e74e1d1 编写于 作者: E Eileen M. Uchitelle 提交者: GitHub

Merge pull request #31727 from...

Merge pull request #31727 from eileencodes/refactor-migration-classes-to-allow-for-migrations_paths-on-conn

Refactor migration to move migrations paths to connection
......@@ -1049,8 +1049,8 @@ def assume_migrated_upto_version(version, migrations_paths)
sm_table = quote_table_name(ActiveRecord::SchemaMigration.table_name)
migrated = ActiveRecord::SchemaMigration.all_versions.map(&:to_i)
versions = ActiveRecord::Migrator.migration_files(migrations_paths).map do |file|
ActiveRecord::Migrator.parse_migration_filename(file).first.to_i
versions = migration_context.migration_files.map do |file|
migration_context.parse_migration_filename(file).first.to_i
end
unless migrated.include?(version)
......
......@@ -119,6 +119,14 @@ def initialize(connection, logger = nil, config = {}) # :nodoc:
end
end
def migrations_paths
@config[:migrations_paths] || Migrator.migrations_paths
end
def migration_context
MigrationContext.new(migrations_paths)
end
class Version
include Comparable
......
......@@ -28,7 +28,7 @@ def encode_with(coder)
coder["columns_hash"] = @columns_hash
coder["primary_keys"] = @primary_keys
coder["data_sources"] = @data_sources
coder["version"] = ActiveRecord::Migrator.current_version
coder["version"] = connection.migration_context.current_version
end
def init_with(coder)
......@@ -100,7 +100,7 @@ def clear_data_source_cache!(name)
def marshal_dump
# if we get current version during initialization, it happens stack over flow.
@version = ActiveRecord::Migrator.current_version
@version = connection.migration_context.current_version
[@version, @columns, @columns_hash, @primary_keys, @data_sources]
end
......
......@@ -3,6 +3,7 @@
require "set"
require "zlib"
require "active_support/core_ext/module/attribute_accessors"
require "active_record/tasks/database_tasks"
module ActiveRecord
class MigrationError < ActiveRecordError#:nodoc:
......@@ -550,7 +551,7 @@ def initialize(app)
end
def call(env)
mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
mtime = ActiveRecord::Base.connection.migration_context.last_migration.mtime.to_i
if @last_check < mtime
ActiveRecord::Migration.check_pending!(connection)
@last_check = mtime
......@@ -575,11 +576,11 @@ def nearest_delegate # :nodoc:
# Raises <tt>ActiveRecord::PendingMigrationError</tt> error if any migrations are pending.
def check_pending!(connection = Base.connection)
raise ActiveRecord::PendingMigrationError if ActiveRecord::Migrator.needs_migration?(connection)
raise ActiveRecord::PendingMigrationError if connection.migration_context.needs_migration?
end
def load_schema_if_pending!
if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations?
if Base.connection.migration_context.needs_migration? || !Base.connection.migration_context.any_migrations?
# Roundtrip to Rake to allow plugins to hook into database initialization.
root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
FileUtils.cd(root) do
......@@ -876,10 +877,10 @@ def copy(destination, sources, options = {})
FileUtils.mkdir_p(destination) unless File.exist?(destination)
destination_migrations = ActiveRecord::Migrator.migrations(destination)
destination_migrations = ActiveRecord::MigrationContext.new(destination).migrations
last = destination_migrations.last
sources.each do |scope, path|
source_migrations = ActiveRecord::Migrator.migrations(path)
source_migrations = ActiveRecord::MigrationContext.new(path).migrations
source_migrations.each do |migration|
source = File.binread(migration.filename)
......@@ -997,132 +998,147 @@ def mtime
end
end
class Migrator#:nodoc:
class << self
attr_writer :migrations_paths
alias :migrations_path= :migrations_paths=
def migrate(migrations_paths, target_version = nil, &block)
case
when target_version.nil?
up(migrations_paths, target_version, &block)
when current_version == 0 && target_version == 0
[]
when current_version > target_version
down(migrations_paths, target_version, &block)
else
up(migrations_paths, target_version, &block)
end
end
class MigrationContext # :nodoc:
attr_reader :migrations_paths
def rollback(migrations_paths, steps = 1)
move(:down, migrations_paths, steps)
end
def initialize(migrations_paths)
@migrations_paths = migrations_paths
end
def forward(migrations_paths, steps = 1)
move(:up, migrations_paths, steps)
def migrate(target_version = nil, &block)
case
when target_version.nil?
up(target_version, &block)
when current_version == 0 && target_version == 0
[]
when current_version > target_version
down(target_version, &block)
else
up(target_version, &block)
end
end
def up(migrations_paths, target_version = nil)
migrations = migrations(migrations_paths)
migrations.select! { |m| yield m } if block_given?
def rollback(steps = 1)
move(:down, steps)
end
new(:up, migrations, target_version).migrate
def forward(steps = 1)
move(:up, steps)
end
def up(target_version = nil)
selected_migrations = if block_given?
migrations.select { |m| yield m }
else
migrations
end
def down(migrations_paths, target_version = nil)
migrations = migrations(migrations_paths)
migrations.select! { |m| yield m } if block_given?
Migrator.new(:up, selected_migrations, target_version).migrate
end
new(:down, migrations, target_version).migrate
def down(target_version = nil)
selected_migrations = if block_given?
migrations.select { |m| yield m }
else
migrations
end
def run(direction, migrations_paths, target_version)
new(direction, migrations(migrations_paths), target_version).run
end
Migrator.new(:down, migrations, target_version).migrate
end
def open(migrations_paths)
new(:up, migrations(migrations_paths), nil)
end
def run(direction, target_version)
Migrator.new(direction, migrations, target_version).run
end
def get_all_versions
if SchemaMigration.table_exists?
SchemaMigration.all_versions.map(&:to_i)
else
[]
end
end
def open
Migrator.new(:up, migrations, nil)
end
def current_version(connection = nil)
get_all_versions.max || 0
rescue ActiveRecord::NoDatabaseError
def get_all_versions
if SchemaMigration.table_exists?
SchemaMigration.all_versions.map(&:to_i)
else
[]
end
end
def needs_migration?(connection = nil)
(migrations(migrations_paths).collect(&:version) - get_all_versions).size > 0
end
def current_version(connection = nil)
get_all_versions.max || 0
rescue ActiveRecord::NoDatabaseError
end
def any_migrations?
migrations(migrations_paths).any?
end
def needs_migration?
(migrations.collect(&:version) - get_all_versions).size > 0
end
def last_migration #:nodoc:
migrations(migrations_paths).last || NullMigration.new
end
def any_migrations?
migrations.any?
end
def migrations_paths
@migrations_paths ||= ["db/migrate"]
# just to not break things if someone uses: migrations_path = some_string
Array(@migrations_paths)
end
def last_migration #:nodoc:
migrations.last || NullMigration.new
end
def parse_migration_filename(filename) # :nodoc:
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
def parse_migration_filename(filename) # :nodoc:
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
end
def migrations
migrations = migration_files.map do |file|
version, name, scope = parse_migration_filename(file)
raise IllegalMigrationNameError.new(file) unless version
version = version.to_i
name = name.camelize
MigrationProxy.new(name, version, file, scope)
end
def migrations(paths)
paths = Array(paths)
migrations.sort_by(&:version)
end
migrations = migration_files(paths).map do |file|
version, name, scope = parse_migration_filename(file)
raise IllegalMigrationNameError.new(file) unless version
version = version.to_i
name = name.camelize
def migrations_status
db_list = ActiveRecord::SchemaMigration.normalized_versions
MigrationProxy.new(name, version, file, scope)
end
file_list = migration_files.map do |file|
version, name, scope = parse_migration_filename(file)
raise IllegalMigrationNameError.new(file) unless version
version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
status = db_list.delete(version) ? "up" : "down"
[status, version, (name + scope).humanize]
end.compact
migrations.sort_by(&:version)
db_list.map! do |version|
["up", version, "********** NO FILE **********"]
end
def migrations_status(paths)
paths = Array(paths)
db_list = ActiveRecord::SchemaMigration.normalized_versions
(db_list + file_list).sort_by { |_, version, _| version }
end
file_list = migration_files(paths).map do |file|
version, name, scope = parse_migration_filename(file)
raise IllegalMigrationNameError.new(file) unless version
version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
status = db_list.delete(version) ? "up" : "down"
[status, version, (name + scope).humanize]
end.compact
def migration_files
paths = Array(migrations_paths)
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
end
db_list.map! do |version|
["up", version, "********** NO FILE **********"]
end
def current_environment
ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
end
(db_list + file_list).sort_by { |_, version, _| version }
end
def protected_environment?
ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
end
def migration_files(paths)
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
end
def last_stored_environment
return nil if current_version == 0
raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
private
environment = ActiveRecord::InternalMetadata[:environment]
raise NoEnvironmentInSchemaError unless environment
environment
end
def move(direction, migrations_paths, steps)
migrator = new(direction, migrations(migrations_paths))
private
def move(direction, steps)
migrator = Migrator.new(direction, migrations)
if current_version != 0 && !migrator.current_migration
raise UnknownMigrationVersionError.new(current_version)
......@@ -1137,10 +1153,29 @@ def move(direction, migrations_paths, steps)
finish = migrator.migrations[start_index + steps]
version = finish ? finish.version : 0
send(direction, migrations_paths, version)
send(direction, version)
end
end
class Migrator # :nodoc:
class << self
attr_accessor :migrations_paths
def migrations_path=(path)
ActiveSupport::Deprecation.warn \
"ActiveRecord::Migrator.migrations_paths= is now deprecated and will be removed in Rails 6.0." \
"You can set the `migrations_paths` on the `connection` instead through the `database.yml`."
self.migrations_paths = [path]
end
# For cases where a table doesn't exist like loading from schema cache
def current_version(connection = nil)
MigrationContext.new(migrations_paths).current_version(connection)
end
end
self.migrations_paths = ["db/migrate"]
def initialize(direction, migrations, target_version = nil)
@direction = direction
@target_version = target_version
......@@ -1203,7 +1238,7 @@ def migrated
end
def load_migrated
@migrated_versions = Set.new(self.class.get_all_versions)
@migrated_versions = Set.new(Base.connection.migration_context.get_all_versions)
end
private
......@@ -1235,7 +1270,7 @@ def migrate_without_lock
# Stores the current environment in the database.
def record_environment
return if down?
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
end
def ran?(migration)
......@@ -1294,23 +1329,6 @@ def record_version_state_after_migrating(version)
end
end
def self.last_stored_environment
return nil if current_version == 0
raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
environment = ActiveRecord::InternalMetadata[:environment]
raise NoEnvironmentInSchemaError unless environment
environment
end
def self.current_environment
ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
end
def self.protected_environment?
ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
end
def up?
@direction == :up
end
......
......@@ -91,6 +91,7 @@ class Railtie < Rails::Railtie # :nodoc:
if File.file?(filename)
current_version = ActiveRecord::Migrator.current_version
next if current_version.nil?
cache = YAML.load(File.read(filename))
......
......@@ -6,7 +6,7 @@ db_namespace = namespace :db do
desc "Set the environment value for the database"
task "environment:set" => :load_config do
ActiveRecord::InternalMetadata.create_table
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
end
task check_protected_environments: :load_config do
......@@ -99,9 +99,8 @@ db_namespace = namespace :db do
ActiveRecord::Tasks::DatabaseTasks.check_target_version
ActiveRecord::Migrator.run(
ActiveRecord::Base.connection.migration_context.run(
:up,
ActiveRecord::Tasks::DatabaseTasks.migrations_paths,
ActiveRecord::Tasks::DatabaseTasks.target_version
)
db_namespace["_dump"].invoke
......@@ -113,9 +112,8 @@ db_namespace = namespace :db do
ActiveRecord::Tasks::DatabaseTasks.check_target_version
ActiveRecord::Migrator.run(
ActiveRecord::Base.connection.migration_context.run(
:down,
ActiveRecord::Tasks::DatabaseTasks.migrations_paths,
ActiveRecord::Tasks::DatabaseTasks.target_version
)
db_namespace["_dump"].invoke
......@@ -131,8 +129,7 @@ db_namespace = namespace :db do
puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
puts "-" * 50
paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths
ActiveRecord::Migrator.migrations_status(paths).each do |status, version, name|
ActiveRecord::Base.connection.migration_context.migrations_status.each do |status, version, name|
puts "#{status.center(8)} #{version.ljust(14)} #{name}"
end
puts
......@@ -142,14 +139,14 @@ db_namespace = namespace :db do
desc "Rolls the schema back to the previous version (specify steps w/ STEP=n)."
task rollback: :load_config do
step = ENV["STEP"] ? ENV["STEP"].to_i : 1
ActiveRecord::Migrator.rollback(ActiveRecord::Tasks::DatabaseTasks.migrations_paths, step)
ActiveRecord::Base.connection.migration_context.rollback(step)
db_namespace["_dump"].invoke
end
# desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
task forward: :load_config do
step = ENV["STEP"] ? ENV["STEP"].to_i : 1
ActiveRecord::Migrator.forward(ActiveRecord::Tasks::DatabaseTasks.migrations_paths, step)
ActiveRecord::Base.connection.migration_context.forward(step)
db_namespace["_dump"].invoke
end
......@@ -172,12 +169,12 @@ db_namespace = namespace :db do
desc "Retrieves the current schema version number"
task version: :load_config do
puts "Current version: #{ActiveRecord::Migrator.current_version}"
puts "Current version: #{ActiveRecord::Base.connection.migration_context.current_version}"
end
# desc "Raises an error if there are pending migrations"
task abort_if_pending_migrations: :load_config do
pending_migrations = ActiveRecord::Migrator.open(ActiveRecord::Tasks::DatabaseTasks.migrations_paths).pending_migrations
pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
if pending_migrations.any?
puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
......
......@@ -55,7 +55,7 @@ def define(info, &block) # :nodoc:
end
ActiveRecord::InternalMetadata.create_table
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
ActiveRecord::InternalMetadata[:environment] = connection.migration_context.current_environment
end
private
......
......@@ -44,7 +44,7 @@ def dump(stream)
def initialize(connection, options = {})
@connection = connection
@version = Migrator::current_version rescue nil
@version = connection.migration_context.current_version rescue nil
@options = options
end
......
......@@ -54,10 +54,10 @@ module DatabaseTasks
def check_protected_environments!
unless ENV["DISABLE_DATABASE_ENVIRONMENT_CHECK"]
current = ActiveRecord::Migrator.current_environment
stored = ActiveRecord::Migrator.last_stored_environment
current = ActiveRecord::Base.connection.migration_context.current_environment
stored = ActiveRecord::Base.connection.migration_context.last_stored_environment
if ActiveRecord::Migrator.protected_environment?
if ActiveRecord::Base.connection.migration_context.protected_environment?
raise ActiveRecord::ProtectedEnvironmentError.new(stored)
end
......@@ -85,6 +85,10 @@ def migrations_paths
@migrations_paths ||= Rails.application.paths["db/migrate"].to_a
end
def migration_context
MigrationContext.new(migrations_paths)
end
def fixtures_path
@fixtures_path ||= if ENV["FIXTURES_PATH"]
File.join(root, ENV["FIXTURES_PATH"])
......@@ -169,7 +173,7 @@ def migrate
verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] != "false" : true
scope = ENV["SCOPE"]
verbose_was, Migration.verbose = Migration.verbose, verbose
Migrator.migrate(migrations_paths, target_version) do |migration|
Base.connection.migration_context.migrate(target_version) do |migration|
scope.blank? || scope == migration.scope
end
ActiveRecord::Base.clear_cache!
......
......@@ -36,7 +36,7 @@ def test_initializes_internal_metadata_for_encoding_utf8mb4
assert connection.column_exists?(table_name, :key, :string)
end
ensure
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
ActiveRecord::InternalMetadata[:environment] = connection.migration_context.current_environment
end
private
......
......@@ -48,7 +48,7 @@ def test_schema_define
assert_nothing_raised { @connection.select_all "SELECT * FROM fruits" }
assert_nothing_raised { @connection.select_all "SELECT * FROM schema_migrations" }
assert_equal 7, ActiveRecord::Migrator::current_version
assert_equal 7, @connection.migration_context.current_version
end
def test_schema_define_w_table_name_prefix
......@@ -64,7 +64,7 @@ def test_schema_define_w_table_name_prefix
t.column :flavor, :string
end
end
assert_equal 7, ActiveRecord::Migrator::current_version
assert_equal 7, @connection.migration_context.current_version
ensure
ActiveRecord::Base.table_name_prefix = old_table_name_prefix
ActiveRecord::SchemaMigration.table_name = table_name
......
......@@ -4,37 +4,37 @@
module ActiveRecord
class Migration
class PendingMigrationsTest < ActiveRecord::TestCase
def setup
super
@connection = Minitest::Mock.new
@app = Minitest::Mock.new
conn = @connection
@pending = Class.new(CheckPending) {
define_method(:connection) { conn }
}.new(@app)
@pending.instance_variable_set :@last_check, -1 # Force checking
end
if current_adapter?(:SQLite3Adapter) && !in_memory_db?
class PendingMigrationsTest < ActiveRecord::TestCase
setup do
file = ActiveRecord::Base.connection.raw_connection.filename
@conn = ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:", migrations_paths: MIGRATIONS_ROOT + "/valid"
source_db = SQLite3::Database.new file
dest_db = ActiveRecord::Base.connection.raw_connection
backup = SQLite3::Backup.new(dest_db, "main", source_db, "main")
backup.step(-1)
backup.finish
end
def teardown
assert @connection.verify
assert @app.verify
super
end
teardown do
@conn.release_connection if @conn
ActiveRecord::Base.establish_connection :arunit
end
def test_errors_if_pending
ActiveRecord::Base.connection.drop_table "schema_migrations", if_exists: true
def test_errors_if_pending
ActiveRecord::Migrator.stub :needs_migration?, true do
assert_raise ActiveRecord::PendingMigrationError do
@pending.call(nil)
assert_raises ActiveRecord::PendingMigrationError do
CheckPending.new(Proc.new {}).call({})
end
end
end
def test_checks_if_supported
@app.expect :call, nil, [:foo]
def test_checks_if_supported
ActiveRecord::SchemaMigration.create_table
migrator = Base.connection.migration_context
capture(:stdout) { migrator.migrate }
ActiveRecord::Migrator.stub :needs_migration?, false do
@pending.call(:foo)
assert_nil CheckPending.new(Proc.new {}).call({})
end
end
end
......
......@@ -71,6 +71,16 @@ def setup
ActiveRecord::Migration.verbose = @verbose_was
end
def test_migrator_migrations_path_is_deprecated
assert_deprecated do
ActiveRecord::Migrator.migrations_path = "/whatever"
end
ensure
assert_deprecated do
ActiveRecord::Migrator.migrations_path = "db/migrate"
end
end
def test_migration_version_matches_component_version
assert_equal ActiveRecord::VERSION::STRING.to_f, ActiveRecord::Migration.current_version
end
......@@ -78,20 +88,20 @@ def test_migration_version_matches_component_version
def test_migrator_versions
migrations_path = MIGRATIONS_ROOT + "/valid"
old_path = ActiveRecord::Migrator.migrations_paths
ActiveRecord::Migrator.migrations_paths = migrations_path
migrator = ActiveRecord::MigrationContext.new(migrations_path)
ActiveRecord::Migrator.up(migrations_path)
assert_equal 3, ActiveRecord::Migrator.current_version
assert_equal false, ActiveRecord::Migrator.needs_migration?
migrator.up
assert_equal 3, migrator.current_version
assert_equal false, migrator.needs_migration?
ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid")
assert_equal 0, ActiveRecord::Migrator.current_version
assert_equal true, ActiveRecord::Migrator.needs_migration?
migrator.down
assert_equal 0, migrator.current_version
assert_equal true, migrator.needs_migration?
ActiveRecord::SchemaMigration.create!(version: 3)
assert_equal true, ActiveRecord::Migrator.needs_migration?
assert_equal true, migrator.needs_migration?
ensure
ActiveRecord::Migrator.migrations_paths = old_path
ActiveRecord::MigrationContext.new(old_path)
end
def test_migration_detection_without_schema_migration_table
......@@ -99,28 +109,31 @@ def test_migration_detection_without_schema_migration_table
migrations_path = MIGRATIONS_ROOT + "/valid"
old_path = ActiveRecord::Migrator.migrations_paths
ActiveRecord::Migrator.migrations_paths = migrations_path
migrator = ActiveRecord::MigrationContext.new(migrations_path)
assert_equal true, ActiveRecord::Migrator.needs_migration?
assert_equal true, migrator.needs_migration?
ensure
ActiveRecord::Migrator.migrations_paths = old_path
ActiveRecord::MigrationContext.new(old_path)
end
def test_any_migrations
old_path = ActiveRecord::Migrator.migrations_paths
ActiveRecord::Migrator.migrations_paths = MIGRATIONS_ROOT + "/valid"
migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid")
assert ActiveRecord::Migrator.any_migrations?
assert migrator.any_migrations?
ActiveRecord::Migrator.migrations_paths = MIGRATIONS_ROOT + "/empty"
migrator_empty = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/empty")
assert_not ActiveRecord::Migrator.any_migrations?
assert_not migrator_empty.any_migrations?
ensure
ActiveRecord::Migrator.migrations_paths = old_path
ActiveRecord::MigrationContext.new(old_path)
end
def test_migration_version
assert_nothing_raised { ActiveRecord::Migrator.run(:up, MIGRATIONS_ROOT + "/version_check", 20131219224947) }
migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/version_check")
assert_equal 0, migrator.current_version
migrator.up(20131219224947)
assert_equal 20131219224947, migrator.current_version
end
def test_create_table_with_force_true_does_not_drop_nonexisting_table
......@@ -219,12 +232,13 @@ def test_filtering_migrations
assert !Reminder.table_exists?
name_filter = lambda { |migration| migration.name == "ValidPeopleHaveLastNames" }
ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", &name_filter)
migrator = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid")
migrator.up(&name_filter)
assert_column Person, :last_name
assert_raise(ActiveRecord::StatementInvalid) { Reminder.first }
ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", &name_filter)
migrator.down(&name_filter)
assert_no_column Person, :last_name
assert_raise(ActiveRecord::StatementInvalid) { Reminder.first }
......@@ -382,9 +396,9 @@ 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
migrator = ActiveRecord::MigrationContext.new(migrations_path)
ActiveRecord::Migrator.up(migrations_path)
migrator.up
assert_equal current_env, ActiveRecord::InternalMetadata[:environment]
original_rails_env = ENV["RAILS_ENV"]
......@@ -395,13 +409,13 @@ def test_internal_metadata_stores_environment
refute_equal current_env, new_env
sleep 1 # mysql by default does not store fractional seconds in the database
ActiveRecord::Migrator.up(migrations_path)
migrator.up
assert_equal new_env, ActiveRecord::InternalMetadata[:environment]
ensure
ActiveRecord::Migrator.migrations_paths = old_path
migrator = ActiveRecord::MigrationContext.new(old_path)
ENV["RAILS_ENV"] = original_rails_env
ENV["RACK_ENV"] = original_rack_env
ActiveRecord::Migrator.up(migrations_path)
migrator.up
end
def test_internal_metadata_stores_environment_when_other_data_exists
......@@ -411,14 +425,15 @@ def test_internal_metadata_stores_environment_when_other_data_exists
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)
migrator = ActiveRecord::MigrationContext.new(migrations_path)
migrator.up
assert_equal current_env, ActiveRecord::InternalMetadata[:environment]
assert_equal "bar", ActiveRecord::InternalMetadata[:foo]
ensure
ActiveRecord::Migrator.migrations_paths = old_path
migrator = ActiveRecord::MigrationContext.new(old_path)
migrator.up
end
def test_proper_table_name_on_migration
......
......@@ -89,7 +89,7 @@ def test_migrator_with_missing_version_numbers
end
def test_finds_migrations
migrations = ActiveRecord::Migrator.migrations(MIGRATIONS_ROOT + "/valid")
migrations = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid").migrations
[[1, "ValidPeopleHaveLastNames"], [2, "WeNeedReminders"], [3, "InnocentJointable"]].each_with_index do |pair, i|
assert_equal migrations[i].version, pair.first
......@@ -98,7 +98,8 @@ def test_finds_migrations
end
def test_finds_migrations_in_subdirectories
migrations = ActiveRecord::Migrator.migrations(MIGRATIONS_ROOT + "/valid_with_subdirectories")
migrations = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/valid_with_subdirectories").migrations
[[1, "ValidPeopleHaveLastNames"], [2, "WeNeedReminders"], [3, "InnocentJointable"]].each_with_index do |pair, i|
assert_equal migrations[i].version, pair.first
......@@ -108,7 +109,7 @@ def test_finds_migrations_in_subdirectories
def test_finds_migrations_from_two_directories
directories = [MIGRATIONS_ROOT + "/valid_with_timestamps", MIGRATIONS_ROOT + "/to_copy_with_timestamps"]
migrations = ActiveRecord::Migrator.migrations directories
migrations = ActiveRecord::MigrationContext.new(directories).migrations
[[20090101010101, "PeopleHaveHobbies"],
[20090101010202, "PeopleHaveDescriptions"],
......@@ -121,14 +122,14 @@ def test_finds_migrations_from_two_directories
end
def test_finds_migrations_in_numbered_directory
migrations = ActiveRecord::Migrator.migrations [MIGRATIONS_ROOT + "/10_urban"]
migrations = ActiveRecord::MigrationContext.new(MIGRATIONS_ROOT + "/10_urban").migrations
assert_equal 9, migrations[0].version
assert_equal "AddExpressions", migrations[0].name
end
def test_relative_migrations
list = Dir.chdir(MIGRATIONS_ROOT) do
ActiveRecord::Migrator.migrations("valid")
ActiveRecord::MigrationContext.new("valid").migrations
end
migration_proxy = list.find { |item|
......@@ -157,7 +158,7 @@ def test_migrations_status
["up", "002", "We need reminders"],
["down", "003", "Innocent jointable"],
["up", "010", "********** NO FILE **********"],
], ActiveRecord::Migrator.migrations_status(path)
], ActiveRecord::MigrationContext.new(path).migrations_status
end
def test_migrations_status_in_subdirectories
......@@ -171,24 +172,20 @@ def test_migrations_status_in_subdirectories
["up", "002", "We need reminders"],
["down", "003", "Innocent jointable"],
["up", "010", "********** NO FILE **********"],
], ActiveRecord::Migrator.migrations_status(path)
], ActiveRecord::MigrationContext.new(path).migrations_status
end
def test_migrations_status_with_schema_define_in_subdirectories
path = MIGRATIONS_ROOT + "/valid_with_subdirectories"
prev_paths = ActiveRecord::Migrator.migrations_paths
ActiveRecord::Migrator.migrations_paths = path
_, migrator = migrator_class(3)
migrator = migrator.new("valid_with_subdirectories")
ActiveRecord::Schema.define(version: 3) do
end
migrator.migrate
assert_equal [
["up", "001", "Valid people have last names"],
["up", "002", "We need reminders"],
["up", "003", "Innocent jointable"],
], ActiveRecord::Migrator.migrations_status(path)
ensure
ActiveRecord::Migrator.migrations_paths = prev_paths
["up", "001", "********** NO FILE **********"],
["up", "002", "********** NO FILE **********"],
["up", "003", "********** NO FILE **********"],
], migrator.migrations_status
end
def test_migrations_status_from_two_directories
......@@ -204,7 +201,7 @@ def test_migrations_status_from_two_directories
["down", "20100201010101", "Valid with timestamps we need reminders"],
["down", "20100301010101", "Valid with timestamps innocent jointable"],
["up", "20160528010101", "********** NO FILE **********"],
], ActiveRecord::Migrator.migrations_status(paths)
], ActiveRecord::MigrationContext.new(paths).migrations_status
end
def test_migrator_interleaved_migrations
......@@ -232,25 +229,28 @@ def test_migrator_interleaved_migrations
def test_up_calls_up
migrations = [Sensor.new(nil, 0), Sensor.new(nil, 1), Sensor.new(nil, 2)]
ActiveRecord::Migrator.new(:up, migrations).migrate
migrator = ActiveRecord::Migrator.new(:up, migrations)
migrator.migrate
assert migrations.all?(&:went_up)
assert migrations.all? { |m| !m.went_down }
assert_equal 2, ActiveRecord::Migrator.current_version
assert_equal 2, migrator.current_version
end
def test_down_calls_down
test_up_calls_up
migrations = [Sensor.new(nil, 0), Sensor.new(nil, 1), Sensor.new(nil, 2)]
ActiveRecord::Migrator.new(:down, migrations).migrate
migrator = ActiveRecord::Migrator.new(:down, migrations)
migrator.migrate
assert migrations.all? { |m| !m.went_up }
assert migrations.all?(&:went_down)
assert_equal 0, ActiveRecord::Migrator.current_version
assert_equal 0, migrator.current_version
end
def test_current_version
ActiveRecord::SchemaMigration.create!(version: "1000")
assert_equal 1000, ActiveRecord::Migrator.current_version
migrator = ActiveRecord::MigrationContext.new("db/migrate")
assert_equal 1000, migrator.current_version
end
def test_migrator_one_up
......@@ -289,33 +289,36 @@ def test_migrator_one_up_one_down
def test_migrator_double_up
calls, migrations = sensors(3)
assert_equal(0, ActiveRecord::Migrator.current_version)
migrator = ActiveRecord::Migrator.new(:up, migrations, 1)
assert_equal(0, migrator.current_version)
ActiveRecord::Migrator.new(:up, migrations, 1).migrate
migrator.migrate
assert_equal [[:up, 1]], calls
calls.clear
ActiveRecord::Migrator.new(:up, migrations, 1).migrate
migrator.migrate
assert_equal [], calls
end
def test_migrator_double_down
calls, migrations = sensors(3)
migrator = ActiveRecord::Migrator.new(:up, migrations, 1)
assert_equal(0, ActiveRecord::Migrator.current_version)
assert_equal 0, migrator.current_version
ActiveRecord::Migrator.new(:up, migrations, 1).run
migrator.run
assert_equal [[:up, 1]], calls
calls.clear
ActiveRecord::Migrator.new(:down, migrations, 1).run
migrator = ActiveRecord::Migrator.new(:down, migrations, 1)
migrator.run
assert_equal [[:down, 1]], calls
calls.clear
ActiveRecord::Migrator.new(:down, migrations, 1).run
migrator.run
assert_equal [], calls
assert_equal(0, ActiveRecord::Migrator.current_version)
assert_equal 0, migrator.current_version
end
def test_migrator_verbosity
......@@ -361,78 +364,85 @@ def test_target_version_zero_should_run_only_once
def test_migrator_going_down_due_to_version_target
calls, migrator = migrator_class(3)
migrator = migrator.new("valid")
migrator.up("valid", 1)
migrator.up(1)
assert_equal [[:up, 1]], calls
calls.clear
migrator.migrate("valid", 0)
migrator.migrate(0)
assert_equal [[:down, 1]], calls
calls.clear
migrator.migrate("valid")
migrator.migrate
assert_equal [[:up, 1], [:up, 2], [:up, 3]], calls
end
def test_migrator_output_when_running_multiple_migrations
_, migrator = migrator_class(3)
migrator = migrator.new("valid")
result = migrator.migrate("valid")
result = migrator.migrate
assert_equal(3, result.count)
# Nothing migrated from duplicate run
result = migrator.migrate("valid")
result = migrator.migrate
assert_equal(0, result.count)
result = migrator.rollback("valid")
result = migrator.rollback
assert_equal(1, result.count)
end
def test_migrator_output_when_running_single_migration
_, migrator = migrator_class(1)
result = migrator.run(:up, "valid", 1)
migrator = migrator.new("valid")
result = migrator.run(:up, 1)
assert_equal(1, result.version)
end
def test_migrator_rollback
_, migrator = migrator_class(3)
migrator = migrator.new("valid")
migrator.migrate("valid")
assert_equal(3, ActiveRecord::Migrator.current_version)
migrator.migrate
assert_equal(3, migrator.current_version)
migrator.rollback("valid")
assert_equal(2, ActiveRecord::Migrator.current_version)
migrator.rollback
assert_equal(2, migrator.current_version)
migrator.rollback("valid")
assert_equal(1, ActiveRecord::Migrator.current_version)
migrator.rollback
assert_equal(1, migrator.current_version)
migrator.rollback("valid")
assert_equal(0, ActiveRecord::Migrator.current_version)
migrator.rollback
assert_equal(0, migrator.current_version)
migrator.rollback("valid")
assert_equal(0, ActiveRecord::Migrator.current_version)
migrator.rollback
assert_equal(0, migrator.current_version)
end
def test_migrator_db_has_no_schema_migrations_table
_, migrator = migrator_class(3)
migrator = migrator.new("valid")
ActiveRecord::Base.connection.drop_table "schema_migrations", if_exists: true
assert_not ActiveRecord::Base.connection.table_exists?("schema_migrations")
migrator.migrate("valid", 1)
migrator.migrate(1)
assert ActiveRecord::Base.connection.table_exists?("schema_migrations")
end
def test_migrator_forward
_, migrator = migrator_class(3)
migrator.migrate("/valid", 1)
assert_equal(1, ActiveRecord::Migrator.current_version)
migrator = migrator.new("/valid")
migrator.migrate(1)
assert_equal(1, migrator.current_version)
migrator.forward("/valid", 2)
assert_equal(3, ActiveRecord::Migrator.current_version)
migrator.forward(2)
assert_equal(3, migrator.current_version)
migrator.forward("/valid")
assert_equal(3, ActiveRecord::Migrator.current_version)
migrator.forward
assert_equal(3, migrator.current_version)
end
def test_only_loads_pending_migrations
......@@ -440,25 +450,27 @@ def test_only_loads_pending_migrations
ActiveRecord::SchemaMigration.create!(version: "1")
calls, migrator = migrator_class(3)
migrator.migrate("valid", nil)
migrator = migrator.new("valid")
migrator.migrate
assert_equal [[:up, 2], [:up, 3]], calls
end
def test_get_all_versions
_, migrator = migrator_class(3)
migrator = migrator.new("valid")
migrator.migrate("valid")
assert_equal([1, 2, 3], ActiveRecord::Migrator.get_all_versions)
migrator.migrate
assert_equal([1, 2, 3], migrator.get_all_versions)
migrator.rollback("valid")
assert_equal([1, 2], ActiveRecord::Migrator.get_all_versions)
migrator.rollback
assert_equal([1, 2], migrator.get_all_versions)
migrator.rollback("valid")
assert_equal([1], ActiveRecord::Migrator.get_all_versions)
migrator.rollback
assert_equal([1], migrator.get_all_versions)
migrator.rollback("valid")
assert_equal([], ActiveRecord::Migrator.get_all_versions)
migrator.rollback
assert_equal([], migrator.get_all_versions)
end
private
......@@ -483,11 +495,11 @@ def sensors(count)
def migrator_class(count)
calls, migrations = sensors(count)
migrator = Class.new(ActiveRecord::Migrator).extend(Module.new {
define_method(:migrations) { |paths|
migrator = Class.new(ActiveRecord::MigrationContext) {
define_method(:migrations) { |*|
migrations
}
})
}
[calls, migrator]
end
end
......@@ -28,10 +28,10 @@ def teardown
class DatabaseTasksUtilsTask < ActiveRecord::TestCase
def test_raises_an_error_when_called_with_protected_environment
ActiveRecord::Migrator.stubs(:current_version).returns(1)
ActiveRecord::MigrationContext.any_instance.stubs(:current_version).returns(1)
protected_environments = ActiveRecord::Base.protected_environments
current_env = ActiveRecord::Migrator.current_environment
current_env = ActiveRecord::Base.connection.migration_context.current_environment
assert_not_includes protected_environments, current_env
# Assert no error
ActiveRecord::Tasks::DatabaseTasks.check_protected_environments!
......@@ -45,10 +45,10 @@ def test_raises_an_error_when_called_with_protected_environment
end
def test_raises_an_error_when_called_with_protected_environment_which_name_is_a_symbol
ActiveRecord::Migrator.stubs(:current_version).returns(1)
ActiveRecord::MigrationContext.any_instance.stubs(:current_version).returns(1)
protected_environments = ActiveRecord::Base.protected_environments
current_env = ActiveRecord::Migrator.current_environment
current_env = ActiveRecord::Base.connection.migration_context.current_environment
assert_not_includes protected_environments, current_env
# Assert no error
ActiveRecord::Tasks::DatabaseTasks.check_protected_environments!
......@@ -63,7 +63,7 @@ def test_raises_an_error_when_called_with_protected_environment_which_name_is_a_
def test_raises_an_error_if_no_migrations_have_been_made
ActiveRecord::InternalMetadata.stubs(:table_exists?).returns(false)
ActiveRecord::Migrator.stubs(:current_version).returns(1)
ActiveRecord::MigrationContext.any_instance.stubs(:current_version).returns(1)
assert_raise(ActiveRecord::NoEnvironmentInSchemaError) do
ActiveRecord::Tasks::DatabaseTasks.check_protected_environments!
......@@ -347,50 +347,92 @@ def test_drops_testand_development_databases_when_rails_env_is_development
end
end
class DatabaseTasksMigrateTest < ActiveRecord::TestCase
self.use_transactional_tests = false
if current_adapter?(:SQLite3Adapter) && !in_memory_db?
class DatabaseTasksMigrateTest < ActiveRecord::TestCase
self.use_transactional_tests = false
# Use a memory db here to avoid having to rollback at the end
setup do
migrations_path = MIGRATIONS_ROOT + "/valid"
file = ActiveRecord::Base.connection.raw_connection.filename
@conn = ActiveRecord::Base.establish_connection adapter: "sqlite3",
database: ":memory:", migrations_paths: migrations_path
source_db = SQLite3::Database.new file
dest_db = ActiveRecord::Base.connection.raw_connection
backup = SQLite3::Backup.new(dest_db, "main", source_db, "main")
backup.step(-1)
backup.finish
end
def setup
ActiveRecord::Tasks::DatabaseTasks.migrations_paths = "custom/path"
end
teardown do
@conn.release_connection if @conn
ActiveRecord::Base.establish_connection :arunit
end
def teardown
ActiveRecord::Tasks::DatabaseTasks.migrations_paths = nil
end
def test_migrate_set_and_unset_verbose_and_version_env_vars
verbose, version = ENV["VERBOSE"], ENV["VERSION"]
ENV["VERSION"] = "2"
ENV["VERBOSE"] = "false"
def test_migrate_receives_correct_env_vars
verbose, version = ENV["VERBOSE"], ENV["VERSION"]
# run down migration because it was already run on copied db
assert_empty capture_migration_output
ENV["VERBOSE"] = "false"
ENV["VERSION"] = "4"
ActiveRecord::Migrator.expects(:migrate).with("custom/path", 4)
ActiveRecord::Migration.expects(:verbose=).with(false)
ActiveRecord::Migration.expects(:verbose=).with(ActiveRecord::Migration.verbose)
ActiveRecord::Tasks::DatabaseTasks.migrate
ENV.delete("VERSION")
ENV.delete("VERBOSE")
ENV.delete("VERBOSE")
ENV.delete("VERSION")
ActiveRecord::Migrator.expects(:migrate).with("custom/path", nil)
ActiveRecord::Migration.expects(:verbose=).with(true)
ActiveRecord::Migration.expects(:verbose=).with(ActiveRecord::Migration.verbose)
ActiveRecord::Tasks::DatabaseTasks.migrate
# re-run up migration
assert_includes capture_migration_output, "migrating"
ensure
ENV["VERBOSE"], ENV["VERSION"] = verbose, version
end
ENV["VERBOSE"] = ""
ENV["VERSION"] = ""
ActiveRecord::Migrator.expects(:migrate).with("custom/path", nil)
ActiveRecord::Migration.expects(:verbose=).with(true)
ActiveRecord::Migration.expects(:verbose=).with(ActiveRecord::Migration.verbose)
ActiveRecord::Tasks::DatabaseTasks.migrate
def test_migrate_set_and_unset_empty_values_for_verbose_and_version_env_vars
verbose, version = ENV["VERBOSE"], ENV["VERSION"]
ENV["VERBOSE"] = "yes"
ENV["VERSION"] = "0"
ActiveRecord::Migrator.expects(:migrate).with("custom/path", 0)
ActiveRecord::Migration.expects(:verbose=).with(true)
ActiveRecord::Migration.expects(:verbose=).with(ActiveRecord::Migration.verbose)
ActiveRecord::Tasks::DatabaseTasks.migrate
ensure
ENV["VERBOSE"], ENV["VERSION"] = verbose, version
ENV["VERSION"] = "2"
ENV["VERBOSE"] = "false"
# run down migration because it was already run on copied db
assert_empty capture_migration_output
ENV["VERBOSE"] = ""
ENV["VERSION"] = ""
# re-run up migration
assert_includes capture_migration_output, "migrating"
ensure
ENV["VERBOSE"], ENV["VERSION"] = verbose, version
end
def test_migrate_set_and_unset_nonsense_values_for_verbose_and_version_env_vars
verbose, version = ENV["VERBOSE"], ENV["VERSION"]
# run down migration because it was already run on copied db
ENV["VERSION"] = "2"
ENV["VERBOSE"] = "false"
assert_empty capture_migration_output
ENV["VERBOSE"] = "yes"
ENV["VERSION"] = "2"
# run no migration because 2 was already run
assert_empty capture_migration_output
ensure
ENV["VERBOSE"], ENV["VERSION"] = verbose, version
end
private
def capture_migration_output
capture(:stdout) do
ActiveRecord::Tasks::DatabaseTasks.migrate
end
end
end
end
class DatabaseTasksMigrateErrorTest < ActiveRecord::TestCase
self.use_transactional_tests = false
def test_migrate_raise_error_on_invalid_version_format
version = ENV["VERSION"]
......
......@@ -3,5 +3,5 @@
require_relative "create_users_migration"
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Migrator.migrate File.expand_path("../../db/migrate", __dir__)
ActiveRecord::Base.connection.migration_context.migrate
ActiveStorageCreateUsers.migrate(:up)
......@@ -99,7 +99,7 @@ def to_html
end
property "Database schema version" do
ActiveRecord::Migrator.current_version rescue nil
ActiveRecord::Base.connection.migration_context.current_version rescue nil
end
end
end
......@@ -37,6 +37,18 @@ class AMigration < ActiveRecord::Migration::Current
assert_match(/AMigration: reverted/, output)
end
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
......
......@@ -34,7 +34,7 @@ def boot_rails
def migrations
migration_root = File.expand_path(ActiveRecord::Migrator.migrations_paths.first, app_path)
ActiveRecord::Migrator.migrations(migration_root)
ActiveRecord::MigrationContext.new(migration_root).migrations
end
test "serving sprocket's assets" do
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册