-
Notifications
You must be signed in to change notification settings - Fork 111
Setup mutation testing #686
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
atm this class replaces any call to a method named yes, or no.
for now it is not scoped to the TrinaryLogic class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
atm this mutator works for these classes in the phpstan-src codebase - which I think is not a bad thing
grafikcurrent challenge: figure out a way to kill mutants across github action jobs - I will think about that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test is failing sporadically after introducing the random order. It's probably because of:
phpstan-doctrine/tests/Rules/Doctrine/ORM/entity-manager.php
Lines 34 to 37 in 5eaf37b
I guess the test that executes this should clean up after itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also I don't see PHPStan configured as mutant killer here.
Makefile
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why turning off the logger-github?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also personally I wouldn't add this to Makefile. We'll need a more complex logic in the GHA job.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added it to makefile to easy running infection locally (to reproduce CI problems)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why turning off the logger-github?
running infection in 3 php versions likely spams the 'files changed tab' with annotations.
I think we need a separate job which accumulates the separate job results and merges them togehter so we get a single final result with less false positives (mutation job on php 8.3 might error about a mutation which can only be killed in the php 8.1 test-suite)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mutation job on php 8.3 might error about a mutation which can only be killed in the php 8.1 test-suite
I had this concern as well but I talked to Maks about this and given that Infection would only mutate covered lines then this shouldn't happen. If a test ran on PHP 8.3 covers a line and we mutate that line, it should fail the test on 8.3.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should fail the test on 8.3.
but the very same mutation will happen on 8.1/8.2 and no test will kill the mutation (in case it is a PHP 8.3 only test)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this was really true Infection would be unusable for us. We'd have to be able to invoke each phase separately and modify the results before feeding them to the next phase. (Run tests on each PHP version, feed the data into Infection, let it mutate the sources, run tests on each PHP version again ourselves and so on.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could run infection on multiple php versions in parallel.. collect the mutations afterwards in a new followup github action and report only those as a problem, which were not killed in any of the previous jobs.
(as long as we do not do source transformations, the mutations should be the same on all 3 jobs)
alternatively we could run infection on a single php version only
Some comments posted by me disappeared. I linked the --git-diff-filter / --git-diff-base / --git-diff-lines options
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PHAR distribution is the recommended one for installing Infection. I think we could just add infection to tools in setup-php action.
Some comments posted by me disappeared. I linked the --git-diff-filter / --git-diff-base / --git-diff-lines options
yeah, I did not yet activate these options, because then there would be no results reported in this PR.
The PHAR distribution is the recommended one for installing Infection. I think we could just add
infectiontotoolsin setup-php action.
I think this only make sense in case we don't want run infection locally. the more we use GitHub Actions only stuff, the harder it is to run the very same setup on a local computer.
The test is failing sporadically after introducing the random order. It's probably because of:
I did not yet see a test, which started failling more often since random order was enabled.
which particular test do you mean?
the build on the master branch is broken long before random order with the same errors
I think this only make sense in case we don't want run infection locally.
Yeah, I think we don't. Given the support for many PHP versions (and that we only typically have a single PHP version running locally), I think it's unlikely we'd run Infection locally.
Also I'm thinking we'll be passing GitHub Actions-specific env variables to the CLI options anyway.
Why is the build green even when there are escaped mutants?
Why is the build green even when there are escaped mutants?
because we did not yet define a "min MSI", meaning there is no minimum threshold yet.
if we want the test to fail when at least a single escaped mutant occurs, we need min-msi=100
Yeah, I want that, alongside the Git-filtering options.
We can demonstrate the failing by adding some new change here in this PR temporarily.
Also I don't see PHPStan configured as mutant killer here.
I think, as long as we only mutate with TrinaryLogicMutator its pretty unlikely that the PHPStan killer will help us.
in addition the process is already slow and adding the PHPStan killer to the mix will make it a even slower
I really want it though. I don't want to write tests for things that would error in PHPStan. Also we'd have more incentives to make it faster 😊
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Phpunit killer requires a green test run
Phpstan killer requires a green phpstan run
Make sure to carry over PHPStan's result cache, probably with upload and download-artifact actions. It should speed up the build significantly.
@maks-rafalko I wonder why infection treats this PHPStan result as a killed mutant?
I would debug the exit code. Here is the logic how Infection determines if it's killed or escaped for PHPStan process output.
We discussed with @ondrejmirtes that checking non-zero exit code is not reliable, but AFAIK nothing has been implemented on PHPStan side to improve it, so we still check (non-)zero exit code.
local debugging reveals: we get a exit code of 2, because infection internally passes --fail-without-result-cache and the result cache is not used as the PHPStan output describes:
Result cache not used because extension file /Users/m.staab/dvl/phpstan-doctrine/src/Rules/Doctrine/ORM/QueryBuilderDqlRule.php hash does not match.
Result cache was not saved because of --tmp-file and --instead-of CLI options passed (editor mode).
Yeah, that's tricky. I suppose we should have a special exit code for when the result is green but result cache was not used (so that Infection does not use it to kill mutants).
Or maybe Infection can stop passing --fail-without-result-cache altogether.
Or maybe Infection can stop passing --fail-without-result-cache altogether.
I think thats the way to go. not everyone has the tools to use a result cache in CI.
Or maybe Infection can stop passing --fail-without-result-cache altogether.
I remember I've added it by @staabm's suggestion to avoid the cases when for some (unexpected) reason we miss the cache, so for me this option did make sense so far.
Can I ask you why do we have here
Result cache not used because extension file /src/Rules/Doctrine/ORM/QueryBuilderDqlRule.php hash does not match.
Is it the issue that can be fixed here? Or is it expected?
Can I ask you why do we have here
Result cache not used because extension file /src/Rules/Doctrine/ORM/QueryBuilderDqlRule.php hash does not match.
Is it the issue that can be fixed here? Or is it expected?
my guess is that this problem occurs because phpstan-doctrine is a phpstan extension repository (regular non phpstan extension projects would not have this case if I got it right)
I remember I've added it by @staabm's suggestion to avoid the cases when for some (unexpected) reason we miss the cache, so for me this option did make sense so far.
ohh I remember that.. while running infection, we actually have a primed cache (caused by the initial test-run). so we don't need CI tooling for the cache to work.
This can happen in any project with custom rules or other extensions. When Infection actually decides to mutate an extension file, it's inevitable the result cache won't be used.
maks-rafalko
commented
Oct 7, 2025
This can happen in any project with custom rules or other extensions. When Infection actually decides to mutate an extension file, it's inevitable the result cache won't be used.
- so do you say here we have a cache miss issue because Infection mutates the extension's file?
- does it mean we need to remove passing
--fail-without-result-cacheby Infection?
I'm not sure I understand all the cases to make a decision.
I think what we're facing here is that we want to make sure the user primed the PHPStan cache before running Infection. But it can still be invalidated in these cases.
--fail-without-result-cache can sometimes fill this purpose but it's not perfect.
@ondrejmirtes I think we are ready to land this.
in case you are fine with the current forced-error I would revert it and we can do the first steps with Infection on PHPStan.
As described above, we are likely seeing every mutation 3 times now (once for each PHP Version).
in case we don't want to put a new aggregation/evaluation job after mutations runs, we could start with a single PHP Version only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am I right that all mutants would currently get killed by SA because of the --fail--without-result-cache option?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should always upload this, not only when Infection passes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
@romm
romm
Oct 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi there 👋
I'm coming from CuyZ/Valinor#721
@ondrejmirtes could you explain the reason why the artifacts should always be uploaded? Also, I'm not familiar with the artifact feature: when it's uploaded we can have access to the files directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because I want to see the logs regardless of whether Infection suceeds or fails.
I'm not familiar with the artifact feature: when it's uploaded we can have access to the files directly?
Yes, on job summary. Artifacts are useful to pass files between jobs, but also for letting users download them. Example https://github.com/phpstan/phpstan-src/actions/runs/18351063855
@romm
romm
Oct 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! Thanks for the info. Have a nice day! 😊
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is far more information in infection.log than what's in the linked screenshot. The log shows the JSON output PHPStan printed when it finished.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had no idea it's possible to have the same thing on stdout that's currently uploaded in infection.log. If it's possible then I'd probably welcome a PR 😊
@romm
romm
Oct 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👀 waiting for an answer, to modify CuyZ/Valinor#721 before merging 👀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you really want to always see the most detailed information available for each build, then
- to see detailed logs, use
--log-verbosity=all --debug. You already have it. (explanation) - to display to
stdout/stderr-infection.json5for each logger supports the following:php://stdoutphp://stderr
So, the final command would be:
infection --log-verbosity=all --debug --show-mutations=0
Here, --show-mutations=0 is needed to not duplicate what is already printed to stdout.
Similar approach is used e.g. by BetterReflection, they always print the whole list of escaped mutations to stderr.
But you will have even more details thatnks to --log-verbosity=all and especially --debug
config needs to be updated:
- "text": "tmp/infection.log", + "text": "php://stdout",
@romm
romm
Oct 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI @ondrejmirtes I just submitted infection/infection#2438 — thought you could be interested.
--fail--without-result-cache
nope, I fixed it in infection and updated this PR to the latest release
see CI results:
grafikAwesome, thank you!
Do you want me to create phpstan/build-infection repository where the mutators could live? 😊
9b118ac
into
phpstan:2.0.x
Do you want me to create
phpstan/build-infectionrepository where the mutators could live?
sure. we need a plan how to scale it over all repos (or what steps next)
I imagine it could similarly to build-cs:
phpstan-doctrine/.github/workflows/build.yml
Lines 61 to 66 in 9b118ac
Does the infection "json5" config file format support includes? The only thing I'm looking to DRY is probably the mutators implementations and the mutators config key, everything else can be copy-pasted across repositories (because I suspect there will have to be some adjustments).
So I imagine:
- Let's do the new repository
- Let's try to reuse it in phpstan-doctrine
- Then we can use it in more places, I would aggresively put it in phpstan-src probably first
Uh oh!
There was an error while loading. Please reload this page.
requires