diff --git a/Rakefile b/Rakefile index d433a1e..4d87ca7 100644 --- a/Rakefile +++ b/Rakefile @@ -7,4 +7,16 @@ Rake::TestTask.new(:test) do |t| t.test_files = FileList["test/**/*_test.rb"] end -task :default => :test +task :clear_coverage do + rm_rf "coverage" +end + +task :coverage_report do + require "simplecov" + SimpleCov.collate Dir["coverage/.resultset.json"] do + coverage_dir "coverage" + enable_coverage :branch + end +end + +task :default => [:clear_coverage, :test, :coverage_report] diff --git a/bin/coverage b/bin/coverage new file mode 100755 index 0000000..8544511 --- /dev/null +++ b/bin/coverage @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby + +require "simplecov" + +gem_src = ENV.fetch("COVERAGE_ROOT", File.expand_path("../..", __FILE__)) + +SimpleCov.start do + root gem_src + coverage_dir ENV.fetch("COVERAGE_DIR", "coverage") + command_name ENV.fetch("COVERAGE_NAME", "acceptance") + enable_coverage :branch +end + +$LOAD_PATH.unshift(File.join(gem_src, "lib")) + +exe = ARGV.shift +exe_path = File.join(gem_src, "exe", exe) +load exe_path diff --git a/procsd.gemspec b/procsd.gemspec index 69545b8..fe1cfe9 100644 --- a/procsd.gemspec +++ b/procsd.gemspec @@ -30,4 +30,5 @@ Gem::Specification.new do |spec| spec.add_development_dependency "bundler", ">= 1.16" spec.add_development_dependency "rake", ">= 10.0" spec.add_development_dependency "minitest", "~> 5.0" + spec.add_development_dependency "simplecov" end diff --git a/test/acceptance/Dockerfile b/test/acceptance/Dockerfile index 3761615..456196e 100644 --- a/test/acceptance/Dockerfile +++ b/test/acceptance/Dockerfile @@ -9,8 +9,6 @@ RUN apt-get update && apt-get install -y \ systemd-sysv \ dbus \ ruby \ - ruby-dev \ - build-essential \ sudo \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* @@ -29,7 +27,7 @@ RUN useradd -m -s /bin/bash testuser && \ echo "testuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/testuser # Install gems needed by procsd -RUN gem install thor dotenv --no-document +RUN gem install thor dotenv simplecov --no-document # Create app directory RUN mkdir -p /home/testuser/myapp && chown testuser:testuser /home/testuser/myapp diff --git a/test/acceptance/helper.rb b/test/acceptance/helper.rb index 94ab610..613c68d 100644 --- a/test/acceptance/helper.rb +++ b/test/acceptance/helper.rb @@ -18,7 +18,9 @@ def teardown DOCKERFILE_PATH = File.expand_path("Dockerfile", __dir__) IMAGE_NAME = "procsd-test" GEM_ROOT = File.expand_path("../..", __dir__) - GEM_BUILD_DIR = "/tmp/procsd-test-gems" + COVERAGE_DIR = File.join(GEM_ROOT, "coverage") + CONTAINER_COVERAGE_DIR = "/tmp/coverage" + CONTAINER_GEM_SRC = "/gem-src" class Container attr_reader :id, :name @@ -37,7 +39,7 @@ def start "--privileged", "--cgroupns=host", "-v", "/sys/fs/cgroup:/sys/fs/cgroup:rw", - "-v", "#{GEM_BUILD_DIR}:/gem:ro", + "-v", "#{GEM_ROOT}:#{CONTAINER_GEM_SRC}:ro", IMAGE_NAME ] @@ -46,12 +48,13 @@ def start @id = output.strip wait_for_systemd - install_gem + setup_coverage self end def stop return unless @id + copy_coverage_results system("podman", "stop", "-t", "1", @name, out: File::NULL, err: File::NULL) system("podman", "rm", "-f", @name, out: File::NULL, err: File::NULL) @id = nil @@ -101,8 +104,27 @@ def list_service_files(pattern) private - def install_gem - exec_as_root("gem install /gem/procsd-test.gem --local --ignore-dependencies --no-document") + def setup_coverage + exec_as_root("mkdir -p #{CONTAINER_COVERAGE_DIR}") + exec_as_root("chown testuser:testuser #{CONTAINER_COVERAGE_DIR}") + end + + def copy_coverage_results + require "json" + temp_file = "/tmp/procsd-coverage-#{SecureRandom.hex(4)}.json" + system("podman", "cp", "#{@name}:#{CONTAINER_COVERAGE_DIR}/.resultset.json", temp_file, out: File::NULL, err: File::NULL) + + container_data = JSON.parse(File.read(temp_file)) + container_data.each do |_, result| + result["coverage"].transform_keys! { |path| path.sub(CONTAINER_GEM_SRC, GEM_ROOT) } + end + + FileUtils.mkdir_p(COVERAGE_DIR) + resultset_path = File.join(COVERAGE_DIR, ".resultset.json") + existing_data = File.exist?(resultset_path) ? JSON.parse(File.read(resultset_path)) : {} + File.write(resultset_path, JSON.generate(existing_data.merge(container_data))) + ensure + FileUtils.rm_f(temp_file) if temp_file end def copy_content_to_container(path, content) @@ -121,20 +143,11 @@ def image_exists? end def build_image - build_gem cmd = ["podman", "build", "-t", IMAGE_NAME, "-f", DOCKERFILE_PATH, File.dirname(DOCKERFILE_PATH)] output, status = Open3.capture2e(*cmd) raise "Failed to build image: #{output}" unless status.success? end - def build_gem - FileUtils.mkdir_p(GEM_BUILD_DIR) - gem_path = File.join(GEM_BUILD_DIR, "procsd-test.gem") - Dir.chdir(GEM_ROOT) do - system("gem", "build", "procsd.gemspec", "-o", gem_path, out: File::NULL, err: File::NULL) - end - end - def wait_for_systemd(timeout: 30) start_time = Time.now loop do @@ -191,6 +204,9 @@ def create_procfile(content) end def run_procsd(command) - container.exec("procsd #{command}") + container.exec( + "COVERAGE_ROOT=#{CONTAINER_GEM_SRC} COVERAGE_DIR=#{CONTAINER_COVERAGE_DIR} " \ + "#{CONTAINER_GEM_SRC}/bin/coverage procsd #{command}" + ) end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 42f1cd1..fd2cc90 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,3 +1,12 @@ +require "simplecov" + +SimpleCov.start do + root File.expand_path("../..", __FILE__) + coverage_dir "coverage" + command_name "unit" + enable_coverage :branch +end + $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__) require "procsd"