DEV: Add docker:test:setup Rake task (#23430)

## What is the context here?

The `docker.rake` Rakefile contains Rake tasks that are meant to be run
in the `discourse/discourse_test:release` Docker image. For example, we
have the `docker:test` Rake task that makes it easier to run the test
suite for a particular Discourse commit.

Why are we introducing a `docker:test:setup` Rake task?

While we have the `docker:test` Rake task, it is very limited in the
test commands that can be executed. It is very useful for automated
testing but not very useful for running tests in the development
environment. Therefore, we are introducing a `docker:test:setup` rake
task that can be used to set up the test environment for running tests.

The envisioned example usage is something like this:

```
docker run -d --name=discourse_test --entrypoint=/sbin/boot discourse/discourse_test:release
docker exec -u discourse:discourse discourse_test ruby script/docker_test.rb --no-tests
docker exec -u discourse:discourse discourse_test bundle exec rake docker:test:setup
docker exec -u discourse:discourse discourse_test bundle exec rspec <path to file>
```
This commit is contained in:
Alan Guo Xiang Tan 2023-09-07 13:46:23 +08:00 committed by GitHub
parent ad58b6d604
commit 9caba30d5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 111 additions and 70 deletions

View File

@ -1,8 +1,51 @@
# frozen_string_literal: true # frozen_string_literal: true
# rake docker:test is designed to be used inside the discourse/docker_test image # The Rake tasks in this file are designed to be used inside the `discourse/discourse_test:release` image.
# running it anywhere else will likely fail # Running it anywhere else is not supported.
#
def run_or_fail(command)
log(command)
pid = Process.spawn(command)
Process.wait(pid)
$?.exitstatus == 0
end
def log(message)
puts "[#{Time.now.strftime("%Y-%m-%d %H:%M:%S")}] #{message}"
end
def setup_postgres(skip_init:)
unless skip_init
log "Initializing postgres"
system("script/start_test_db.rb --skip-run", exception: true)
end
log "Starting postgres"
Process.spawn("script/start_test_db.rb --skip-setup --exec")
end
def setup_redis
log "Starting background redis"
data_directory = "#{Rails.root}/tmp/test_data/redis"
`rm -rf #{data_directory} && mkdir -p #{data_directory}`
Process.spawn("redis-server --dir #{data_directory} --port 1234")
end
def migrate_databases(parallel: false, load_plugins: false)
migrate_env = load_plugins ? "LOAD_PLUGINS=1" : "LOAD_PLUGINS=0"
success = run_or_fail("#{migrate_env} bundle exec rake db:migrate")
success &&= run_or_fail("#{migrate_env} bundle exec rake parallel:migrate") if parallel
success
end
desc "Setups up the test environment"
task "docker:test:setup" do
setup_redis
setup_postgres(skip_init: false)
migrate_databases(parallel: true, load_plugins: true)
end
# Environment Variables (specific to this rake task) # Environment Variables (specific to this rake task)
# => SKIP_LINT set to 1 to skip linting (eslint and rubocop) # => SKIP_LINT set to 1 to skip linting (eslint and rubocop)
# => SKIP_TESTS set to 1 to skip all tests # => SKIP_TESTS set to 1 to skip all tests
@ -33,30 +76,18 @@
# docker run -e SKIP_CORE=1 -v $(pwd)/my-awesome-plugin:/var/www/discourse/plugins/my-awesome-plugin discourse/discourse_test:release # docker run -e SKIP_CORE=1 -v $(pwd)/my-awesome-plugin:/var/www/discourse/plugins/my-awesome-plugin discourse/discourse_test:release
# Run tests for a specific plugin (with a plugin mounted from host filesystem): # Run tests for a specific plugin (with a plugin mounted from host filesystem):
# docker run -e SKIP_CORE=1 SINGLE_PLUGIN='my-awesome-plugin' -v $(pwd)/my-awesome-plugin:/var/www/discourse/plugins/my-awesome-plugin discourse/discourse_test:release # docker run -e SKIP_CORE=1 SINGLE_PLUGIN='my-awesome-plugin' -v $(pwd)/my-awesome-plugin:/var/www/discourse/plugins/my-awesome-plugin discourse/discourse_test:release
def run_or_fail(command)
log(command)
pid = Process.spawn(command)
Process.wait(pid)
$?.exitstatus == 0
end
def run_or_fail_prettier(*patterns)
if patterns.any? { |p| Dir[p].any? }
patterns = patterns.map { |p| "'#{p}'" }.join(" ")
run_or_fail("yarn pprettier --list-different #{patterns}")
else
puts "Skipping prettier. Pattern not found."
true
end
end
def log(message)
puts "[#{Time.now.strftime("%Y-%m-%d %H:%M:%S")}] #{message}"
end
desc "Run all tests (JS and code in a standalone environment)" desc "Run all tests (JS and code in a standalone environment)"
task "docker:test" do task "docker:test" do
def run_or_fail_prettier(*patterns)
if patterns.any? { |p| Dir[p].any? }
patterns = patterns.map { |p| "'#{p}'" }.join(" ")
run_or_fail("yarn pprettier --list-different #{patterns}")
else
puts "Skipping prettier. Pattern not found."
true
end
end
begin begin
@good = true @good = true
@good &&= run_or_fail("yarn install") @good &&= run_or_fail("yarn install")
@ -120,19 +151,8 @@ task "docker:test" do
end end
unless ENV["SKIP_TESTS"] unless ENV["SKIP_TESTS"]
puts "Cleaning up old test tmp data in tmp/test_data" @redis_pid = setup_redis
`rm -fr tmp/test_data && mkdir -p tmp/test_data/redis && mkdir tmp/test_data/pg` @pg_pid = setup_postgres(skip_init: ENV["SKIP_DB_CREATE"].present?)
puts "Starting background redis"
@redis_pid = Process.spawn("redis-server --dir tmp/test_data/redis")
unless ENV["SKIP_DB_CREATE"]
puts "Initializing postgres"
system("script/start_test_db.rb --skip-run", exception: true)
end
puts "Starting postgres"
@pg_pid = Process.spawn("script/start_test_db.rb --skip-setup --exec")
ENV["RAILS_ENV"] = "test" ENV["RAILS_ENV"] = "test"
# this shaves all the creation of the multisite db off # this shaves all the creation of the multisite db off
@ -159,19 +179,7 @@ task "docker:test" do
end end
end end
command_prefix = @good &&= migrate_databases(parallel: ENV["USE_TURBO"], load_plugins: !ENV["SKIP_PLUGINS"])
if ENV["SKIP_PLUGINS"]
# Make sure not to load plugins. bin/rake will add LOAD_PLUGINS=1 automatically unless we set it to 0 explicitly
"LOAD_PLUGINS=0 "
else
"LOAD_PLUGINS=1 "
end
@good &&= run_or_fail("#{command_prefix}bundle exec rake db:migrate")
if ENV["USE_TURBO"]
@good &&= run_or_fail("#{command_prefix}bundle exec rake parallel:migrate")
end
unless ENV["JS_ONLY"] unless ENV["JS_ONLY"]
if ENV["WARMUP_TMP_FOLDER"] if ENV["WARMUP_TMP_FOLDER"]

View File

@ -1,12 +1,44 @@
# frozen_string_literal: true # frozen_string_literal: true
# This script is run in the discourse_test docker image # This script is to be run in the `discourse/discourse_test:release` docker image.
# Available environment variables:
# => NO_UPDATE disables updating the source code within the discourse_test docker image require "optparse"
# => COMMIT_HASH used by the discourse_test docker image to load a specific commit of discourse
# this can also be set to a branch, e.g. "origin/tests-passed" options = {}
# => RUN_SMOKE_TESTS executes the smoke tests instead of the regular tests from docker.rake
# See lib/tasks/docker.rake and lib/tasks/smoke_test.rake for more information OptionParser
.new do |opts|
opts.banner = "Usage: ruby script/docker_test.rb [options]"
opts.on(
"--checkout-ref CHECKOUT_REF",
"Checks out the working tree to a specified commit hash or branch. If not specified, defaults to 'origin/tests-passed'.",
) { |v| options[:checkout_ref] = v }
opts.on(
"--run-smoke-tests",
"Executes the smoke tests instead of the regular tests from docker.rake. See lib/tasks/smoke_test.rake for more information.",
) { options[:run_smoke_tests] = true }
opts.on(
"--no-checkout",
"Does not check out the working tree when this option is passed. By default, the working tree is checked out to the latest commit on the 'origin/tests-passed' branch.",
) { options[:no_checkout] = true }
opts.on("--no-tests", "Does not execute any tests") { options[:no_tests] = true }
opts.on_tail("-h", "--help", "Displays usage information") do
puts opts
exit
end
end
.parse!
no_checkout = options.has_key?(:no_checkout) ? options[:no_checkout] : ENV["NO_UPDATE"]
checkout_ref = options.has_key?(:checkout_ref) ? options[:checkout_ref] : ENV["COMMIT_HASH"]
run_smoke_test =
options.has_key?(:run_smoke_test) ? options[:run_smoke_test] : ENV["RUN_SMOKE_TESTS"]
no_tests = options.has_key?(:no_tests) ? options[:no_tests] : false
def log(message) def log(message)
puts "[#{Time.now.strftime("%Y-%m-%d %H:%M:%S")}] #{message}" puts "[#{Time.now.strftime("%Y-%m-%d %H:%M:%S")}] #{message}"
@ -19,20 +51,19 @@ def run_or_fail(command)
exit 1 unless $?.exitstatus == 0 exit 1 unless $?.exitstatus == 0
end end
unless ENV["NO_UPDATE"] unless no_checkout
run_or_fail("git reset --hard") run_or_fail("git reset --hard")
run_or_fail("git fetch") run_or_fail("git fetch")
run_or_fail("LEFTHOOK=0 git checkout #{checkout_ref || "origin/tests-passed"}")
checkout = ENV["COMMIT_HASH"] || "origin/tests-passed"
run_or_fail("LEFTHOOK=0 git checkout #{checkout}")
run_or_fail("bundle") run_or_fail("bundle")
end end
log("Running tests") unless no_tests
if run_smoke_tests
if ENV["RUN_SMOKE_TESTS"] log("Running smoke tests")
run_or_fail("bundle exec rake smoke:test") run_or_fail("bundle exec rake smoke:test")
else else
run_or_fail("bundle exec rake docker:test") log("Running tests")
run_or_fail("bundle exec rake docker:test")
end
end end

View File

@ -24,6 +24,8 @@ while a = ARGV.pop
end end
if should_setup if should_setup
run "rm -rf #{DATA}"
run "mkdir -p #{DATA}"
run "#{BIN}/initdb -D #{DATA}" run "#{BIN}/initdb -D #{DATA}"
run "echo fsync = off >> #{DATA}/postgresql.conf" run "echo fsync = off >> #{DATA}/postgresql.conf"
@ -32,7 +34,7 @@ if should_setup
end end
if should_exec if should_exec
exec "#{BIN}/postmaster -D #{DATA}" exec "#{BIN}/postgres -D #{DATA}"
elsif should_run elsif should_run
run "#{BIN}/pg_ctl -D #{DATA} start" run "#{BIN}/pg_ctl -D #{DATA} start"
end end