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

Add support for multiple DBs in Rails >= 6.1 #930

Merged
merged 7 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Breaking Changes

### Added
- Support for running tasks against individual databases in a multi-database setup with Rails >= 6.1 ([#930](https://github.com/grosser/parallel_tests/pull/930))

## 4.4.0 - 2023-12-24

Expand Down
10 changes: 10 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,28 @@ test:
### Create additional database(s)
rake parallel:create
### (Multi-DB) Create individual database
rake parallel:create:<database>
rake parallel:create:secondary
### Copy development schema (repeat after migrations)
rake parallel:prepare
### Run migrations in additional database(s) (repeat after migrations)
rake parallel:migrate
### (Multi-DB) Run migrations in individual database
rake parallel:migrate:<database>
### Setup environment from scratch (create db and loads schema, useful for CI)
rake parallel:setup
### Drop all test databases
rake parallel:drop
### (Multi-DB) Drop individual test database
rake parallel:drop:<database>
### Run!
rake parallel:test # Minitest
rake parallel:spec # RSpec
Expand Down
130 changes: 97 additions & 33 deletions lib/parallel_tests/tasks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ def suppress_output(command, ignore_regex)
activate_pipefail = "set -o pipefail"
remove_ignored_lines = %{(grep -v #{Shellwords.escape(ignore_regex)} || true)}

# remove nil values (ex: #purge_before_load returns nil)
command.compact!

if system('/bin/bash', '-c', "#{activate_pipefail} 2>/dev/null")
shell_command = "#{activate_pipefail} && (#{Shellwords.shelljoin(command)}) | #{remove_ignored_lines}"
['/bin/bash', '-c', shell_command]
Expand Down Expand Up @@ -125,6 +128,23 @@ def build_run_command(type, args)
command
end

def configured_databases
return [] unless defined?(ActiveRecord) && rails_61_or_greater?

@@configured_databases ||= ActiveRecord::Tasks::DatabaseTasks.setup_initial_database_yaml
end

def for_each_database(&block)
return unless defined?(ActiveRecord)

# Use nil to represent all databases
block&.call(nil)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be after this to preserve original behavior ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh gosh, nice catch 😄 0f8e6a8


ActiveRecord::Tasks::DatabaseTasks.for_each(configured_databases) do |name|
block&.call(name)
end
end

private

def rails_7_or_greater?
Expand All @@ -145,25 +165,45 @@ def rails_61_or_greater?
ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
end

desc "Create test databases via db:create --> parallel:create[num_cpus]"
task :create, :count do |_, args|
ParallelTests::Tasks.run_in_parallel(
[$0, "db:create", "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"],
args
)
ParallelTests::Tasks.for_each_database do |name|
task_name = 'create'
task_name += ":#{name}" if name
description = if name
"Create test #{name} database via db:#{task_name} --> parallel:#{task_name}[num_cpus]"
else
"Create test databases via db:#{task_name} --> parallel:#{task_name}[num_cpus]"
end

desc description
task task_name.to_sym, :count do |_, args|
ParallelTests::Tasks.run_in_parallel(
[$0, "db:#{task_name}", "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"],
args
)
end
end

desc "Drop test databases via db:drop --> parallel:drop[num_cpus]"
task :drop, :count do |_, args|
ParallelTests::Tasks.run_in_parallel(
[
$0,
"db:drop",
"RAILS_ENV=#{ParallelTests::Tasks.rails_env}",
"DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
],
args
)
ParallelTests::Tasks.for_each_database do |name|
task_name = 'drop'
task_name += ":#{name}" if name
description = if name
"Drop test #{name} database via db:#{task_name} --> parallel:#{task_name}[num_cpus]"
else
"Drop test databases via db:#{task_name} --> parallel:#{task_name}[num_cpus]"
end

desc description
task task_name.to_sym, :count do |_, args|
ParallelTests::Tasks.run_in_parallel(
[
$0,
"db:#{task_name}",
"RAILS_ENV=#{ParallelTests::Tasks.rails_env}",
"DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
],
args
)
end
end

desc "Update test databases by dumping and loading --> parallel:prepare[num_cpus]"
Expand All @@ -190,12 +230,22 @@ def rails_61_or_greater?
end

# when dumping/resetting takes too long
desc "Update test databases via db:migrate --> parallel:migrate[num_cpus]"
task :migrate, :count do |_, args|
ParallelTests::Tasks.run_in_parallel(
[$0, "db:migrate", "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"],
args
)
ParallelTests::Tasks.for_each_database do |name|
task_name = 'migrate'
task_name += ":#{name}" if name
description = if name
"Update test #{name} database via db:#{task_name} --> parallel:#{task_name}[num_cpus]"
else
"Update test databases via db:#{task_name} --> parallel:#{task_name}[num_cpus]"
end

desc description
task task_name.to_sym, :count do |_, args|
ParallelTests::Tasks.run_in_parallel(
[$0, "db:#{task_name}", "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"],
args
)
end
end

desc "Rollback test databases via db:rollback --> parallel:rollback[num_cpus]"
Expand All @@ -207,16 +257,30 @@ def rails_61_or_greater?
end

# just load the schema (good for integration server <-> no development db)
desc "Load dumped schema for test databases via db:schema:load --> parallel:load_schema[num_cpus]"
task :load_schema, :count do |_, args|
command = [
$0,
ParallelTests::Tasks.purge_before_load,
"db:schema:load",
"RAILS_ENV=#{ParallelTests::Tasks.rails_env}",
"DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
]
ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
ParallelTests::Tasks.for_each_database do |name|
rails_task = 'db:schema:load'
rails_task += ":#{name}" if name

task_name = 'load_schema'
task_name += ":#{name}" if name

description = if name
"Load dumped schema for test #{name} database via #{rails_task} --> parallel:#{task_name}[num_cpus]"
else
"Load dumped schema for test databases via #{rails_task} --> parallel:#{task_name}[num_cpus]"
end

desc description
task task_name.to_sym, :count do |_, args|
command = [
$0,
ParallelTests::Tasks.purge_before_load,
rails_task,
"RAILS_ENV=#{ParallelTests::Tasks.rails_env}",
"DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
]
ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
end
end

# load the structure from the structure.sql file
Expand Down