From badb4b336cab4d2d03a5cbfecd6c6a0e1b43c719 Mon Sep 17 00:00:00 2001 From: barbie-bot Date: Wed, 8 Apr 2026 11:47:35 +0000 Subject: [PATCH] Use DATABASE_URL instead of temp database.yml for multi-db tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the RAILS_DATABASE_YML / Dir.mktmpdir approach with DATABASE_URL: - Read database config via Rails.application.config.database_configuration instead of manually parsing YAML+ERB - Build a DATABASE_URL from each test config and pass it to subprocesses; Rails merges it on top of the test: entry — no temp files needed - Remove non_test_configs, Dir.mktmpdir, and the require yaml/erb/tmpdir - Remove RAILS_DATABASE_YML override from config/application.rb(.dist) Co-Authored-By: Claude Sonnet 4.6 --- config/application.rb.dist | 4 --- lib/tasks/test_databases.rake | 62 +++++++++++++++++++---------------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/config/application.rb.dist b/config/application.rb.dist index ea1f8b6..f1be478 100644 --- a/config/application.rb.dist +++ b/config/application.rb.dist @@ -20,10 +20,6 @@ Bundler.require(*Rails.groups) module FixinMe class Application < Rails::Application - # Allow RAILS_DATABASE_YML to override the database config file path. - # Used by the multi-database test runner (lib/tasks/test_databases.rake). - config.paths['config/database'] = [ENV['RAILS_DATABASE_YML']] if ENV['RAILS_DATABASE_YML'] - # Initialize configuration defaults for originally generated Rails version. config.load_defaults 7.0 diff --git a/lib/tasks/test_databases.rake b/lib/tasks/test_databases.rake index 2c26f1a..bc37861 100644 --- a/lib/tasks/test_databases.rake +++ b/lib/tasks/test_databases.rake @@ -1,6 +1,4 @@ -require 'yaml' -require 'erb' -require 'tmpdir' +require 'uri' # Multi-database test runner # ========================== @@ -25,9 +23,10 @@ require 'tmpdir' # # A single-database setup is unchanged: every task behaves exactly as before. # -# The mechanism uses RAILS_DATABASE_YML — an env var read by -# config/application.rb(.dist) to override Rails' database config path before -# initialisation, giving each subprocess a clean, isolated database config. +# Database configuration is read via Rails.application.config.database_configuration +# so ERB interpolation and all Rails path overrides are respected automatically. +# Each subprocess receives DATABASE_URL built from the selected config, which +# Rails merges on top of the test: entry from database.yml — no temporary files needed. module MultiDbTests ADAPTER_GEMS = { @@ -55,19 +54,8 @@ module MultiDbTests class << self # Returns {name => config_hash} for every key starting with "test". def test_configs - @test_configs ||= begin - db_file = Rails.root.join('config', 'database.yml') - all = YAML.safe_load(ERB.new(db_file.read).result, aliases: true) || {} - all.select { |k, v| k.to_s.start_with?('test') && v.is_a?(Hash) } - end - end - - def non_test_configs - @non_test_configs ||= begin - db_file = Rails.root.join('config', 'database.yml') - all = YAML.safe_load(ERB.new(db_file.read).result, aliases: true) || {} - all.reject { |k, _| k.to_s.start_with?('test') } - end + @test_configs ||= Rails.application.config.database_configuration + .select { |k, v| k.to_s.start_with?('test') && v.is_a?(Hash) } end # Run rails +task_name+ for every configured test database. @@ -89,16 +77,12 @@ module MultiDbTests next end - Dir.mktmpdir('rails_test_') do |tmpdir| - tmp_yml = File.join(tmpdir, 'database.yml') - File.write(tmp_yml, non_test_configs.merge('test' => config).to_yaml) - env = { 'RAILS_DATABASE_YML' => tmp_yml } + env = { 'DATABASE_URL' => config_to_url(config) } - if system(env, 'bundle exec rails db:test:prepare') - results[db_name] = system(env, 'rails', task_name) ? :pass : :fail - else - results[db_name] = :prepare_failed - end + if system(env, 'bundle exec rails db:test:prepare') + results[db_name] = system(env, 'rails', task_name) ? :pass : :fail + else + results[db_name] = :prepare_failed end end @@ -110,6 +94,28 @@ module MultiDbTests private + # Build a DATABASE_URL string from a database.yml config hash. + # Rails merges DATABASE_URL on top of the test: entry, so adapter and + # connection details from the URL take precedence over the YAML file. + def config_to_url(config) + adapter = config['adapter'].to_s + database = config['database'].to_s + + return "sqlite3:#{database}" if adapter == 'sqlite3' + + user = config['username'] + pass = config['password'] + host = config['host'] || 'localhost' + port = config['port'] + socket = config['socket'] + + userinfo = user ? "#{URI.encode_www_form_component(user)}:#{URI.encode_www_form_component(pass.to_s)}@" : '' + hostport = port ? "#{host}:#{port}" : host + url = "#{adapter}://#{userinfo}#{hostport}/#{database}" + url += "?socket=#{URI.encode_www_form_component(socket)}" if socket + url + end + def adapter_available?(adapter) require ADAPTER_GEMS.fetch(adapter, adapter) true