Last active
July 28, 2024 12:08
-
-
Save alexcastrodev/5657332d6d8a32a179a51b9dca3b7330 to your computer and use it in GitHub Desktop.
parallel rake rspec
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
namespace :tests do | |
desc "Create multiple test databases, load schema, seed data, and run RSpec tests in parallel" | |
task :parallel, [:quantity] => :environment do |t, args| | |
quantity = args[:quantity].to_i | |
raise ArgumentError, "Please provide a valid quantity greater than 0." if quantity <= 0 | |
test_config = ActiveRecord::Base.configurations.configurations.find { |config| config.env_name == 'test' } | |
raise "Test configuration not found." if test_config.nil? | |
errors = [] | |
db_names = [] | |
quantity.times do |i| | |
db_name = "test_#{SecureRandom.hex(4)}_#{i}" | |
db_names << db_name | |
config = test_config.configuration_hash.deep_dup | |
config['database'] = db_name | |
begin | |
ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public')) | |
ActiveRecord::Base.connection.drop_database(config['database']) rescue nil | |
ActiveRecord::Base.connection.create_database(config['database']) | |
ActiveRecord::Base.establish_connection(config) | |
system("DATABASE_URL=#{get_database_url(config, db_name)} rails db:schema:load --trace") | |
system("rails db:seed") | |
rescue ActiveRecord::StatementInvalid => e | |
errors << e.message | |
end | |
end | |
unless errors.empty? | |
drop_databases(db_names) | |
raise errors.join("\n") | |
end | |
test_files = Dir.glob("spec/**/*_spec.rb") | |
files_per_db = (test_files.size / quantity.to_f).ceil | |
Parallel.each_with_index(db_names, in_threads: quantity) do |db_name, index| | |
config = test_config.configuration_hash.deep_dup | |
config['database'] = db_name | |
files_to_run = test_files.slice(index * files_per_db, files_per_db) | |
next if files_to_run.nil? || files_to_run.empty? | |
thread_config = config.dup | |
thread_config['database'] = db_name | |
database_url = get_database_url(thread_config, db_name) | |
puts "Running tests for #{db_name}... in #{database_url}" | |
ActiveRecord::Base.establish_connection(thread_config) | |
system("DATABASE_URL=#{database_url} rspec #{files_to_run.join(' ')} --fail-fast --format documentation") | |
end | |
drop_databases(db_names) | |
end | |
private | |
def get_database_url(config, db_name = nil) | |
"#{config[:adapter]}://#{config[:username]}:#{config[:password]}@#{config[:host]}/#{db_name || config[:database]}" | |
end | |
def drop_databases(db_names) | |
test_config = ActiveRecord::Base.configurations.configurations.find { |config| config.env_name == 'test' } | |
db_names.each do |db_name| | |
ActiveRecord::Base.establish_connection(test_config.configuration_hash.merge('database' => db_name)) | |
ActiveRecord::Base.connection.drop_database(db_name) rescue nil | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment