Skip to content

[6.x] Pest time-balanced sharding - #15140

Merged
jasonvarga merged 6 commits into
6.xfrom
pest
Aug 10, 2026
Merged

[6.x] Pest time-balanced sharding#15140
jasonvarga merged 6 commits into
6.xfrom
pest

Conversation

@jasonvarga

@jasonvarga jasonvarga commented Aug 8, 2026

Copy link
Copy Markdown
Member

Adds Pest as the CI test runner so we can shard the PHP suite across parallel jobs, using its time-balanced sharding to keep them even.

The suite is ~10,000 tests and the slowest job (Windows) had grown to nearly 13 minutes, which sets the floor for how long a PR sits waiting.

Tests themselves (after the overhead of setting up the jobs) goes from ~11m to ~3m.

A pull request workflow run goes from ~14m to ~4m.

Pest 4 is used because we still support Laravel 12. Luckily, the time-balanced sharding feature actually landed on Pest 4 - not Pest 5 like their marketing implies.

Pest is only the runner

Intentionally not rewriting any tests. Pest is just being used as the runner and for its sharding feature.

You can use vendor/bin/phpunit or vendor/bin/pest locally.

Ubuntu is split 4 ways, Windows 6

Windows runs the same tests in roughly twice the time, so splitting both evenly leaves Windows as the critical path with Ubuntu jobs sitting idle. Six shards brings Windows' test execution down to roughly the same as Ubuntu's, for two extra jobs.

Test fixes

Three pre-existing bugs surfaced while getting this green. They're follow-ups to #15143 — same class of problem, just not caught at the time — and are included here because sharding can't work without them:

  • Invalid data provider key. ProvidesExternalUrls::externalUrlProvider() keyed its data sets by URL, and '' is one of the internal URLs — an empty-string key, which PHPUnit rejects. This broke --list-tests outright, which is how shard assignment is discovered.
  • CP\ColorTest leaked state. It wrote theme colour preferences to resources/preferences.yaml and never cleaned up, so Preferences\EndpointsTest inherited a stray theme.colors block. Now cleaned up in tearDown(), matching DefaultPreferencesTest and PrecedenceTest.
  • View tag state leaked between tests. The increment and rotate tags keep counters in static properties that are only cleared when the ClearState listener fires on a response. A test that renders Antlers without a full request leaves them populated. StateTest picked up a counter of 31 from IncrementTest once sharding put them in the same job. TestCase::setUp() now resets view state.

Notes

jasonvarga and others added 3 commits August 10, 2026 08:36
The provider keyed data sets by URL, and an empty string is one of the
internal URLs, producing an empty-string key. PHPUnit rejects this when
listing tests, which broke any tooling relying on --list-tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
setThemeColors() writes resource_path('preferences.yaml'), and while
setUp() deleted it, nothing cleaned up after the last test. The final
test's colors survived into unrelated tests that assert on preferences,
making the suite order dependent. Delete the file in tearDown() too,
matching DefaultPreferencesTest and PrecedenceTest.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pest runs the existing PHPUnit test suite as-is, with no conversion to
Pest syntax. It's added for its sharding support, which PHPUnit has no
equivalent for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The test run is around 90% of each job's wall clock, so sharding is
close to linear. Four shards takes the workflow from ~12.8 to ~4
minutes. Windows needs its own include entry per shard, since an
include that overrides a matrix key creates a standalone combination
rather than merging, and so wouldn't inherit the shard dimension.

shards.json holds recorded timings so shards are balanced by duration
rather than test count. Regenerate it with --update-shards.

Adds a php-tests-result job that aggregates every shard, so branch
protection can require one check instead of one per matrix cell.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Windows tests take roughly twice as long as ubuntu's, so splitting both
of them four ways leaves Windows as the critical path. Six brings its
slowest job down to about the same as the slowest ubuntu one, which is
as far as it's worth going.
The increment and rotate tags keep their counters in static properties
that are only cleared when the ClearState listener fires on a response.
A test that renders Antlers without going through a full request leaves
them populated, and the next test in the same process inherits them.

StateTest picked up a counter of 31 from IncrementTest once sharding put
the two in the same job.
@jasonvarga
jasonvarga marked this pull request as ready for review August 10, 2026 14:51
@jasonvarga jasonvarga changed the title [6.x] Pest [6.x] Pest time-balanced sharding Aug 10, 2026
@jasonvarga
jasonvarga merged commit 05775d9 into 6.x Aug 10, 2026
69 checks passed
@jasonvarga
jasonvarga deleted the pest branch August 10, 2026 15:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants