Run tests on multiple database configurations

This commit is contained in:
2026-04-27 17:38:49 +02:00
parent 3ac3a6f13c
commit dedea0246f
9 changed files with 167 additions and 21 deletions

6
.gitignore vendored
View File

@@ -15,6 +15,9 @@
/config/master.key
/config/puma.rb
# Ignore test database.
/db/test.sqlite3
# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
@@ -30,7 +33,7 @@
/tmp/restart.txt
# Ignore user files
# Ignore user files.
/.bash_history
/.byebug_history
/.config
@@ -38,6 +41,7 @@
/.lesshst
/.local
/.mysql_history
/.sqlite_history
/.ssh
/.vim
/.viminfo

View File

@@ -119,9 +119,10 @@ Contributing
### Gems
Apart from database adapter, install development and testing gems:
Install development and testing gems, including at least MySQL and SQLite
database adapters:
bundle config --local with mysql development test
bundle config --local with development test mysql sqlite
### Configuration
@@ -134,8 +135,9 @@ assets.
### Database
Grant database user privileges for development and test environments,
possibly with different Ruby versions:
Grant database user privileges for development and test environments. Example
below shows how to grant privileges to all databases which names start with
`fixinme-` on MySQL:
> mysql -p
mysql> create user `fixinme-dev`@localhost identified by '<some password>';
@@ -148,6 +150,10 @@ Starting application server in development environment:
bundle exec rails s -e development
Accessing database console when more than one test db is present:
bundle exec rails dbconsole -e test --db sqlite3
For running rake tasks, prepend command with environment:
RAILS_ENV=development bundle exec rails ...
@@ -160,14 +166,22 @@ Tests need to be run from within toplevel application directory:
bundle exec rails test:system
* system test(s) with seed/test name specified:
* system test(s) with seed or test name specified:
bundle exec rails test:system --seed 64690 --name test_add_unit
bundle exec rails test:system --include test_add_unit --seed 64690
* all tests from one file, with optional seed:
* all tests from one file, optionally with seed:
bundle exec rails test test/system/users_test.rb --seed 1234
* system tests for selected database configuration (if multiple present):
bundle exec rails test:system --include /^test_sqlite3_/
* single system test for all database configurations (if multiple present):
bundle exec rails test:system --include /^test_\\w+_add_unit$/
### Icons
Pictogrammers Material Design Icons: https://pictogrammers.com/library/mdi/

View File

@@ -24,27 +24,45 @@
# Read https://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full overview on how database connection configuration can be specified.
default: &default
adapter: mysql2
encoding: utf8mb4
collation: utf8mb4_0900_as_ci
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: fixinme
password: Some-password1%
socket: /run/mysqld/mysqld.sock
pool: <%= ENV.fetch('RAILS_MAX_THREADS', 3) %>
#mysql_default: &mysql_default
# <<: *default
# username: fixinme
# password: Some-password1%
# host: 127.0.0.1
# encoding: utf8mb4
# collation: utf8mb4_0900_as_ci
production:
<<: *default
database: fixinme
adapter: sqlite3
database: db/production.sqlite3
# Unless you're planning on developing the application, you can skip
# Unless you're planning on developing the application, you can skip/remove
# configurations for development and test databases altogether.
#development:
# <<: *default
# <<: *mysql_default
# adapter: mysql2
# database: fixinme_dev
# Warning: The database defined as "test" will be erased and
# Warning: The database(s) defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
#test:
# <<: *default
# <<: *mysql_default
# adapter: mysql2
# database: fixinme_test
# Multiple test databases can be provided. When more than one test db is
# present, every test task (test, test:models, test:system, etc.) runs against
# all of them.
#test:
# mysql2:
# <<: *mysql_default
# adapter: mysql2
# database: fixinme_test
# sqlite3:
# <<: *default
# adapter: sqlite3
# database: db/test.sqlite3

View File

@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.2].define(version: 2025_01_21_230456) do
ActiveRecord::Schema[8.0].define(version: 2025_01_21_230456) do
create_table "quantities", charset: "utf8mb4", collation: "utf8mb4_0900_as_ci", force: :cascade do |t|
t.bigint "user_id"
t.string "name", limit: 31, null: false

