提交 ba093a5a 编写于 作者: J John Hawthorn

Sync test DB from schema using its SHA1

Previously, we used the migration status to determine whether the test
database(s) needed to be reloaded from the schema. This worked in most
cases, but if a schema.rb was modified outside of migrations or if a
migration was rolled back, it would require a manual db:test:prepare.

This commit updates load_schema to record the SHA1 of the loaded schema
file inside of the ar_internal_metadata table. We can then use this SHA
to determine whether we should reload the schema.

This ensures that the test DB stays exactly in sync with the schema
file, including rollbacks which fixes a test marked TODO.
上级 eb4faa13
......@@ -587,18 +587,22 @@ def check_pending!(connection = Base.connection)
end
def load_schema_if_pending!
if Base.connection.migration_context.needs_migration? || !Base.connection.migration_context.any_migrations?
current_config = Base.connection_config
all_configs = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env)
unless all_configs.all? { |config| Tasks::DatabaseTasks.schema_up_to_date?(config.config) }
# Roundtrip to Rake to allow plugins to hook into database initialization.
root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
FileUtils.cd(root) do
current_config = Base.connection_config
Base.clear_all_connections!
system("bin/rails db:test:prepare")
# Establish a new connection, the old database may be gone (db:test:prepare uses purge)
Base.establish_connection(current_config)
end
check_pending!
end
# Establish a new connection, the old database may be gone (db:test:prepare uses purge)
Base.establish_connection(current_config)
check_pending!
end
def maintain_test_schema! #:nodoc:
......
......@@ -332,10 +332,21 @@ def load_schema(configuration, format = ActiveRecord::Base.schema_format, file =
end
ActiveRecord::InternalMetadata.create_table
ActiveRecord::InternalMetadata[:environment] = environment
ActiveRecord::InternalMetadata[:schema_sha1] = schema_sha1(file)
ensure
Migration.verbose = verbose_was
end
def schema_up_to_date?(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = env, spec_name = "primary")
file ||= dump_filename(spec_name, format)
return true unless File.exist?(file)
ActiveRecord::Base.establish_connection(configuration)
return false unless ActiveRecord::InternalMetadata.table_exists?
ActiveRecord::InternalMetadata[:schema_sha1] == schema_sha1(file)
end
def dump_schema(configuration, format = ActiveRecord::Base.schema_format, spec_name = "primary") # :nodoc:
require "active_record/schema_dumper"
filename = dump_filename(spec_name, format)
......@@ -467,6 +478,10 @@ def each_local_configuration
def local_database?(configuration)
configuration["host"].blank? || LOCAL_HOSTS.include?(configuration["host"])
end
def schema_sha1(file)
Digest::SHA1.hexdigest(File.read(file))
end
end
end
end
......@@ -232,10 +232,7 @@ class UserTest < ActiveSupport::TestCase
assert_successful_test_run("models/user_test.rb")
end
# TODO: would be nice if we could detect the schema change automatically.
# For now, the user has to synchronize the schema manually.
# This test case serves as a reminder for this use case.
test "manually synchronize test schema after rollback" do
test "automatically synchronizes test schema after rollback" do
output = rails("generate", "model", "user", "name:string")
version = output.match(/(\d+)_create_users\.rb/)[1]
......@@ -268,10 +265,6 @@ class UserTest < ActiveSupport::TestCase
end
RUBY
assert_successful_test_run "models/user_test.rb"
rails "db:test:prepare"
assert_unsuccessful_run "models/user_test.rb", <<-ASSERTION
Expected: ["id", "name"]
Actual: ["id", "name", "age"]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册