Skip to content

Conversation

swissspidy
Copy link
Member

@swissspidy swissspidy commented Mar 14, 2025

Here's what's going on:

Right now, on the main branch, some of the tests are failing when code coverage is failing:

Example run: https://github.com/wp-cli/wp-cli/actions/runs/14721677772/job/41316957178#step:11:73

001 Scenario: Composer stack with override requirement before WP-CLI # features/bootstrap.feature:32
      Then STDOUT should contain:                                    # features/bootstrap.feature:93
        $ vendor/bin/wp eval '\WP_CLI::Success( "WP-Standard-Eval" );'
        Success: WP-Standard-Eval
        
        cwd: /tmp/wp-cli-test-run--68103be4d2ca41.59611126/
        run time: 0.58504390716553
        exit status: 0 (Exception)

002 Scenario: Override command bundled with current source # features/bootstrap.feature:98
      Then STDOUT should contain:                          # features/bootstrap.feature:172
        $ wp --require=override/override.php eval '\WP_CLI::Success( "WP-Standard-Eval" );'
        Success: WP-Standard-Eval
        
        cwd: /tmp/wp-cli-test-run--68103be87eb446.18633621/
        run time: 1.5230369567871
        exit status: 0 (Exception)

003 Scenario: Override command through package manager # features/bootstrap.feature:177
      Then STDOUT should contain:                      # features/bootstrap.feature:251
        $ wp eval '\WP_CLI::Success( "WP-Standard-Eval" );'
        Success: WP-Standard-Eval
        
        cwd: /tmp/wp-cli-test-run--68103bef0fa995.51[75](https://github.com/wp-cli/wp-cli/actions/runs/14721677772/job/41316957178#step:11:76)0029/
        run time: 1.5111899375916
        exit status: 0 (Exception)

004 Scenario: Ensure that Utils\run_mysql_command() passes through without reading full DB into memory # features/utils.feature:108
      Then the return code should be 0                                                                 # features/utils.feature:165
Error formatting output: Backtrack limit exhausted

004 is due to memory limit, but the other 3 ones can be attributed to a change in how the autoloading works when code coverage is involved:

When running tests with WP_CLI_TEST_COVERAGE=1, we modify the command that's being run to prepend WP_CLI_REQUIRE=vendor/wp-cli/wp-cli-tests/utils/generate-coverage.php. So given the above example, it will become WP_CLI_REQUIRE=vendor/wp-cli/wp-cli-tests/utils/generate-coverage.php vendor/bin/wp eval '\WP_CLI::Success( "WP-Standard-Eval" );'

The generate-coverage.php file requires the project's autoloader to ensure that the code coverage classes exist, see https://github.com/wp-cli/wp-cli-tests/blob/7ac2ff7fc494f94ba34410ea4e7e2409e2afb945/utils/generate-coverage.php#L33-L38

The above tests were failing because they defined a custom \Eval_Command class to override wp eval, but because of the early autoloading, the original \Eval_Command class (yes, same name) was loaded, so no override was happening.

IMO this is just an oversight in the test. If someone overrides a specific command, they should be using a custom class name anyway. So this PR changes those tests to use a custom class name so it doesn't clash with the earlier autoloaded Eval_Command.

Good news: with this PR, all tests with code coverage now pass 🎉

Bad news: 2 tests fail when code coverage is disabled. Example run: https://github.com/wp-cli/wp-cli/actions/runs/14727955107/job/41335108255?pr=6069#step:11:75

Weirdly enough I cannot seem to reproduce those locally when performing those steps manually 🤔 So not sure why they fail during tests.


See wp-cli/wp-cli-tests#241

So it doesn't clash with an earlier autoloaded `Eval_Command`
@swissspidy swissspidy requested a review from a team as a code owner March 14, 2025 17:42
Copy link

codecov bot commented Mar 14, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

📢 Thoughts on this report? Let us know!

@swissspidy swissspidy changed the title Fix overrides test by using custom class name Fix failing tests Mar 24, 2025
@swissspidy swissspidy changed the title Fix failing tests Fix failing tests in coverage Apr 29, 2025
@schlessera schlessera mentioned this pull request Apr 29, 2025
47 tasks
@swissspidy
Copy link
Member Author

@schlessera wrote down the details now and would appreciate some extra eyes.

@mrsdizzie
Copy link
Member

Some initial debugging suggests this is just an issue with the order packages are being autoloaded. the cli override example works because it happens to get loaded after the normal cli command, where as the eval override doesn't work because for whatever autoload magic reason the regular eval command is loaded again after the Custom_Eval_Command class is evaluated. I can reproduce this locally with tests, though not sure if the order is based on environment in anyway.

This suggests to me that it isn't possible to reliably actually override an existing command in the way we test, and it just happened to 'work' before because we used the same class names. If you add --debug to one of the failing examples you can see the eval command get added several times. The last one is from the original, not the override. Unfortunately I'm not more familiar with autoload to have a better idea.

@swissspidy
Copy link
Member Author

I should use --debug more :-)

One of the early bootstrap steps is IncludePackageAutoloader, where commands from packages will be added. This includes the custom cli & eval commands.

Later on, IncludeFallbackAutoloader runs, which loads the fallback autoloader that is provided through the composer.json file (vendor/autoload.php). And I think here is the difference:

In tests, this will add the commands found in vendor/wp-cli, which includes the eval command. That's why the override happens. But when I perform the steps manually using the phar (loading phar://wp-cli.phar/vendor/autoload.php), there is no eval command being autoloaded, so it doesn't override the custom command from the package again.

I don't know whether that means it is working as intended.

However, conceptually, I would think that a reliable override would need to happen by actually waiting for the original command to be registered first, by hooking into after_add_command:eval. So something like this:

WP_CLI::add_hook(
  'after_add_command:eval',
  static function () {
    WP_CLI::add_command( 'eval', 'Custom_Eval_Command', array( 'when' => 'before_wp_load' ) );
  }
);

@swissspidy
Copy link
Member Author

^ That seems to cause an infinite loop during tests though because the hook fires every time the command is added again. With a simple static variable it seems to work now...

@swissspidy swissspidy changed the title Fix failing tests in coverage Fix unstable package override tests Apr 30, 2025
@swissspidy
Copy link
Member Author

It worked 🥳

@mrsdizzie mrsdizzie merged commit 8b064c7 into main Apr 30, 2025
52 checks passed
@mrsdizzie mrsdizzie deleted the fix/override-test branch April 30, 2025 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants