From 27743717a4941b26a0e2eb40ce495f460231a079 Mon Sep 17 00:00:00 2001 From: JonJagger Date: Thu, 21 May 2026 05:47:23 +0100 Subject: [PATCH] Fix Docker cleanup, extract slow-tests reporter, set Puma workers to nprocessors containers_down now force-removes all containers across all projects, so ports held by containers from other compose projects (e.g. saver from cyber-dojo/web) no longer block test runs. run_tests.sh calls containers_down at startup so 'make test_server' is self-contained. Slow-test timing extracted into a dedicated SlowTestsReporter class, matching the pattern already used in cyber-dojo/saver. Puma configured to spawn one worker per CPU core via Etc.nprocessors. Co-Authored-By: Claude Sonnet 4.6 --- bin/lib.sh | 9 +++++++-- bin/run_tests.sh | 1 + source/server/config/puma.rb | 2 ++ test/client/lib/coverage_metrics_limits.rb | 2 +- test/client/lib/id58_test_base.rb | 21 ++++----------------- test/client/lib/slow_tests_reporter.rb | 20 ++++++++++++++++++++ test/server/lib/coverage_metrics_limits.rb | 2 +- test/server/lib/id58_test_base.rb | 21 ++++----------------- test/server/lib/slow_tests_reporter.rb | 20 ++++++++++++++++++++ 9 files changed, 60 insertions(+), 38 deletions(-) create mode 100644 test/client/lib/slow_tests_reporter.rb create mode 100644 test/server/lib/slow_tests_reporter.rb diff --git a/bin/lib.sh b/bin/lib.sh index 238f2fde..6a792299 100644 --- a/bin/lib.sh +++ b/bin/lib.sh @@ -50,7 +50,11 @@ copy_in_saver_test_data() containers_down() { - docker compose down --remove-orphans --volumes + local -r all=$(docker ps --all --quiet) + if [ -n "${all}" ]; then + # shellcheck disable=SC2086 + docker rm --force ${all} + fi } echo_warnings() @@ -95,10 +99,11 @@ remove_all_but_latest() # Keep latest in the cache local -r docker_image_ls="${1}" local -r name="${2}" + docker container prune --force for image_name in $(echo "${docker_image_ls}" | grep "${name}:") do if [ "${image_name}" != "${name}:latest" ]; then - docker image rm "${image_name}" + docker image rm --force "${image_name}" fi done docker system prune --force diff --git a/bin/run_tests.sh b/bin/run_tests.sh index 182e0eb8..87987ed2 100755 --- a/bin/run_tests.sh +++ b/bin/run_tests.sh @@ -64,6 +64,7 @@ check_args() run_tests() { check_args "$@" + containers_down local -r TYPE="${1}" # {server|client} local -r TEST_LOG=test.log diff --git a/source/server/config/puma.rb b/source/server/config/puma.rb index ae91e4c5..587521ff 100755 --- a/source/server/config/puma.rb +++ b/source/server/config/puma.rb @@ -1,4 +1,6 @@ #!/usr/bin/env puma +require 'etc' environment('production') rackup("#{__dir__}/config.ru") +workers(Etc.nprocessors) diff --git a/test/client/lib/coverage_metrics_limits.rb b/test/client/lib/coverage_metrics_limits.rb index d2011cc7..e4b1cc63 100644 --- a/test/client/lib/coverage_metrics_limits.rb +++ b/test/client/lib/coverage_metrics_limits.rb @@ -1,7 +1,7 @@ def metrics [ [ nil ], - [ 'test.lines.total' , '<=', 230 ], + [ 'test.lines.total' , '<=', 243 ], [ 'test.lines.missed' , '<=', 0 ], [ 'test.branches.total' , '<=', 0 ], [ 'test.branches.missed', '<=', 0 ], diff --git a/test/client/lib/id58_test_base.rb b/test/client/lib/id58_test_base.rb index 46bd91ac..880500f8 100644 --- a/test/client/lib/id58_test_base.rb +++ b/test/client/lib/id58_test_base.rb @@ -3,13 +3,15 @@ require 'minitest/autorun' require 'minitest/reporters' require_relative 'slim_json_reporter' +require_relative 'slow_tests_reporter' Minitest.parallel_executor = Minitest::Parallel::Executor.new(Etc.nprocessors) reporters = [ Minitest::Reporters::DefaultReporter.new, Minitest::Reporters::SlimJsonReporter.new, - Minitest::Reporters::JUnitReporter.new("#{ENV.fetch('COVERAGE_ROOT')}/junit") + Minitest::Reporters::JUnitReporter.new("#{ENV.fetch('COVERAGE_ROOT')}/junit"), + Minitest::Reporters::SlowTestsReporter.new ] Minitest::Reporters.use!(reporters) @@ -28,8 +30,6 @@ def initialize(arg) @@args = (ARGV.sort.uniq - ['--']) # eg 2m4 @@seen_ids = [] - @@timings = {} - TIMINGS_LOCK = Mutex.new def self.test(id58, *lines, &test_block) src = test_block.source_location @@ -47,7 +47,7 @@ def self.test(id58, *lines, &test_block) t1 = Time.now instance_eval(&test_block) t2 = Time.now - TIMINGS_LOCK.synchronize { @@timings["#{id58}:#{src_file}:#{src_line}:#{name58}"] = (t2 - t1) } + SlowTestsTimings::LOCK.synchronize { SlowTestsTimings::TIMINGS["#{id58}:#{src_file}:#{src_line}:#{name58}"] = (t2 - t1) } ensure puts $ERROR_INFO.message unless $ERROR_INFO.nil? id58_teardown @@ -57,19 +57,6 @@ def self.test(id58, *lines, &test_block) define_method("test_\n#{name}".to_sym, &execute_around) end - Minitest.after_run do - slow = @@timings.select { |_name, secs| secs > 0.000 } - sorted = slow.sort_by { |_name, secs| -secs }.to_h - size = [sorted.size, 5].min - puts - puts 'Slowest tests are...' unless sorted.empty? - sorted.each_with_index do |(name, secs), index| - puts format('%3.4f - %-72s', secs, name) - break if index == size - end - puts - end - ID58_ALPHABET = %w[ 0 1 2 3 4 5 6 7 8 9 A B C D E F G H J K L M N P Q R S T U V W X Y Z diff --git a/test/client/lib/slow_tests_reporter.rb b/test/client/lib/slow_tests_reporter.rb new file mode 100644 index 00000000..3da17760 --- /dev/null +++ b/test/client/lib/slow_tests_reporter.rb @@ -0,0 +1,20 @@ +require 'minitest/reporters' + +module SlowTestsTimings + TIMINGS = {} + LOCK = Mutex.new +end + +class Minitest::Reporters::SlowTestsReporter < Minitest::Reporters::BaseReporter + def report + # Prints the 5 slowest tests by duration after the full test run. + super + sorted = SlowTestsTimings::TIMINGS.sort_by { |_name, secs| -secs }.first(5) + puts + puts 'Slowest tests are...' + sorted.each do |(name, secs)| + puts format('%3.4f %-72s', secs, name) + end + puts + end +end diff --git a/test/server/lib/coverage_metrics_limits.rb b/test/server/lib/coverage_metrics_limits.rb index 00ee2a56..83bfff77 100644 --- a/test/server/lib/coverage_metrics_limits.rb +++ b/test/server/lib/coverage_metrics_limits.rb @@ -1,7 +1,7 @@ def metrics [ [ nil ], - [ 'test.lines.total' , '<=', 531 ], + [ 'test.lines.total' , '<=', 544 ], [ 'test.lines.missed' , '<=', 0 ], [ 'test.branches.total' , '<=', 0 ], [ 'test.branches.missed', '<=', 0 ], diff --git a/test/server/lib/id58_test_base.rb b/test/server/lib/id58_test_base.rb index 46bd91ac..880500f8 100644 --- a/test/server/lib/id58_test_base.rb +++ b/test/server/lib/id58_test_base.rb @@ -3,13 +3,15 @@ require 'minitest/autorun' require 'minitest/reporters' require_relative 'slim_json_reporter' +require_relative 'slow_tests_reporter' Minitest.parallel_executor = Minitest::Parallel::Executor.new(Etc.nprocessors) reporters = [ Minitest::Reporters::DefaultReporter.new, Minitest::Reporters::SlimJsonReporter.new, - Minitest::Reporters::JUnitReporter.new("#{ENV.fetch('COVERAGE_ROOT')}/junit") + Minitest::Reporters::JUnitReporter.new("#{ENV.fetch('COVERAGE_ROOT')}/junit"), + Minitest::Reporters::SlowTestsReporter.new ] Minitest::Reporters.use!(reporters) @@ -28,8 +30,6 @@ def initialize(arg) @@args = (ARGV.sort.uniq - ['--']) # eg 2m4 @@seen_ids = [] - @@timings = {} - TIMINGS_LOCK = Mutex.new def self.test(id58, *lines, &test_block) src = test_block.source_location @@ -47,7 +47,7 @@ def self.test(id58, *lines, &test_block) t1 = Time.now instance_eval(&test_block) t2 = Time.now - TIMINGS_LOCK.synchronize { @@timings["#{id58}:#{src_file}:#{src_line}:#{name58}"] = (t2 - t1) } + SlowTestsTimings::LOCK.synchronize { SlowTestsTimings::TIMINGS["#{id58}:#{src_file}:#{src_line}:#{name58}"] = (t2 - t1) } ensure puts $ERROR_INFO.message unless $ERROR_INFO.nil? id58_teardown @@ -57,19 +57,6 @@ def self.test(id58, *lines, &test_block) define_method("test_\n#{name}".to_sym, &execute_around) end - Minitest.after_run do - slow = @@timings.select { |_name, secs| secs > 0.000 } - sorted = slow.sort_by { |_name, secs| -secs }.to_h - size = [sorted.size, 5].min - puts - puts 'Slowest tests are...' unless sorted.empty? - sorted.each_with_index do |(name, secs), index| - puts format('%3.4f - %-72s', secs, name) - break if index == size - end - puts - end - ID58_ALPHABET = %w[ 0 1 2 3 4 5 6 7 8 9 A B C D E F G H J K L M N P Q R S T U V W X Y Z diff --git a/test/server/lib/slow_tests_reporter.rb b/test/server/lib/slow_tests_reporter.rb new file mode 100644 index 00000000..3da17760 --- /dev/null +++ b/test/server/lib/slow_tests_reporter.rb @@ -0,0 +1,20 @@ +require 'minitest/reporters' + +module SlowTestsTimings + TIMINGS = {} + LOCK = Mutex.new +end + +class Minitest::Reporters::SlowTestsReporter < Minitest::Reporters::BaseReporter + def report + # Prints the 5 slowest tests by duration after the full test run. + super + sorted = SlowTestsTimings::TIMINGS.sort_by { |_name, secs| -secs }.first(5) + puts + puts 'Slowest tests are...' + sorted.each do |(name, secs)| + puts format('%3.4f %-72s', secs, name) + end + puts + end +end