1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

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.
This commit is contained in:
John Hawthorn 2019-08-06 10:31:26 -07:00
parent eb4faa13e8
commit ba093a5ada
3 changed files with 25 additions and 13 deletions

View file

@ -587,18 +587,22 @@ module ActiveRecord
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:

View file

@ -332,10 +332,21 @@ module ActiveRecord
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 @@ module ActiveRecord
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

View file

@ -232,10 +232,7 @@ module ApplicationTests
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 @@ module ApplicationTests
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"]