Skip to content

ci: exercise the vips driver on JRuby - #243

Merged
pftg merged 2 commits into
masterfrom
ci/vips-on-jruby
Aug 23, 2026
Merged

ci: exercise the vips driver on JRuby#243
pftg merged 2 commits into
masterfrom
ci/vips-on-jruby

Conversation

@pftg

@pftg pftg commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

Why

Ahead of 2.1 removing the chunky_png driver, we needed to know whether ruby-vips actually works on JRuby — otherwise that removal silently drops JRuby support.

It works. This PR makes CI prove it instead of assuming it.

What was already true

Nothing was missing from the JRuby cells:

  • .github/actions/setup-ruby-and-dependencies installs libvips unconditionally (cached path or apt fallback), including for JRuby.
  • gems.rb declares gem "ruby-vips", require: false with no platform guard, so JRuby installs it. (oily_png is the only gem with platform: :ruby.)

So SnapDiff::Drivers.detect_available has always returned [:vips, :chunky_png] on JRuby, and every skip ... unless defined?(Vips) unit test has always run there. Job log from master run 32590002736, Test Ruby & Rails (jruby-10.0, rails81_gems.rb):

2026-08-22T18:12:57Z     ruby-vips (2.3.0)
2026-08-22T18:13:15Z [capybara-screenshot-diff] drivers detected: vips, chunky_png
2026-08-22T18:16:20Z 445 runs, 1167 assertions, 0 failures, 0 errors, 6 skips

test/test_helper.rb would have aborted the whole run via DriverCoverage.missing_for_ci if vips had not loaded, so those green cells are themselves proof that require "vips" succeeds on JRuby on Linux.

What was missing

The integration path. bin/rake test leaves SCREENSHOT_DRIVER unset, and test/system_test_case.rb:24 defaults it to chunky_png. So on JRuby the vips FFI binding was only ever loaded, never driven — no capture → compare → annotate, and never the Vips.cache_set_max flush in that file's teardown. Test Drivers covers both drivers end to end, but only on CRuby 4.0.

The change

One env line on the Test Ruby & Rails job. Non-JRuby cells get chunky_png spelled out, which is the default they already had — no behaviour change there. No new cells, no matrix growth, no extra Actions minutes.

Evidence (empirical, local)

JRuby 10.0.6.0 (3.4.5) on OpenJDK 26, ruby-vips 2.3.0, libvips 8.18.5.

Driver contract tests:

$ SCREENSHOT_DRIVER=vips bundle exec ruby -Itest -Ilib test/unit/drivers/vips_driver_test.rb
[capybara-screenshot-diff] drivers detected: vips, chunky_png
50 runs, 104 assertions, 0 failures, 0 errors, 0 skips

Other vips-touching unit tests (image_compare, annotation_service, compare_api, screenshoter, drivers, drivers/utils, image_preprocessor):

48 runs, 280 assertions, 0 failures, 0 errors, 0 skips

Integration suite, cuprite + vips, with CI's JRUBY_OPTS:

28 runs, 45 assertions, 0 failures, 0 errors, 1 skips

MRI 4.0.6 control, same machine, same suite, same driver:

28 runs, 45 assertions, 0 failures, 0 errors, 1 skips

Identical. No JRuby-specific breakage in the vips path — no FFI pointer trouble, no Vips::Image finalization trouble, no threading trouble.

One unrelated thing found

Without JRUBY_OPTS="--dev -J-Djruby.thread.pool.enabled=true", the integration suite completes (Ruby.tearDown is reached, so minitest has already reported) but then hangs forever joining a leftover puma reactor thread and a ferrum/utils/thread.rb thread. With CI's JRUBY_OPTS it exits cleanly. Not caused by vips, and CI already sets those options — noting it so nobody rediscovers it as a vips bug.

Scope

2.0-shaped: additive, no chunky_png removal (that is 2.1's job), no version bump, no CHANGELOG edit. standardrb clean.

full-ci label applied so the matrix job actually runs on this PR.

Summary by Sourcery

Run the vips driver through the JRuby integration suite and adjust its CI time budget so JRuby support is continuously validated.

New Features:

  • Exercise the vips screenshot driver end to end in JRuby CI cells.

Enhancements:

  • Select vips for JRuby tests while preserving chunky_png coverage on other platforms.
  • Increase JRuby CI job and test retry timeouts to accommodate the expanded suite.

CI:

  • Update the Ruby and Rails workflow to run the JRuby vips integration path without adding matrix cells.

Tests:

  • Extend CI coverage to validate vips capture, comparison, and annotation behavior on JRuby.

Summary by CodeRabbit

  • Chores
    • Updated automated test workflows to allow more time for JRuby runs.
    • Configured screenshot processing to use the appropriate driver for each Ruby environment.
    • Increased retry timeouts for JRuby tests to improve reliability.

@pftg pftg added the full-ci Run full test matrix on this PR label Aug 23, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @pftg, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 17886554-8c70-4f2e-982d-94e3bd8091b9

📥 Commits

Reviewing files that changed from the base of the PR and between b1d01af and b71e6a3.

📒 Files selected for processing (1)
  • .github/workflows/test.yml

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The test workflow now applies longer job and retry timeouts to JRuby matrix cells. It also selects vips for JRuby screenshots and chunky_png for other Ruby runtimes.

Changes

CI runtime configuration

Layer / File(s) Summary
Runtime-specific test settings
.github/workflows/test.yml
The matrix job uses a 25-minute timeout and 15-minute retry timeout for JRuby. Other runtimes retain their existing timeout values. SCREENSHOT_DRIVER selects vips for JRuby and chunky_png otherwise.

Estimated code review effort: 1 (Trivial) | ~3 minutes

Merge Risk: ⚪ Minimal · up to b71e6

The CI workflow now exercises the vips driver on JRuby while preserving existing coverage elsewhere; no actionable merge-blocking risk remains beyond normal checks and review.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary CI change: exercising the vips screenshot driver on JRuby.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0 files. (1 skipped: 1 unsupported.)
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/vips-on-jruby

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Configures CI to explicitly exercise the vips screenshot driver on JRuby by setting SCREENSHOT_DRIVER per matrix cell, ensuring the vips integration path is driven end-to-end without changing behavior for MRI runs.

File-Level Changes

Change Details Files
Drive the vips screenshot driver on JRuby in the Test Ruby & Rails CI job via environment configuration, while keeping non-JRuby cells explicitly on chunky_png.
  • Set SCREENSHOT_DRIVER in the Test Ruby & Rails job env block using a matrix.ruby-version conditional to choose vips on JRuby and chunky_png on other rubies
  • Document in comments that JRuby is the only non-MRI engine exercising vips, that the previous default left JRuby on chunky_png, and that chunky_png remains covered by its own unit tests on JRuby
.github/workflows/test.yml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@pftg

pftg commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator Author

CI update — the JRuby cells did not pass. Marking this PR as not-ready pending diagnosis.

All CRuby cells are green, including Test Drivers (*, vips). All five JRuby cells (jruby-10.0 x 4 gemfiles, plus jruby-head) were cancelled at the 20-minute job timeout after all three retry attempts hit the 7-minute per-attempt limit.

From Test Ruby & Rails (jruby-10.0, rails81_gems.rb), attempt 1:

12:38:16Z [capybara-screenshot-diff] drivers detected: vips, chunky_png
12:38:24Z .......
12:38:45Z ...[snap_diff] 2 screenshots compared, no failures.
12:45:11Z <~150 dots flushed by the SIGTERM>
12:45:11Z SignalException: SIGTERM
12:45:20Z ##[warning]Attempt 1 failed. Reason: Timeout of 420000ms hit

For reference, the same job on master with chunky_png finishes the whole suite in about three minutes: 445 runs, 1167 assertions, 0 failures, 0 errors, 6 skips.

Two things this is not:

  1. Not a correctness problem. No failures or errors were reported before the SIGTERM, and locally on JRuby 10.0.6.0 the vips driver contract tests are 50 runs, 104 assertions, 0 failures, 0 errors, 0 skips and the integration suite is 28 runs, 45 assertions, 0 failures, 0 errors, 1 skips — identical to the MRI 4.0.6 control.

  2. Not vips being slow. On the same JRuby locally, the integration suite is faster with vips than with chunky_png — 23s vs 72s.

So something environment-specific is stalling on the Linux runner that does not reproduce on macOS/arm64. Running the full suite locally on JRuby + vips now to establish whether it is slow-but-finite or genuinely hung; will post the timing.

Do not merge as-is.

pftg added 2 commits August 23, 2026 15:18
The JRuby cells install libvips and ruby-vips already -- the setup action
installs libvips unconditionally and gems.rb declares ruby-vips with no
platform guard -- so `Drivers.detect_available` has always reported
`vips, chunky_png` there, and the vips-gated unit tests have always run.

What never ran on JRuby was the integration path: `bin/rake test` leaves
SCREENSHOT_DRIVER unset, and test/system_test_case.rb defaults that to
chunky_png. So capture -> compare -> annotate, plus the vips cache flush
in that file's teardown, were MRI-only.

Point the JRuby cells at vips. Non-JRuby cells get chunky_png spelled
out, which is the default they already had.

Verified locally on JRuby 10.0.6.0 + libvips 8.18.5:

  test/unit/drivers/vips_driver_test.rb
    50 runs, 104 assertions, 0 failures, 0 errors, 0 skips

  test/integration (cuprite, SCREENSHOT_DRIVER=vips)
    28 runs, 45 assertions, 0 failures, 0 errors, 1 skips

Identical to the MRI 4.0.6 control on the same machine (28 runs, 45
assertions, 0 failures, 0 errors, 1 skips).
Separate from the vips switch and a fix for a failure already on master:
every JRuby cell of run 32638878557 (master b1d01af, chunky_png, no
change from this branch) burns all three attempts on
`Timeout of 420000ms hit` and is killed at the 20-minute job cap. The
cells have stopped gating anything.

The suite outgrew the budget -- it is ~600 tests now. Measured on JRuby
10.0.6.0 locally, same machine, same suite, only SCREENSHOT_DRIVER
differing:

  vips        598 runs, 1683 assertions, 0 failures, 0 errors -- 390.4s
  chunky_png  598 runs, 1683 assertions, 0 failures, 0 errors -- 434.4s

vips is the faster of the two, so this is not driver cost. Raise the
per-attempt budget to 15 minutes and the job cap to 25 so one attempt
plus setup fits with headroom. A passing cell still costs ~8 minutes; a
failing one costs 25 instead of 20, but produces a result rather than a
cancellation.
@pftg
pftg force-pushed the ci/vips-on-jruby branch from 9a320aa to b71e6a3 Compare August 23, 2026 13:19
@pftg

pftg commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator Author

Diagnosed — the JRuby timeout is pre-existing on master and has nothing to do with vips. Rebased onto current master and added the budget fix; this PR is now two commits.

The control

Run 32638878557, master b1d01af, chunky_png, none of this branch applied. All five JRuby cells cancelled, identically:

12:18:56Z [capybara-screenshot-diff] drivers detected: vips, chunky_png
12:26:00Z ##[warning]Attempt 1 failed. Reason: Timeout of 420000ms hit
12:33:11Z ##[warning]Attempt 2 failed. Reason: Timeout of 420000ms hit
12:38:13Z ##[error]The operation was canceled.

The JRuby cells have stopped gating anything on master. My first push just inherited that.

And vips is the faster driver

JRuby 10.0.6.0, same machine, same full suite, only SCREENSHOT_DRIVER differing:

driver result wall
vips 598 runs, 1683 assertions, 0 failures, 0 errors, 1 skips 390.4s
chunky_png 598 runs, 1683 assertions, 0 failures, 0 errors, 1 skips 434.4s

vips is 10% faster and equally correct. The suite simply outgrew the 7-minute per-attempt budget — it is ~600 tests now, up from the 445 that used to finish in about three minutes.

Second commit

timeout_minutes 7 -> 15 for JRuby, job cap 20 -> 25 so one attempt plus setup fits with headroom. A passing cell still costs ~8 minutes. A failing one costs 25 instead of 20 but produces a result instead of a cancellation.

It is a separate concern from the vips switch, so it is a separate commit — happy to split it into its own PR and rebase this on top if you would rather land the budget fix independently, since it fixes master either way.

@pftg

pftg commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator Author

vips on JRuby is proven green on real CI

Test Ruby & Rails (jruby-10.0, rails72_gems.rb), run 32641982006, SCREENSHOT_DRIVER=vips, Linux x64, first attempt:

13:22:47Z [capybara-screenshot-diff] drivers detected: vips, chunky_png
13:31:04Z 600 runs, 1690 assertions, 0 failures, 0 errors, 1 skips

8m17s. jruby-10.0, rails71_gems.rb passed too. That is the whole suite — unit, integration and legacy — driving the vips FFI path end to end on JRuby, which had never happened before this PR.

The 2.1 chunky_png removal does not drop JRuby support.

Three JRuby cells were still cancelled — pre-existing, not vips

jruby-10.0, rails81_gems.rb stalled mid-run:

13:22:56Z Run options: --seed 29927
13:22:56Z # Running:
13:37:50Z <~230 dots> rake aborted!
13:37:59Z ##[warning]Attempt 1 failed. Reason: Timeout of 900000ms hit

~230 of 600 tests in 15 minutes, against 600 in 8m17s in the cell that passed. Different seed, same code. So there is an intermittent, seed-dependent hang in the JRuby suite.

It predates this branch. Master b1d01af on chunky_png (32638878557) cancels all five JRuby cells the same way. And locally I caught what is probably the same thing with a jstack: the suite finishes, at_exit runs, then JRuby blocks forever in Ruby.tearDown -> ThreadService.teardown -> Thread.join, waiting on a leftover puma reactor thread and a ferrum/utils/thread.rb thread.

That is a separate defect and I have not tried to fix it here. Worth its own issue — a timeout cannot fix a hang.

Why the second commit stays

Not papering over the hang: 7 minutes was simply too small. The cell that passed cleanly needed 8m17s. At the old budget even a healthy JRuby run could not finish, which is why every cell on master is cancelled rather than failing with a result.

Summary

vips loads on JRuby yes — drivers detected: vips, chunky_png, and has been true in CI all along
vips is correct on JRuby yes — 600 runs / 1690 assertions / 0 failures on CI; matches the MRI 4.0.6 control locally
vips is slower on JRuby no — 390s vs 434s for chunky_png on the same suite
JRuby CI is reliable no — pre-existing intermittent hang, independent of driver

@pftg
pftg merged commit f9c8ca6 into master Aug 23, 2026
26 of 29 checks passed
@pftg
pftg deleted the ci/vips-on-jruby branch August 23, 2026 13:50
pftg added a commit that referenced this pull request Aug 23, 2026
The retry budget was larger than the job cap on both engines, so the last
attempt was always killed partway and the cell reported `cancelled`.

Measured on master run 32643567648 (post-#243), the 5 JRuby cells:

  jruby-10.0 rails81  suite 713s, no hang, 1 attempt   -> 12m02  pass
  jruby-10.0 rails71  suite 545s + 6m hang -> 15m t/o;
                      attempt 2 clean at 543s          -> 24m20  pass
  jruby-10.0 rails80  attempt 1 hung -> 15m t/o;
                      attempt 2 killed at the 25m cap  -> cancelled
  jruby-10.0 rails72  same                             -> cancelled
  jruby-head rails81  same                             -> cancelled

3 of 5 JRuby cells gate nothing. The cause is arithmetic, not the driver:
max_attempts 3 x timeout_minutes 15 = 45 min against timeout-minutes 25.
Attempt 3 could never start, and attempt 2 had only 25 - 15 - 0.7 = 9.3 min
to finish a run that measures 9-12 min -- so whether a cell survived a hang
came down to which gemfile it drew. MRI has the same shape, smaller: 3x3 = 9
against a cap of 8.

  - JRuby job cap 25 -> 31, so 1 + 15 + 15 fits.
  - max_attempts 3 -> 2 on both engines, since 3 was never reachable.

A doubly-hung JRuby cell now costs 31 min instead of 25, but today's 25 min
buys no verdict at all. Coverage, drivers and the full-ci/cron opt-in model
are unchanged.

Also adds the concurrency group Lint never had, so superseded PR pushes stop
running the linter to completion.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

full-ci Run full test matrix on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant