From af07b435ddb8e58af3f706825f86409c9a5cffd2 Mon Sep 17 00:00:00 2001 From: Alex Le Date: Thu, 27 Aug 2026 09:45:36 -0700 Subject: [PATCH 01/11] ci: add SimpleCov for code coverage Signed-off-by: Alex Le --- .github/workflows/ci.yml | 14 +++++++++++--- .simplecov | 18 ++++++++++++++++++ DEVELOPER.md | 15 +++++++++++++++ Gemfile | 10 ++++++---- README.md | 4 ++++ test/test_helper.rb | 3 +++ 6 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 .simplecov diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2f8e9401..31d886cb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,9 +25,6 @@ on: - main - release-* - schedule: - - cron: "0 6 * * *" - workflow_dispatch: inputs: full-matrix: @@ -252,6 +249,17 @@ jobs: run: bundle exec rake test env: SKIP_TLS_TESTS: ${{ matrix.host.OS == 'macos' && 'true' || '' }} + COVERAGE: "1" # Coverage is cheap so we compute it every run + + - name: Upload coverage report + if: always() + continue-on-error: true + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: coverage-report-ruby-${{ matrix.version }}-${{ matrix.engine.type }}-${{ matrix.engine.version }}-${{ matrix.host.NAMED_OS }}-${{ matrix.host.ARCH }} + path: coverage/ + retention-days: 14 + if-no-files-found: ignore # Must run in its own process: the fork guard's precondition is that no # command has been issued yet, which is false inside the shared suite. diff --git a/.simplecov b/.simplecov new file mode 100644 index 00000000..51b1555a --- /dev/null +++ b/.simplecov @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# SimpleCov configuration +SimpleCov.configure do + enable_coverage :branch + primary_coverage :line + command_name "test-#{ENV['COV_GROUP'] || 'all'}" + merging true + merge_timeout 3600 + + skip %r{^/test/} + skip %r{^/valkey-glide/} # vendored upstream submodule, not our code + cover "lib/**/*.rb" # includes unloaded lib files and restricts the report to them + + # Ideally, branch should be at 80. However at the time of writing the coverage sits + # slightly above 65. We should increase this overtime. + minimum_coverage line: 80, branch: 65 +end diff --git a/DEVELOPER.md b/DEVELOPER.md index 6bfe90dd..3a272d9a 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -77,6 +77,21 @@ bundle exec rake test:standalone python3 valkey-glide/utils/cluster_manager.py --tls stop --prefix tls-standalone ``` +## Test Coverage + +We measure both **line coverage** and **branch coverage** with [SimpleCov](https://github.com/simplecov-ruby/simplecov). Coverage is opt-in via the `COVERAGE` environment variable; when set, the test suite writes an HTML report to `coverage/index.html` and a machine-readable summary to `coverage/.last_run.json`. The `coverage/` directory is gitignored. + +```bash +# Standalone only +COVERAGE=1 bundle exec rake test:standalone + +# Full suite (standalone + cluster) +COVERAGE=1 bundle exec rake test + +# Coverage report (MacOS) +open coverage/index.html +``` + ## RuboCop ```bash diff --git a/Gemfile b/Gemfile index 5791dea2..ff8444d1 100644 --- a/Gemfile +++ b/Gemfile @@ -11,8 +11,10 @@ gem "irb" if RUBY_VERSION >= "4.0" gem "rake", "~> 13.0" -gem "minitest", "~> 5.16" - -gem "minitest-reporters", "~> 1.4" - gem "rubocop", "~> 1.21" + +group :test do + gem "minitest", "~> 5.16" + gem "minitest-reporters", "~> 1.4" + gem "simplecov", "~> 1.1" +end diff --git a/README.md b/README.md index f411c4b1..b7b64f1f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # Valkey GLIDE for Ruby +[![CI](https://github.com/valkey-io/valkey-glide-ruby/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/valkey-io/valkey-glide-ruby/actions/workflows/ci.yml?query=branch%3Amain) +[![Gem Version](https://img.shields.io/gem/v/valkey-glide-rb.svg)](https://rubygems.org/gems/valkey-glide-rb) +[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://github.com/valkey-io/valkey-glide-ruby/blob/main/LICENSE) + Valkey General Language Independent Driver for the Enterprise (GLIDE) is the official open-source Valkey client library, part of the [Valkey](https://valkey.io) organization. The Ruby gem (`valkey-glide-rb`) wraps [Valkey GLIDE Core](https://github.com/valkey-io/valkey-glide), giving Ruby applications the performance and reliability of the GLIDE core. ## Features diff --git a/test/test_helper.rb b/test/test_helper.rb index c97fec68..329b9719 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -4,6 +4,9 @@ # This is useful for CD testing to verify the published gem works correctly $LOAD_PATH.unshift File.expand_path("../lib", __dir__) unless ENV["TEST_INSTALLED_GEM"] +require "simplecov" +SimpleCov.start if ENV["COVERAGE"] + require "valkey" require_relative "support/test_cluster" From 7c45da759de41e1571d1c47af68718f09ccd92bc Mon Sep 17 00:00:00 2001 From: Alex Le Date: Thu, 3 Sep 2026 09:39:14 -0700 Subject: [PATCH 02/11] fix: updated minimum coverage Signed-off-by: Alex Le --- .simplecov | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.simplecov b/.simplecov index 51b1555a..da48d3bc 100644 --- a/.simplecov +++ b/.simplecov @@ -2,7 +2,7 @@ # SimpleCov configuration SimpleCov.configure do - enable_coverage :branch + enable_coverage :branch primary_coverage :line command_name "test-#{ENV['COV_GROUP'] || 'all'}" merging true @@ -12,7 +12,7 @@ SimpleCov.configure do skip %r{^/valkey-glide/} # vendored upstream submodule, not our code cover "lib/**/*.rb" # includes unloaded lib files and restricts the report to them - # Ideally, branch should be at 80. However at the time of writing the coverage sits - # slightly above 65. We should increase this overtime. - minimum_coverage line: 80, branch: 65 + # We aims for a minimum of 80% coverage. However, our coverage at this time is much lower than this. + # Improvement is tracked in https://github.com/valkey-io/valkey-glide-ruby/issues/307 + minimum_coverage line: 40, branch: 10 end From ea184f9afe083afbd30f04452e44f2ff8ffebe79 Mon Sep 17 00:00:00 2001 From: Alex Le Date: Fri, 4 Sep 2026 09:48:03 -0700 Subject: [PATCH 03/11] fix: add an option to upload coverage reports Signed-off-by: Alex Le --- .github/workflows/ci.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 31d886cb..98adcf35 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,6 +39,10 @@ on: - "use-self-hosted" - "use-github" default: "false" + upload-coverage: + description: "Upload the coverage report as an artifact" + type: boolean + default: false name: description: "Custom run name" type: string @@ -50,6 +54,10 @@ on: description: "Include macOS runners" type: string default: "false" + upload-coverage: + description: "Upload the coverage report as an artifact" + type: boolean + default: false concurrency: group: ruby-${{ github.head_ref || github.ref }}-${{ toJson(inputs) }} @@ -252,13 +260,13 @@ jobs: COVERAGE: "1" # Coverage is cheap so we compute it every run - name: Upload coverage report - if: always() + if: always() && inputs.upload-coverage == true continue-on-error: true uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: coverage-report-ruby-${{ matrix.version }}-${{ matrix.engine.type }}-${{ matrix.engine.version }}-${{ matrix.host.NAMED_OS }}-${{ matrix.host.ARCH }} path: coverage/ - retention-days: 14 + retention-days: 7 if-no-files-found: ignore # Must run in its own process: the fork guard's precondition is that no From 2a975fcc137f20fe5988cf80e8f32ea96193eb31 Mon Sep 17 00:00:00 2001 From: Alex Le Date: Fri, 4 Sep 2026 14:05:36 -0700 Subject: [PATCH 04/11] fix: used expected_coverage instead Signed-off-by: Alex Le --- .simplecov | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.simplecov b/.simplecov index da48d3bc..88f2e664 100644 --- a/.simplecov +++ b/.simplecov @@ -12,7 +12,7 @@ SimpleCov.configure do skip %r{^/valkey-glide/} # vendored upstream submodule, not our code cover "lib/**/*.rb" # includes unloaded lib files and restricts the report to them - # We aims for a minimum of 80% coverage. However, our coverage at this time is much lower than this. - # Improvement is tracked in https://github.com/valkey-io/valkey-glide-ruby/issues/307 - minimum_coverage line: 40, branch: 10 + # Ideally, we aim for 80% coverage, which at this time is lower. + # Should we make coverage improvements, please bump this number. + expected_coverage line: 40, branch: 10 end From 3fde32581d986d3194ad08a708342def761f4efc Mon Sep 17 00:00:00 2001 From: Alex Le Date: Fri, 4 Sep 2026 14:51:04 -0700 Subject: [PATCH 05/11] fix: removed upload_coverage Signed-off-by: Alex Le --- .github/workflows/ci.yml | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 98adcf35..1f8f0d2b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,10 +39,6 @@ on: - "use-self-hosted" - "use-github" default: "false" - upload-coverage: - description: "Upload the coverage report as an artifact" - type: boolean - default: false name: description: "Custom run name" type: string @@ -54,10 +50,6 @@ on: description: "Include macOS runners" type: string default: "false" - upload-coverage: - description: "Upload the coverage report as an artifact" - type: boolean - default: false concurrency: group: ruby-${{ github.head_ref || github.ref }}-${{ toJson(inputs) }} @@ -259,16 +251,6 @@ jobs: SKIP_TLS_TESTS: ${{ matrix.host.OS == 'macos' && 'true' || '' }} COVERAGE: "1" # Coverage is cheap so we compute it every run - - name: Upload coverage report - if: always() && inputs.upload-coverage == true - continue-on-error: true - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: coverage-report-ruby-${{ matrix.version }}-${{ matrix.engine.type }}-${{ matrix.engine.version }}-${{ matrix.host.NAMED_OS }}-${{ matrix.host.ARCH }} - path: coverage/ - retention-days: 7 - if-no-files-found: ignore - # Must run in its own process: the fork guard's precondition is that no # command has been issued yet, which is false inside the shared suite. - name: Run isolated fork tests From dd5590cda4565581cd2a8b39a87636c702b85ad6 Mon Sep 17 00:00:00 2001 From: Alex Le Date: Fri, 4 Sep 2026 14:51:28 -0700 Subject: [PATCH 06/11] fix: only run coverage on ruby 3.2+ Signed-off-by: Alex Le --- Gemfile | 2 +- test/test_helper.rb | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index ff8444d1..3bda9639 100644 --- a/Gemfile +++ b/Gemfile @@ -16,5 +16,5 @@ gem "rubocop", "~> 1.21" group :test do gem "minitest", "~> 5.16" gem "minitest-reporters", "~> 1.4" - gem "simplecov", "~> 1.1" + gem "simplecov", "~> 1.1" if RUBY_VERSION >= "3.2" end diff --git a/test/test_helper.rb b/test/test_helper.rb index 329b9719..4af16d3e 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -4,8 +4,12 @@ # This is useful for CD testing to verify the published gem works correctly $LOAD_PATH.unshift File.expand_path("../lib", __dir__) unless ENV["TEST_INSTALLED_GEM"] -require "simplecov" -SimpleCov.start if ENV["COVERAGE"] +# We use SimpleCov expected_coverage option, which requires SimpleCov 1.0 which needs +# Ruby 3.2. Enable for Ruby 3.0 and 3.1 once coverage reaches 80%. +if ENV["COVERAGE"] && RUBY_VERSION >= "3.2" + require "simplecov" + SimpleCov.start +end require "valkey" require_relative "support/test_cluster" From 72af14bcb8bedf7f61f1ec64d458a82ac3e3f554 Mon Sep 17 00:00:00 2001 From: Alex Le Date: Tue, 8 Sep 2026 05:53:57 -0700 Subject: [PATCH 07/11] fix: enforce specific coverage on specific versions Signed-off-by: Alex Le --- .simplecov | 24 +++++++++++++++++++++--- Rakefile | 8 ++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/.simplecov b/.simplecov index 88f2e664..43a66712 100644 --- a/.simplecov +++ b/.simplecov @@ -2,9 +2,11 @@ # SimpleCov configuration SimpleCov.configure do + suite = ENV["COV_GROUP"] || "all" + enable_coverage :branch primary_coverage :line - command_name "test-#{ENV['COV_GROUP'] || 'all'}" + command_name "test-#{suite}" merging true merge_timeout 3600 @@ -13,6 +15,22 @@ SimpleCov.configure do cover "lib/**/*.rb" # includes unloaded lib files and restricts the report to them # Ideally, we aim for 80% coverage, which at this time is lower. - # Should we make coverage improvements, please bump this number. - expected_coverage line: 40, branch: 10 + expected = { + "unit" => { line: 51.11, branch: 17.41 }, + "standalone" => { line: 85.08, branch: 67.09 }, + "cluster" => { line: 76.80, branch: 49.30 } + } + + # Different configurations have different coverage. We enforce on the latest + # for now. See https://github.com/valkey-io/valkey-glide-ruby/issues/307 + reference_config = RUBY_PLATFORM.include?("linux") && + RUBY_VERSION.start_with?("3.4") && + ENV["ENGINE_VERSION"] == "9.0" + + if reference_config && expected.key?(suite) + # Ideally this should be removed once we reached the minimum coverage + expected_coverage expected.fetch(suite) + else + minimum_coverage line: 80, branch: 80 + end end diff --git a/Rakefile b/Rakefile index 2fec2c6e..54ad432b 100644 --- a/Rakefile +++ b/Rakefile @@ -117,6 +117,12 @@ namespace :test do cluster: "integration/cluster" } groups.each do |group, dir| + # Set the COV_GROUP environment variable for the test group task, so that + # SimpleCov can use it to determine the coverage group. + task "cov_group_#{group}" do + ENV["COV_GROUP"] = group.to_s + end + Rake::TestTask.new(group) do |t| t.libs << "test" # Only add local lib to load path when not testing installed gem @@ -124,6 +130,8 @@ namespace :test do t.test_files = FileList["test/#{dir}/**/*_test.rb"] t.options = '-v' if ENV['CI'] || ENV['VERBOSE'] end + + Rake::Task["test:#{group}"].enhance(["test:cov_group_#{group}"]) end # Exclude module directories (integration/valkey/, lint/) from lost_tests check From cc30fafad1e05bf5138203b0736b48cca2e37ef4 Mon Sep 17 00:00:00 2001 From: Alex Le Date: Tue, 8 Sep 2026 06:10:55 -0700 Subject: [PATCH 08/11] updated coverage Signed-off-by: Alex Le --- .simplecov | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.simplecov b/.simplecov index 43a66712..d8c300d3 100644 --- a/.simplecov +++ b/.simplecov @@ -17,20 +17,20 @@ SimpleCov.configure do # Ideally, we aim for 80% coverage, which at this time is lower. expected = { "unit" => { line: 51.11, branch: 17.41 }, - "standalone" => { line: 85.08, branch: 67.09 }, + "standalone" => { line: 86.73, branch: 71.13 }, "cluster" => { line: 76.80, branch: 49.30 } } # Different configurations have different coverage. We enforce on the latest # for now. See https://github.com/valkey-io/valkey-glide-ruby/issues/307 - reference_config = RUBY_PLATFORM.include?("linux") && + reference_config = RUBY_PLATFORM.start_with?("x86_64-linux") && RUBY_VERSION.start_with?("3.4") && ENV["ENGINE_VERSION"] == "9.0" if reference_config && expected.key?(suite) - # Ideally this should be removed once we reached the minimum coverage expected_coverage expected.fetch(suite) else - minimum_coverage line: 80, branch: 80 + # Ideally this should be the minimum + # minimum_coverage line: 80, branch: 80 end end From 6154b34a31b7922c64c68144e4768e7221c5f698 Mon Sep 17 00:00:00 2001 From: Alex Le Date: Tue, 8 Sep 2026 06:28:42 -0700 Subject: [PATCH 09/11] fixed: code cov Signed-off-by: Alex Le --- .simplecov | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.simplecov b/.simplecov index d8c300d3..81ea6967 100644 --- a/.simplecov +++ b/.simplecov @@ -17,7 +17,7 @@ SimpleCov.configure do # Ideally, we aim for 80% coverage, which at this time is lower. expected = { "unit" => { line: 51.11, branch: 17.41 }, - "standalone" => { line: 86.73, branch: 71.13 }, + "standalone" => { line: 86.73 }, "cluster" => { line: 76.80, branch: 49.30 } } @@ -28,9 +28,7 @@ SimpleCov.configure do ENV["ENGINE_VERSION"] == "9.0" if reference_config && expected.key?(suite) + # Ideally this should be minimum_coverage line: 80, branch: 80 expected_coverage expected.fetch(suite) - else - # Ideally this should be the minimum - # minimum_coverage line: 80, branch: 80 end end From 451b7791a0041193eab8c6846e40dc9dd9edf9cf Mon Sep 17 00:00:00 2001 From: Alex Le Date: Tue, 8 Sep 2026 07:20:27 -0700 Subject: [PATCH 10/11] updated expected coverage Signed-off-by: Alex Le --- .simplecov | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/.simplecov b/.simplecov index 81ea6967..68f0ba73 100644 --- a/.simplecov +++ b/.simplecov @@ -14,21 +14,16 @@ SimpleCov.configure do skip %r{^/valkey-glide/} # vendored upstream submodule, not our code cover "lib/**/*.rb" # includes unloaded lib files and restricts the report to them - # Ideally, we aim for 80% coverage, which at this time is lower. - expected = { - "unit" => { line: 51.11, branch: 17.41 }, - "standalone" => { line: 86.73 }, - "cluster" => { line: 76.80, branch: 49.30 } - } + # tracked in https://github.com/valkey-io/valkey-glide-ruby/issues/307 + # reference_config = RUBY_PLATFORM.start_with?("x86_64-linux") && + # RUBY_VERSION.start_with?("3.4") && + # ENV["ENGINE_VERSION"] == "9.0" - # Different configurations have different coverage. We enforce on the latest - # for now. See https://github.com/valkey-io/valkey-glide-ruby/issues/307 - reference_config = RUBY_PLATFORM.start_with?("x86_64-linux") && - RUBY_VERSION.start_with?("3.4") && - ENV["ENGINE_VERSION"] == "9.0" + # cluster runs last, so its report is the merge of all three suites. + project_total = suite == "cluster" - if reference_config && expected.key?(suite) - # Ideally this should be minimum_coverage line: 80, branch: 80 - expected_coverage expected.fetch(suite) + if reference_config && project_total + minimum_coverage line: 88.87, branch: 72.5 + maximum_coverage line: 88.87 end end From b279a6083040ebc73c85d8f7aa611a346e14b3a9 Mon Sep 17 00:00:00 2001 From: Alex Le Date: Tue, 8 Sep 2026 07:21:15 -0700 Subject: [PATCH 11/11] test Signed-off-by: Alex Le --- .simplecov | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.simplecov b/.simplecov index 68f0ba73..7aea1b75 100644 --- a/.simplecov +++ b/.simplecov @@ -23,7 +23,6 @@ SimpleCov.configure do project_total = suite == "cluster" if reference_config && project_total - minimum_coverage line: 88.87, branch: 72.5 - maximum_coverage line: 88.87 + minimum_coverage line: 80, branch: 70 end end