Speed up the default PHPUnit suite#71
Open
sirreal wants to merge 10 commits into
Open
Conversation
Cache core registration resets and expected annotations, keep common test-context hooks registered persistently, avoid repeated autocommit setup, and apply low-cost password hashing to class fixtures. Update auth fixtures and add guard coverage for cached registration snapshots.
Guard export headers once output has already started and define WXR helper functions only once per PHP process so the export test class no longer needs process isolation.
Initialize the sitemap server explicitly for the disabled-sitemap path and remove unnecessary process isolation from the two 404-path tests.
Pass explicit chmod values where constants are not under test, keep a focused FS_CHMOD_DIR coverage case isolated, and remove isolation from independent ID, upgrader, and theme fixture tests.
Avoid the generic UTF-8 scanner for the common first-code-point and ISO-8859-1 decode paths while retaining exhaustive polyfill and invalid-subpart coverage.
Replace pack/unpack single-byte length handling with chr/ord in WP_Token_Map hot paths.
Use smaller deterministic image fixtures, avoid external missing-URL latency, and keep cross-origin rewrite coverage in-process while preserving one isolated header assertion.
Let REST controller test classes opt into rest_api_init without create_initial_rest_routes and register only the post type, taxonomy, or controller routes they need.
Opt REST controller-focused tests into minimal route registration while preserving related routes for dispatch, links, embedding, revisions, autosaves, widgets, menus, templates, fonts, and application-password behavior.
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR speeds up the default PHPUnit suite by more than 70% without removing tests or reducing coverage.
Measured default-suite wall time:
275.951s77.960s-197.991sThat is a
71.75%wall-time reduction. The 70% target ceiling was82.785s, so the final run is4.825sunder target.JUnit body time also dropped from
154.880826sto57.582364s, a62.82%reduction. The final full run still executed29,639tests with105,737assertions.Commit Structure
This branch is intentionally split into logical commits:
6e7a4dc77eTests: Optimize shared PHPUnit setupfb964f6bc4Tests: Run export tests in processeadb4dab9aTests: Avoid process isolation in sitemap 404 tests1dca902b0eTests: Reduce isolated PHP processes9b32b13f63Compat: Decode UTF-8 hot paths directly0f2273fdb1HTML API: Use byte helpers in token mapsf6115ff315Tests: Reduce media fixture costdbdc75f3a7Tests: Add reduced REST route setup helpersbbd6926c13Tests: Reduce REST route setup in controller suitesWhat Changed
Shared PHPUnit Harness
The largest non-REST foundation is in
WP_UnitTestCase_Base:SET autocommit = 0once it is already disabled for the test connection.The auth tests were updated to preserve algorithm coverage while avoiding repeated expensive hash generation where a stable fixture hash is equivalent.
Export Tests
export_wp()declared WXR helper functions inside the function body. That forced the test class to run in separate PHP processes to avoid redeclaration and header issues.This PR:
Tests_Admin_ExportWp.The export coverage remains the same; the tests now run in process.
Process Isolation Reductions
Several tests were isolated only because they used constants or historical global assumptions. This PR removes unnecessary isolation while keeping explicit coverage where constants are the behavior under test.
Changed areas:
WP_Filesystem_Direct::mkdir()tests pass explicit chmod values whereFS_CHMOD_DIRis not the behavior under test.FS_CHMOD_DIRbehavior.WP_Upgrader::install_package()tests no longer define chmod constants and now assert the expected filesystem calls directly.wp_unique_prefixed_id()datasets now run in process.UTF-8 and Token Map Hot Paths
The compat layer now avoids generic scanner work in common hot paths:
_mb_ord()decodes the first UTF-8 code point directly after validating byte ranges._wp_utf8_decode_fallback()directly handles valid UTF-8 spans and invalid subpart lengths while preserving the previous replacement behavior.WP_Token_Mapuseschr()andord()for single-byte lengths instead ofpack()andunpack()in token-map hot paths.Media Test Fixture Cost
The media changes keep the same behavior under test but reduce fixture weight:
Document-Isolation-Policyemission.REST Route Setup
REST setup was the largest remaining cost. Most controller-specific test classes were paying the cost of registering the entire core REST route catalog for every test, even when a class only dispatched one controller's routes.
This PR adds shared helpers to:
rest_api_initwhile temporarily suppressingcreate_initial_rest_routes.create_initial_rest_routesin afinallyblock.Individual REST test classes opt into minimal route sets only where focused validation proved the related routes they dispatch, link, embed, or assert. Examples include:
Tests_REST_APIsetup paths that do not need the full route catalog.REST-ish JUnit class time dropped from about
63.661sto19.385sin the final full-suite artifact.Coverage and Equivalence Notes
This PR does not remove tests and does not narrow assertions. The speedups come from:
For REST controller tests, the default behavior remains full initial route creation unless a class explicitly opts into reduced setup. The reduced setup still runs
rest_api_init; it only suppressescreate_initial_rest_routesand then registers the routes relevant to that class.Validation
Full Suite
Command:
Result:
77.960s57.582364s29,639105,737867814The error/failures are known local/environmental issues observed during the speedup work:
Tests_WP_Customize_Manager::test_wp_customize_publish_changeset- local sidebar state warning/error.Tests_Abilities_API_WpRegisterCoreAbilities::test_core_get_site_info_executes- generated REST fixture state wheredescriptionis not the expected string.Tests_DB::test_mysqli_flush_sync- missing local DB procedure privileges.WP_Test_REST_Attachments_Controller::test_sideload_scaled_unique_filename- localcanola-scaled-1.jpgfilename collision.Tests_Theme_ThemeDir::test_broken_themes- local extra brokenhtmltheme fixture.The generated QUnit REST fixture drift produced by the full run was restored after validation.
Focused and Group Validation
The following focused/group validations were run during development:
Tests_REST_API, widgets/sidebars, singleton REST controllers, term/global-style/pattern controllers, menu/navigation controllers, block controllers, pages, and font controllers.--group restapiwith the route-reduction candidate. The route-specific coverage held; the run exposed the known local attachment collision and an oEmbed classic-provider issue that also reproduced when run alone, so it was not caused by route reduction.git diff --checkis clean.Adversarial Review
An adversarial expert review subagent reviewed the expanded REST route-reduction batch and explicitly approved it with no required fixes.
Key approval points:
did_action( 'rest_api_init' ), default REST filters, settings registration, and oEmbed route registration while suppressing onlycreate_initial_rest_routes.Spy_REST_Server.Residual review note: controller-specific tests no longer incidentally cover coexistence with every unrelated core REST controller on each test method. Full route catalog coverage remains in schema/setup style tests, and these controller classes continue to assert their own behavioral surface.
Per-Commit Impact Report
After the initial PR write-up, I ran a second full-suite boundary sweep to estimate the marginal impact of each logical commit in branch order.
Method:
WP_TESTS_SKIP_INSTALL=1 vendor/bin/phpunit --log-junit artifacts/impact/<boundary>.xmlonce per boundary.2with the same known local/environmental failures listed above, so the timing comparison is still useful.The wall-time column is intentionally shown raw. It includes process startup, external waits, filesystem/cache effects, and local outliers. For smaller changes, the JUnit body-time delta is the more stable signal. Negative deltas below mean the suite got faster compared with the previous boundary.
a1314bbebc269.94s148.48s4,558,0116e7a4dc77e439.25s+169.31s112.33s-36.15s4,558,016fb964f6bc4144.28s-294.97s108.28s-4.06s4,558,016eadb4dab9a171.32s+27.04s107.73s-0.54s4,558,0161dca902b0e1087.49s+916.17s109.13s+1.39s4,558,0189b32b13f63132.29s-955.20s106.51s-2.62s105,7370f2273fdb1129.99s-2.30s104.65s-1.86s105,737f6115ff315155.68s+25.69s130.03s+25.38s105,737dbdc75f3a7211.82s+56.14s163.15s+33.13s105,737bbd6926c1389.88s-121.94s65.97s-97.18s105,737This second sweep measured the final branch at
89.88swall time and65.97sJUnit body time, versus269.94sand148.48sat baseline. That is180.06swall time saved (66.7%) and82.51sJUnit body time saved (55.6%). The earlier final validation run in this PR body measured faster absolute numbers (77.960swall,57.582364sJUnit body), which is consistent with the amount of run-to-run wall-time variance visible in the boundary sweep.Interpretation by Logical Change
REST route reduction is the strongest isolated win, but only as a bundle.
dbdc75f3a7costs time by itself because it adds the reduced setup machinery without using it broadly.bbd6926c13pays that back heavily:-121.94swall and-97.18sJUnit body against the helper-only boundary.f6115ff315tobbd6926c13, the suite saves65.80swall and64.05sJUnit body.dbdc75f3a7andbbd6926c13together. Do not merge the helper commit alone for performance.Shared PHPUnit setup is valuable, but should not ship alone.
6e7a4dc77ecuts JUnit body time by36.15s, which confirms the harness work reduces work inside tests.+169.31sslower in isolation, likely because remaining process-isolated tests amplify the shared setup cost until the follow-up isolation changes land.fb964f6bc4then recovers the wall-time regression and leaves the suite much faster overall. Baseline to export-in-process is269.94s -> 144.28swall and148.48s -> 108.28sJUnit body.6e7a4dc77ewithout at leastfb964f6bc4.UTF-8 direct decode has a modest full-suite time win and a major assertion-overhead win.
9b32b13f63reduces JUnit body time by2.62sin this sweep.4.56Mto105.7kbecause exhaustive Unicode coverage now validates large corpora in aggregate instead of emitting per-codepoint assertions.Token-map byte helpers are a small, clean speedup.
0f2273fdb1saves2.30swall and1.86sJUnit body in the full suite.Sitemaps process-isolation cleanup is small in full-suite terms.
eadb4dab9asaves only0.54sJUnit body in this sweep, while wall time moves the wrong way by27.04s.The broader process-isolation cleanup did not show a stable isolated speedup in this sweep.
1dca902b0eproduced a severe wall-time outlier (1087.49s) while JUnit body time stayed near the surrounding boundaries (109.13s).+916.17swall delta as the commit's actual cost; it looks like one non-JUnit wait or local timeout in a single run.Media fixture cost did not prove itself as a full-suite speedup in this run.
f6115ff315was slower by25.69swall and25.38sJUnit body in the boundary sweep.Prioritized Merge Guidance
dbdc75f3a7+bbd6926c13. This is the clearest large JUnit-body reduction in the boundary sweep.6e7a4dc77e+fb964f6bc4. This pair gives a large net win, but the first commit is misleadingly bad on wall time when isolated.9b32b13f63+0f2273fdb1. These are smaller full-suite wins but clean up hot paths and remove assertion overhead.eadb4dab9aand1dca902b0efor correctness/maintenance reasons, not because this sweep proves large suite-time wins.f6115ff315media fixture cost. The full-suite boundary result was slower, so it should not be used as a headline performance justification without targeted follow-up data.