80
db/sqlite3_schema.rb Normal file
View File

@@ -0,0 +1,80 @@
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# This file is the source Rails uses to define your schema when running `bin/rails
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
# be faster and is potentially less error prone than running all of your
# migrations from scratch. Old migrations may fail to apply correctly if those
# migrations use external dependencies or application code.
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.0].define(version: 2025_01_21_230456) do
create_table "quantities", force: :cascade do |t|
t.integer "user_id"
t.string "name", limit: 31, null: false
t.text "description"
t.integer "parent_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "depth", default: 0, null: false
t.string "pathname", limit: 511, null: false
t.index ["parent_id"], name: "index_quantities_on_parent_id"
t.index ["user_id", "parent_id", "name"], name: "index_quantities_on_user_id_and_parent_id_and_name", unique: true
t.index ["user_id"], name: "index_quantities_on_user_id"
end
create_table "readouts", force: :cascade do |t|
t.integer "user_id", null: false
t.integer "quantity_id", null: false
t.integer "category", default: 0, null: false
t.float "value", limit: 53, null: false
t.integer "unit_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["quantity_id", "created_at"], name: "index_readouts_on_quantity_id_and_created_at", unique: true
t.index ["quantity_id"], name: "index_readouts_on_quantity_id"
t.index ["unit_id"], name: "index_readouts_on_unit_id"
t.index ["user_id"], name: "index_readouts_on_user_id"
end
create_table "units", force: :cascade do |t|
t.integer "user_id"
t.string "symbol", limit: 15, null: false
t.text "description"
t.decimal "multiplier", precision: 30, scale: 15, default: "1.0", null: false
t.integer "base_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["base_id"], name: "index_units_on_base_id"
t.index ["user_id", "symbol"], name: "index_units_on_user_id_and_symbol", unique: true
t.index ["user_id"], name: "index_units_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "email", limit: 64, null: false
t.integer "status", default: 0, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email", limit: 64
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
add_foreign_key "quantities", "quantities", column: "parent_id", on_delete: :cascade
add_foreign_key "quantities", "users"
add_foreign_key "readouts", "quantities"
add_foreign_key "readouts", "units"
add_foreign_key "readouts", "users"
add_foreign_key "units", "units", column: "base_id", on_delete: :cascade
add_foreign_key "units", "users"
end

View File

@@ -39,6 +39,32 @@ class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
end
alias :t :translate
DB_CONFIGS = ActiveRecord::Base.configurations.configs_for(env_name: "test")
TEST_CONFIGS = Hash.new(DB_CONFIGS.first.name.to_sym)
class << self
# NOTE: alternative to current solution is to create shards:
# ActiveRecord::Base.connects_to(
# shards: {mysql2: {writing: :mysql2}, sqlite3: {writing: :sqlite3}}
# )
# and use them in one of the following ways:
# * set config.active_record.shard_selector/shard_resolver
# * run tests within: ActiveRecord::Base.connected_to(shard: :sqlite3) { test_ }
# Remove this note once current solution is confirmed to work.
#
# Test block should not be modified here, as it would change its binding from
# instance level to class level.
if DB_CONFIGS.many?
def test(name, ...)
DB_CONFIGS.each do |config|
TEST_CONFIGS[super("#{config.name} #{name}", ...)] = config.name.to_sym
end
end
end
end
setup do
ActiveRecord::Base.establish_connection(TEST_CONFIGS[name.to_sym])
end
#def assert_stale(element)
# assert_raises(Selenium::WebDriver::Error::StaleElementReferenceError) { element.tag_name }
#end

View File

@@ -1,5 +1,7 @@
require "test_helper"
# TODO: make sure tested actions are covered by system tests and remove all
# controller tests.
class UsersControllerTest < ActionDispatch::IntegrationTest
setup do
@user = users(:one)

View File

@@ -1,5 +1,6 @@
require "test_helper"
# TODO: remove model tests
class UserTest < ActiveSupport::TestCase
# test "the truth" do
# assert true

View File

@@ -204,6 +204,7 @@ class UsersTest < ApplicationSystemTestCase
test 'update profile' do
# TODO
assert true
end
test 'update status' do