diff --git a/.gitignore b/.gitignore index eba4eea..02961fb 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/README.md b/README.md index 62de50b..ee82bb7 100644 --- a/README.md +++ b/README.md @@ -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 ''; @@ -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/ diff --git a/config/database.yml.dist b/config/database.yml.dist index 5d079fe..25c80c4 100644 --- a/config/database.yml.dist +++ b/config/database.yml.dist @@ -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 diff --git a/db/schema.rb b/db/schema.rb index 3205384..9d97716 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -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 diff --git a/db/sqlite3_schema.rb b/db/sqlite3_schema.rb new file mode 100644 index 0000000..5002cdb --- /dev/null +++ b/db/sqlite3_schema.rb @@ -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 diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb index 4ba8106..e03481f 100644 --- a/test/application_system_test_case.rb +++ b/test/application_system_test_case.rb @@ -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 diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb index bda70d8..9097514 100644 --- a/test/controllers/users_controller_test.rb +++ b/test/controllers/users_controller_test.rb @@ -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) diff --git a/test/models/user_test.rb b/test/models/user_test.rb index 5c07f49..5a2150d 100644 --- a/test/models/user_test.rb +++ b/test/models/user_test.rb @@ -1,5 +1,6 @@ require "test_helper" +# TODO: remove model tests class UserTest < ActiveSupport::TestCase # test "the truth" do # assert true diff --git a/test/system/users_test.rb b/test/system/users_test.rb index b012bf4..5654a56 100644 --- a/test/system/users_test.rb +++ b/test/system/users_test.rb @@ -204,6 +204,7 @@ class UsersTest < ApplicationSystemTestCase test 'update profile' do # TODO + assert true end test 'update status' do