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 running tests against different DB adapters #120

Merged
merged 1 commit into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 3 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Install SQLite3 Development Libraries
run: sudo apt-get update && sudo apt-get install -y libsqlite3-dev
run: sudo apt-get update && sudo apt-get install -y libsqlite3-dev docker-compose
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- name: Run the default task
run: bundle exec rake
- name: Run Tests with All Adapters
run: bundle exec rake test:all

rubocop:
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ GEM
zeitwerk (2.6.12)

PLATFORMS
arm64-darwin-22
arm64-darwin-23
x86_64-darwin-20
x86_64-darwin-22
Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,24 @@ To run tests with a specific version of Rails using Appraisal:
bundle exec appraisal rails.6.0 rake test TEST=test/rake_task_test.rb TESTOPTS="--name=/db::db:rollback_branches#test_0003_keeps/"
```

By default, `rake test` runs tests using `SQLite3`. To explicitly run tests with `SQLite3`, `PostgreSQL`, or `MySQL`, you can use the following tasks:
- Run tests with `SQLite3`:
```sh
bundle exec rake test:sqlite3
```
- Run tests with `PostgreSQL` (requires Docker):
```sh
bundle exec rake test:postgresql
```
- Run tests with `MySQL` (requires Docker):
```sh
bundle exec rake test:mysql2
```
- Run tests for all supported adapters:
```sh
bundle exec rake test:all
```

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/widefix/actual_db_schema. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/widefix/actual_db_schema/blob/master/CODE_OF_CONDUCT.md).
Expand Down
2 changes: 2 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
require "bundler/gem_tasks"
require "rake/testtask"

load "lib/tasks/test.rake"

Rake::TestTask.new(:test) do |t|
t.libs << "test"
t.libs << "lib"
Expand Down
23 changes: 23 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
version: '3.8'

services:
postgres:
image: postgres:14
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: actual_db_schema_test
ports:
- "5432:5432"
volumes:
- ./docker/postgres-init:/docker-entrypoint-initdb.d

mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: actual_db_schema_test
ports:
- "3306:3306"
volumes:
- ./docker/mysql-init:/docker-entrypoint-initdb.d
1 change: 1 addition & 0 deletions docker/mysql-init/create_secondary_db.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CREATE DATABASE actual_db_schema_test_secondary;
1 change: 1 addition & 0 deletions docker/postgres-init/create_secondary_db.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CREATE DATABASE actual_db_schema_test_secondary;
2 changes: 2 additions & 0 deletions gemfiles/rails.6.0.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ source "https://rubygems.org"
gem "activerecord", "~> 6.0.0"
gem "activesupport", "~> 6.0.0"
gem "minitest", "~> 5.0"
gem "mysql2", "~> 0.5.2"
gem "pg", "~> 1.5"
gem "rake"
gem "rubocop", "~> 1.21"
gem "sqlite3", "~> 1.4.0"
Expand Down
2 changes: 2 additions & 0 deletions gemfiles/rails.6.1.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ source "https://rubygems.org"
gem "activerecord", "~> 6.1.0"
gem "activesupport", "~> 6.1.0"
gem "minitest", "~> 5.0"
gem "mysql2", "~> 0.5.2"
gem "pg", "~> 1.5"
gem "rake"
gem "rubocop", "~> 1.21"
gem "sqlite3", "~> 1.4.0"
Expand Down
2 changes: 2 additions & 0 deletions gemfiles/rails.7.0.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ source "https://rubygems.org"
gem "activerecord", "~> 7.0.0"
gem "activesupport", "~> 7.0.0"
gem "minitest", "~> 5.0"
gem "mysql2", "~> 0.5.2"
gem "pg", "~> 1.5"
gem "rake"
gem "rubocop", "~> 1.21"
gem "sqlite3", "~> 1.4.0"
Expand Down
2 changes: 2 additions & 0 deletions gemfiles/rails.7.1.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ source "https://rubygems.org"
gem "activerecord", "~> 7.1.0"
gem "activesupport", "~> 7.1.0"
gem "minitest", "~> 5.0"
gem "mysql2", "~> 0.5.2"
gem "pg", "~> 1.5"
gem "rake"
gem "rubocop", "~> 1.21"
gem "sqlite3", "~> 1.4.0"
Expand Down
2 changes: 2 additions & 0 deletions gemfiles/rails.edge.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ source "https://rubygems.org"
gem "activerecord", ">= 7.2.0.beta"
gem "activesupport", ">= 7.2.0.beta"
gem "minitest", "~> 5.0"
gem "mysql2", "~> 0.5.2"
gem "pg", "~> 1.5"
gem "rake"
gem "rubocop", "~> 1.21"
gem "rails", ">= 7.2.0.beta"
Expand Down
11 changes: 10 additions & 1 deletion lib/actual_db_schema/patches/migration_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def handle_rollback_error(migration, exception)
error_message = <<~ERROR
Error encountered during rollback:

#{exception.message.gsub(/^An error has occurred, all later migrations canceled:\s*/, "").strip}
#{cleaned_exception_message(exception.message)}
ERROR

puts colorize(error_message, :red)
Expand All @@ -118,6 +118,15 @@ def handle_rollback_error(migration, exception)
branch: branch_for(migration.version.to_s)
)
end

def cleaned_exception_message(message)
patterns_to_remove = [
/^An error has occurred, all later migrations canceled:\s*/,
/^An error has occurred, this and all later migrations canceled:\s*/
]

patterns_to_remove.reduce(message.strip) { |msg, pattern| msg.gsub(pattern, "").strip }
end
end
end
end
69 changes: 69 additions & 0 deletions lib/tasks/test.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# frozen_string_literal: true

namespace :test do # rubocop:disable Metrics/BlockLength
desc "Run tests with SQLite3"
task :sqlite3 do
ENV["DB_ADAPTER"] = "sqlite3"
Rake::Task["test"].invoke
Rake::Task["test"].reenable
end

desc "Run tests with PostgreSQL"
task :postgresql do
sh "docker-compose up -d postgres"
wait_for_postgres

begin
ENV["DB_ADAPTER"] = "postgresql"
Rake::Task["test"].invoke
Rake::Task["test"].reenable
ensure
sh "docker-compose down"
end
end

desc "Run tests with MySQL"
task :mysql2 do
sh "docker-compose up -d mysql"
wait_for_mysql

begin
ENV["DB_ADAPTER"] = "mysql2"
Rake::Task["test"].invoke
Rake::Task["test"].reenable
ensure
sh "docker-compose down"
end
end

desc "Run tests with all adapters (SQLite3, PostgreSQL, MySQL)"
task all: %i[sqlite3 postgresql mysql2]

def wait_for_postgres
retries = 10
begin
sh "docker-compose exec -T postgres pg_isready -U postgres"
rescue StandardError
retries -= 1

raise "PostgreSQL is not ready after several attempts." if retries < 1

sleep 2
retry
end
end

def wait_for_mysql
retries = 10
begin
sh "docker-compose exec -T mysql mysqladmin ping -h 127.0.0.1 --silent"
rescue StandardError
retries -= 1

raise "MySQL is not ready after several attempts." if retries < 1

sleep 2
retry
end
end
end
25 changes: 15 additions & 10 deletions test/controllers/actual_db_schema/migrations_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,35 +44,35 @@ def active_record_setup
assert_select "td", text: "20130906111511"
assert_select "td", text: "FirstPrimary"
assert_select "td", text: @utils.branch_for("20130906111511")
assert_select "td", text: "tmp/primary.sqlite3"
assert_select "td", text: @utils.primary_database
end
assert_select "tr" do
assert_select "td", text: "up"
assert_select "td", text: "20130906111512"
assert_select "td", text: "SecondPrimary"
assert_select "td", text: @utils.branch_for("20130906111512")
assert_select "td", text: "tmp/primary.sqlite3"
assert_select "td", text: @utils.primary_database
end
assert_select "tr" do
assert_select "td", text: "up"
assert_select "td", text: "20130906111514"
assert_select "td", text: "FirstSecondary"
assert_select "td", text: @utils.branch_for("20130906111514")
assert_select "td", text: "tmp/secondary.sqlite3"
assert_select "td", text: @utils.secondary_database
end
assert_select "tr" do
assert_select "td", text: "up"
assert_select "td", text: "20130906111515"
assert_select "td", text: "SecondSecondary"
assert_select "td", text: @utils.branch_for("20130906111515")
assert_select "td", text: "tmp/secondary.sqlite3"
assert_select "td", text: @utils.secondary_database
end
end
end
end

test "GET #show returns a successful response" do
get :show, params: { id: "20130906111511", database: "tmp/primary.sqlite3" }
get :show, params: { id: "20130906111511", database: @utils.primary_database }
assert_response :success
assert_select "h2", text: "Migration FirstPrimary Details"
assert_select "table" do
Expand All @@ -86,7 +86,7 @@ def active_record_setup
end
assert_select "tr" do
assert_select "th", text: "Database"
assert_select "td", text: "tmp/primary.sqlite3"
assert_select "td", text: @utils.primary_database
end
assert_select "tr" do
assert_select "th", text: "Branch"
Expand All @@ -96,7 +96,7 @@ def active_record_setup
end

test "GET #show returns a 404 response if migration not found" do
get :show, params: { id: "nil", database: "tmp/primary.sqlite3" }
get :show, params: { id: "nil", database: @utils.primary_database }
assert_response :not_found
end

Expand All @@ -115,15 +115,20 @@ def down
RUBY
end
@utils.prepare_phantom_migrations(TestingState.db_config)
post :rollback, params: { id: "20130906111513", database: "tmp/primary.sqlite3" }
post :rollback, params: { id: "20130906111513", database: @utils.primary_database }
assert_response :redirect
get :index
message = "An error has occurred, this and all later migrations canceled:\n\nActiveRecord::IrreversibleMigration"
message = if ENV["DB_ADAPTER"] == "mysql2"
"An error has occurred, all later migrations canceled:\n\nActiveRecord::IrreversibleMigration"
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"An error has occurred, all later migrations canceled:\n\nActiveRecord::IrreversibleMigration"
"An error has occurred, all subsequent migrations have been canceled:\n\nActiveRecord::IrreversibleMigration"

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The error message is generated by Rails and is specific to the database adapter. For MySQL the message is An error has occurred, all subsequent migrations have been canceled, while for other adapters (PostgreSQL, SQLite) it's An error has occurred, this and all later migrations canceled. Making the suggested change would cause the test to fail for the MySQL adapter.

else
"An error has occurred, this and all later migrations canceled:\n\n" \
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"An error has occurred, this and all later migrations canceled:\n\n" \
"An error has occurred; this migration and all subsequent ones have been canceled:\n\n" \

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Same as here

"ActiveRecord::IrreversibleMigration"
end
assert_select ".flash", text: message
end

test "POST #rollback changes migration status to down and hide migration with down status" do
post :rollback, params: { id: "20130906111511", database: "tmp/primary.sqlite3" }
post :rollback, params: { id: "20130906111511", database: @utils.primary_database }
assert_response :redirect
get :index
assert_select "table" do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,28 +51,28 @@ def active_record_setup
assert_select "td", text: "20130906111511"
assert_select "td", text: "FirstPrimary"
assert_select "td", text: @utils.branch_for("20130906111511")
assert_select "td", text: "tmp/primary.sqlite3"
assert_select "td", text: @utils.primary_database
end
assert_select "tr" do
assert_select "td", text: "up"
assert_select "td", text: "20130906111512"
assert_select "td", text: "SecondPrimary"
assert_select "td", text: @utils.branch_for("20130906111512")
assert_select "td", text: "tmp/primary.sqlite3"
assert_select "td", text: @utils.primary_database
end
assert_select "tr" do
assert_select "td", text: "up"
assert_select "td", text: "20130906111514"
assert_select "td", text: "FirstSecondary"
assert_select "td", text: @utils.branch_for("20130906111514")
assert_select "td", text: "tmp/secondary.sqlite3"
assert_select "td", text: @utils.secondary_database
end
assert_select "tr" do
assert_select "td", text: "up"
assert_select "td", text: "20130906111515"
assert_select "td", text: "SecondSecondary"
assert_select "td", text: @utils.branch_for("20130906111515")
assert_select "td", text: "tmp/secondary.sqlite3"
assert_select "td", text: @utils.secondary_database
end
end
end
Expand All @@ -86,7 +86,7 @@ def active_record_setup
end

test "GET #show returns a successful response" do
get :show, params: { id: "20130906111511", database: "tmp/primary.sqlite3" }
get :show, params: { id: "20130906111511", database: @utils.primary_database }
assert_response :success
assert_select "h2", text: "Phantom Migration FirstPrimary Details"
assert_select "table" do
Expand All @@ -100,7 +100,7 @@ def active_record_setup
end
assert_select "tr" do
assert_select "th", text: "Database"
assert_select "td", text: "tmp/primary.sqlite3"
assert_select "td", text: @utils.primary_database
end
assert_select "tr" do
assert_select "th", text: "Branch"
Expand All @@ -110,12 +110,12 @@ def active_record_setup
end

test "GET #show returns a 404 response if migration not found" do
get :show, params: { id: "nil", database: "tmp/primary.sqlite3" }
get :show, params: { id: "nil", database: @utils.primary_database }
assert_response :not_found
end

test "POST #rollback changes migration status to down and hide migration with down status" do
post :rollback, params: { id: "20130906111511", database: "tmp/primary.sqlite3" }
post :rollback, params: { id: "20130906111511", database: @utils.primary_database }
assert_response :redirect
get :index
assert_select "table" do
Expand Down Expand Up @@ -151,10 +151,15 @@ def down
RUBY
end
@utils.prepare_phantom_migrations(TestingState.db_config)
post :rollback, params: { id: "20130906111513", database: "tmp/primary.sqlite3" }
post :rollback, params: { id: "20130906111513", database: @utils.primary_database }
assert_response :redirect
get :index
message = "An error has occurred, this and all later migrations canceled:\n\nActiveRecord::IrreversibleMigration"
message = if ENV["DB_ADAPTER"] == "mysql2"
"An error has occurred, all later migrations canceled:\n\nActiveRecord::IrreversibleMigration"
else
"An error has occurred, this and all later migrations canceled:\n\n" \
"ActiveRecord::IrreversibleMigration"
end
assert_select ".flash", text: message
end

Expand Down
Loading
Loading