Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only create parallel test databases on schema changes #36826

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 6 additions & 3 deletions activerecord/lib/active_record/migration.rb
Expand Up @@ -587,8 +587,10 @@ 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?
# Roundtrip to Rake to allow plugins to hook into database initialization.
all_configs = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env)

unless all_configs.all? { |config| Tasks::DatabaseTasks.schema_up_to_date?(config.config) }
# Roundrip 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
Expand All @@ -597,8 +599,9 @@ def load_schema_if_pending!
# Establish a new connection, the old database may be gone (db:test:prepare uses purge)
Base.establish_connection(current_config)
end
check_pending!
end

check_pending!
end

def maintain_test_schema! #:nodoc:
Expand Down
30 changes: 30 additions & 0 deletions activerecord/lib/active_record/tasks/database_tasks.rb
Expand Up @@ -332,10 +332,36 @@ 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 reset_to_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = env, spec_name = "primary") # :nodoc:
file ||= dump_filename(spec_name, format)

check_schema_file(file)

ActiveRecord::Base.establish_connection(configuration)

if schema_up_to_date?(configuration, format, file, environment, spec_name)
truncate_tables(configuration)
else
purge(configuration)
load_schema(configuration, format, file, environment, spec_name)
end
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)
Expand Down Expand Up @@ -467,6 +493,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
17 changes: 1 addition & 16 deletions activerecord/lib/active_record/test_databases.rb
Expand Up @@ -8,31 +8,16 @@ module TestDatabases # :nodoc:
create_and_load_schema(i, env_name: Rails.env)
end

ActiveSupport::Testing::Parallelization.run_cleanup_hook do
drop(env_name: Rails.env)
end

def self.create_and_load_schema(i, env_name:)
old, ENV["VERBOSE"] = ENV["VERBOSE"], "false"

ActiveRecord::Base.configurations.configs_for(env_name: env_name).each do |db_config|
db_config.config["database"] += "-#{i}"
ActiveRecord::Tasks::DatabaseTasks.create(db_config.config)
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config.config, ActiveRecord::Base.schema_format, nil, env_name, db_config.spec_name)
ActiveRecord::Tasks::DatabaseTasks.reset_to_schema(db_config.config, ActiveRecord::Base.schema_format, nil, env_name, db_config.spec_name)
end
ensure
ActiveRecord::Base.establish_connection(Rails.env.to_sym)
ENV["VERBOSE"] = old
end

def self.drop(env_name:)
old, ENV["VERBOSE"] = ENV["VERBOSE"], "false"

ActiveRecord::Base.configurations.configs_for(env_name: env_name).each do |db_config|
ActiveRecord::Tasks::DatabaseTasks.drop(db_config.config)
end
ensure
ENV["VERBOSE"] = old
end
end
end
9 changes: 1 addition & 8 deletions railties/test/application/test_test.rb
Expand Up @@ -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]

Expand Down Expand Up @@ -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"]
Expand Down