Page MenuHomePhabricator

The PHPUnit config override does not appear to be auto-generated
Open, HighPublic

Description

Changes for T345481 introduced PHPUnitConfigTest::testConfigUpToDate, a structure test that requires phpunit.xml to exist and be auto-generated by generatePHPUnitConfig.php.

The parallel PHPUnit path in quibble calls composer phpunit:prepare-parallel:* directly, which does not chain through @phpunit@phpunit:config, so phpunit.xml is never generated. This causes the structure test to fail with:

PHPUnitConfigTest::testConfigUpToDate
No local PHPUnit config found. Generate it manually by running `composer phpunit:config`,
or automatically by running tests via `composer phpunit`.
Failed asserting that file "phpunit.xml" exists.

Example failing builds:

Fix: https://gerrit.wikimedia.org/r/q/Idc48e77f4a682288bc2838a91100552ab2b68c90

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
Daimona claimed this task.
Daimona removed Daimona as the assignee of this task.

Apparently this can still happen with the phpunit-databaseless.xml config file, see e.g. https://integration.wikimedia.org/ci/job/quibble-vendor-mysql-php83/47565/console. Perhaps the top-level XML comment is lost when the file is generated, as we're seeing in T419073?

Actually that shouldn't really matter, because the script checks phpunit.xml, not the config in use. The config is being generated, too, as can be seen from the CI logs; and I can't reproduce locally. I'll take another look later, but for the time being I need to rest a bit.

@Daimona: Do we want to temporarily revert https://gerrit.wikimedia.org/r/c/mediawiki/core/+/1248119 and https://gerrit.wikimedia.org/r/c/mediawiki/core/+/1247719 to unblock this task and T419073, make fixes to Quibble's running of unit tests and to phpunit-patch-coverage, before restoring?

@Daimona: Do we want to temporarily revert https://gerrit.wikimedia.org/r/c/mediawiki/core/+/1248119 and https://gerrit.wikimedia.org/r/c/mediawiki/core/+/1247719 to unblock this task and T419073, make fixes to Quibble's running of unit tests and to phpunit-patch-coverage, before restoring?

What makes me a bit nervous about reverts (I kind of expressed the same thought earlier today) is that we aren't fully sure what caused the breakage here, as multiple changes went out over the last couple days, in MW core, extensions, and CI. I'd say reverts could be a possibility if we really can't figure this out, but I'd like to try a bit first. As for T419073, I don't think that one warrants a revert, because it's just the coverage reports that are broken. In that case we also know what needs to be done, it's just that I don't know how to do it.

So, I tried reproducing the failure locally using https://gitlab.wikimedia.org/arthurtaylor/jenkins-run-analysis, but it didn't fail. However, I noticed two bugs with the tool along the way (and CC @ArthurTaylor -- let me know where you'd like similar reports in future): 1) SKIN_DEPENDENCIES has a value of N/A, which is treated as a normal string, so it tries to clone a N/A repo and fails; 2) The list of cloned extensions is longer than in CI. Could it be that MW_ZUUL_RECURSE=false is not applied locally?

So I tried with manual invocation, and while this time the set of cloned extensions seemed correct, I still couldn't reproduce the error over two runs. Guess I'll try again tomorrow, but I'll say that if we have failures that can't even be reproduced by replicating a CI run locally, that's a problem in its own right.

That said, I'm not really sure what might be causing this. Maybe a race condition from multiple processes (from each PHPUnit split group) manipulating the config file at the same time? Those processes all run phpunit:config via composer phpunit:entrypoint, but I don't see how that could cause this. Maybe it's the PHPUnitSplitter code that does something with the config file? E.g., it temporarily moves it out of the way, and then the bootstrap in another process can't find it? I'm not familiar with the splitter and don't know if this could be the case.

Maybe it's the PHPUnitSplitter code that does something with the config file? E.g., it temporarily moves it out of the way, and then the bootstrap in another process can't find it? I'm not familiar with the splitter and don't know if this could be the case.

Ah, probably https://gerrit.wikimedia.org/g/mediawiki/core/+/4dba1491f0c608c16127807be09137752663317d/includes/Composer/PhpUnitSplitter/PhpUnitXmlManager.php#378?

// Quibble still expects a `phpunit.xml` file to be generated by parallel runs.
// Create this file for now to make the Quibble migration easier. Delete this when
// Quibble has been updated to expect the correct files (T378797)
copy( $phpunitConfigOutputFile, $system->getcwd() . DIRECTORY_SEPARATOR . 'phpunit.xml' );

I remember seeing this code before and wondering if it was still needed, but then forgot about it. The associated task has been resolved, and phpunit.xml exists now anyway, so this looks like something that should be removed anyway.


EDIT: Except in that case the bootstrap should (possibly) complain about the file not being autogenerated, not it being missing. Nonetheless, it shouldn't hurt to try this as well...

Change #1248659 had a related patch set uploaded (by Daimona Eaytoy; author: Daimona Eaytoy):

[mediawiki/core@master] PhpUnitSplitter: do not override phpunit.xml

https://gerrit.wikimedia.org/r/1248659

1237375 failed gate checks three times in a row, although it failed in a different place each time. First in PHP 8.2, then in PHP 8.3 at split group 5, then in PHP 8.3 at split group 6. Each time with the error message

Error in bootstrap script: RuntimeException:
No PHPUnit config override found. Generate it manually by running `composer phpunit:config`, or automatically by running tests via `composer phpunit`.
#0 /workspace/src/vendor/phpunit/phpunit/src/Util/FileLoader.php(66): include_once()
#1 /workspace/src/vendor/phpunit/phpunit/src/Util/FileLoader.php(49): PHPUnit\Util\FileLoader::load()
#2 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(567): PHPUnit\Util\FileLoader::checkAndLoad()
#3 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(347): PHPUnit\TextUI\Command->handleBootstrap()
#4 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(114): PHPUnit\TextUI\Command->handleArguments()
#5 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(99): PHPUnit\TextUI\Command->run()
#6 /workspace/src/vendor/phpunit/phpunit/phpunit(107): PHPUnit\TextUI\Command::main()
#7 /workspace/src/vendor/bin/phpunit(122): include('...')
#8 {main}

I see the same error in a test case above, but nobody had quoted it on Phabricator yet, so I didn't find this task when I searched for the error.

Change #1248659 merged by jenkins-bot:

[mediawiki/core@master] PhpUnitSplitter: do not override phpunit.xml

https://gerrit.wikimedia.org/r/1248659

Another failure after the core patch was merged: https://integration.wikimedia.org/ci/job/quibble-vendor-mysql-php83/47798/console

It's a small extension, which probably helps to reproduce the issue. Split group 3 passed in only 64ms, and then two of the other split groups failed.

@Daimona thanks for the report. I noticed issue 1 this week and have pushed a fix for that. For the second issue I've filed T419202 , and in the absence of a better place for them, please do tag issues as Wikidata Omega and assign them to me.

@tstarling I've tried a couple of times this morning to reproduce that failure locally, and it seems to work fine. Just as an info. I'll do some more digging into what the difference could be between CI and local reproductions.

Okay - now I have an STR and will dig a bit deeper:

python run_local.py --bash https://integration.wikimedia.org/ci/job/quibble-vendor-mysql-php83/47798/console

then in the shell:

composer run phpunit:prepare-parallel:extensions
while true; do composer run phpunit:parallel:databaseless; done

and then I see the error about 30% of the time.

...and I can confirm that phpunit.xml disappears briefly every time one of the split groups starts

So I think I can say that it's not a fan of this:

rename( $localCfgPath, $tmpPath );

If I skip testConfigUpToDate, I don't see the issue (so far).

Change #1248772 had a related patch set uploaded (by Arthur taylor; author: Arthur taylor):

[mediawiki/core@master] Temporarily disable phpunit config test

https://gerrit.wikimedia.org/r/1248772

@Daimona thanks for the report. I noticed issue 1 this week and have pushed a fix for that. For the second issue I've filed T419202 , and in the absence of a better place for them, please do tag issues as Wikidata Omega and assign them to me.

Thanks, will do that!

and then I see the error about 30% of the time.

Ah, then I suppose it could just be that I didn't try hard enough.

So I think I can say that it's not a fan of this:

rename( $localCfgPath, $tmpPath );

If I skip testConfigUpToDate, I don't see the issue (so far).

Ohhhhhh damn, yeah... In retrospect, we shouldn't be moving the used config file around when running test; that was a bad decision on my part and I didn't fully realize this while writing the test.

It is still interesting though, that this test is consistently running so early that it conflicts with the bootstrap in another process. I suppose the ordering consistently puts it near the start of the suite for whatever reason. Maybe even just the fact that structure tests are the first thing listed in the extensions suite, although I'm not sure if the parallel PHPUnit setup would shuffle them.

At any rate, I've just +2ed the patch to temporarily disable the test. Later I will change it so it doesn't actually touch the real phpunit.xml (adding a parameter to the script should do).

Change #1248400 abandoned by Hashar:

[integration/quibble@master] commands: Run composer phpunit:config for parallel tests

Reason:

Thank you!

https://gerrit.wikimedia.org/r/1248400

Change #1248772 merged by jenkins-bot:

[mediawiki/core@master] Temporarily disable phpunit config test

https://gerrit.wikimedia.org/r/1248772

Daimona lowered the priority of this task from Unbreak Now! to High.Mar 6 2026, 1:32 PM

The immediate issue of broken CI should be resolved now, hence lowering priority. I'd still like to properly fix the test before closing this task though.

(This is not about MW core's own tests, but the PHPUnit rigging for all MediaWiki things.)

Change #1248848 had a related patch set uploaded (by Daimona Eaytoy; author: Daimona Eaytoy):

[mediawiki/core@master] phpunit: Make config test use a temporary file

https://gerrit.wikimedia.org/r/1248848

Conveniently this is only making VisualEditor's *post-merge* tests fail, but it's definitely still ongoing.

I can confirm this is also blocking our post-merge and gate-and-submit checks in PersonalDashboard.

I'm assuming the post-merge issue is actually T419073 and not this one. Post-merge coverage jobs shouldn't actually block anything and that task is therefore lower priority (but still high priority of course). Discussion can continue over there, but the TLDR is that the fix is there waiting for someone who knows how to parse XML in python without losing comments along the way. And that person could be YOU :D

As for the issue in gate-and-submit: T419107#11682676 in ReadingLists is not the same as the last one we fixed. This time the phpunit.xml file is there, it just doesn't have the comment indicating that it was autogenerated. I'm not sure how it could happen. The one in PersonalDashboard seems to be from earlier today, when the hotfix r1248772 had not yet landed.

I think this https://gerrit.wikimedia.org/r/c/integration/config/+/1248875 (update Quibble) fixed the issue for ReadingLists

I don't know for sure, but I highly doubt it's related, and more likely that there is some sort of race condition that's only rarely triggered... Except of course I don't know what could be causing it. In fact, just to clarify, I'm not working on this task, as it seems really hard to reproduce the failure locally.

The immediate issue of broken CI should be resolved now, hence lowering priority. I'd still like to properly fix the test before closing this task though.

This still happens on CI:
https://integration.wikimedia.org/ci/job/quibble-vendor-mysql-php83/48168/console

21:01:59 > Composer\Config::disableProcessTimeout
21:01:59 > @php tests/phpunit/generatePHPUnitConfig.php '--configuration' '/workspace/src/phpunit-databaseless.xml' '--testsuite' 'split_group_0' '--exclude-group' 'Broken,Standalone,Database' '--cache-result-file=/workspace/log/phpunit_group_0_databaseless.result.cache'
21:01:59 Using PHP 8.3.30
21:01:59 Generating PHPUnit config
21:01:59 Config written to /workspace/src/phpunit.xml
21:01:59 > phpunit '--configuration' '/workspace/src/phpunit-databaseless.xml' '--testsuite' 'split_group_0' '--exclude-group' 'Broken,Standalone,Database' '--cache-result-file=/workspace/log/phpunit_group_0_databaseless.result.cache'
21:01:59 Using PHP 8.3.30
21:01:59 Running with MediaWiki settings because there might be integration tests
21:01:59 PHPUnit 9.6.34 by Sebastian Bergmann and contributors.
21:01:59 
21:01:59 Error in bootstrap script: RuntimeException:
21:01:59 The PHPUnit config override does not appear to be auto-generated. Generate it manually by running `composer phpunit:config`, or automatically by running tests via `composer phpunit`.
21:01:59 #0 /workspace/src/vendor/phpunit/phpunit/src/Util/FileLoader.php(66): include_once()
21:01:59 #1 /workspace/src/vendor/phpunit/phpunit/src/Util/FileLoader.php(49): PHPUnit\Util\FileLoader::load()
21:01:59 #2 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(567): PHPUnit\Util\FileLoader::checkAndLoad()
21:01:59 #3 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(347): PHPUnit\TextUI\Command->handleBootstrap()
21:01:59 #4 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(114): PHPUnit\TextUI\Command->handleArguments()
21:01:59 #5 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(99): PHPUnit\TextUI\Command->run()
21:01:59 #6 /workspace/src/vendor/phpunit/phpunit/phpunit(107): PHPUnit\TextUI\Command::main()
21:01:59 #7 /workspace/src/vendor/bin/phpunit(122): include('...')
21:01:59 #8 {main}
21:01:59 Script phpunit handling the phpunit event returned with error code 1
21:01:59 Script @phpunit was called via phpunit:entrypoint
21:01:59 Worker exited with status 1

For the Parallel Run there is a prepare step (with --list-tests-xml), that runs generatePHPUnitConfig.php at the moment

Each phpunit process uses --configuration argument to point to another file, it seems wrong to check the phpunit.xml in each process to be generated, as that happens earlier and the process uses another file.
On the other side the file phpunit.xml exists and is generated via the script in the prepare step, no idea why the paralel process does not see this generated file and pass the check.
Maybe each parallel process should not use the command that generate to file to avoid race condition about half written files read for checking.

I think this https://gerrit.wikimedia.org/r/c/integration/config/+/1248875 (update Quibble) fixed the issue for ReadingLists

This has rebuild the CI base images so we get ones with Quibble 1.16.0 which I have cut yesterday (eg: docker-registry.wikimedia.org/releng/quibble-bullseye-php81:1.16.0). The CI jobs have otherwise not been updated, that will be done by https://gerrit.wikimedia.org/r/c/integration/config/+/1248880 , possibly on Monday.

This still happens on CI:
https://integration.wikimedia.org/ci/job/quibble-vendor-mysql-php83/48168/console

That definitely looks like the same issue, and I find it equally impossible to explain. I tried running the job a couple of times here locally and wasn't able to reproduce the issue. Also not when using the STR in T419107#11680621 and letting in run in a loop for 10 minutes. But I do agree that having the structure test look for a phpunit.xml that is different from the configuration in use is at least confusing even if there's no reason it should be a problem in this case.

Let's keep collecting reports of the The PHPUnit config override does not appear to be auto-generated. issue here and try and get a sense of how often it's still happening.

Hi @Viktoria_Hillerud_WMSE,

For the coverage jobs, we are tracking the issue in T419073 , but I think we are (also?) still looking for a solution there.

Hi @Viktoria_Hillerud_WMSE,

For the coverage jobs, we are tracking the issue in T419073 , but I think we are (also?) still looking for a solution there.

I see, thankyou!

Each phpunit process uses --configuration argument to point to another file, it seems wrong to check the phpunit.xml in each process to be generated, as that happens earlier and the process uses another file.

Yeah, ideally that is probably the case. But I also wanted to keep the quick check as simple as possible, and the phpunit.xml file should most probably exist anyway: anything that wants to use a custom configuration would need to start by generating that phpunit.xml file and then modifying it. I'm not sure what other use cases this complex we have outside of quibble; but I don't think it's totally unreasonable to have these more complex use cases adapt to the logic in question, e.g. by making sure to preserve the autogenerated phpunit.xml file.

Maybe each parallel process should not use the command that generate to file to avoid race condition about half written files read for checking.

I had a similar thought in the last paragraph of T419107#11680167. But then I would assume those writes to be atomic, and therefore that nothing should ever read a half-written file.

That definitely looks like the same issue, and I find it equally impossible to explain. I tried running the job a couple of times here locally and wasn't able to reproduce the issue. Also not when using the STR in T419107#11680621 and letting in run in a loop for 10 minutes.

Yeah, FWIW I had a similar experience.

Hi @Viktoria_Hillerud_WMSE,

For the coverage jobs, we are tracking the issue in T419073 , but I think we are (also?) still looking for a solution there.

In that case the problem has been identified, it's the python code in phpunit-suite-edit that strips all comments from the XML file, including the marker that lets us recognize it as an autogenerated file. The fix would be to avoid stripping comments, which sounds like it should be trivial, and yet here we are...

Change #1248924 had a related patch set uploaded (by Daimona Eaytoy; author: Daimona Eaytoy):

[mediawiki/core@master] phpunit: Print content of non-autogenerated phpunit.xml in quibble

https://gerrit.wikimedia.org/r/1248924

I made r1248924 to print the full config file when running in quibble; this should let us understand what the "presumably non-autogenerated" file really is.

However, I also realized something fun: the code that checks for the comment marker looks for the string generatePHPUnitConfig. What I didn't realize at first is that this string is already included in the phpunit.xml.template file (The actual extension tests are added in generatePHPUnitConfig.php). We could check for a different string, but I also wonder if we could maybe just drop this check now that the .dist file has been renamed to .template, and so it won't get used automatically.

Change #1249399 had a related patch set uploaded (by Jforrester; author: Jforrester):

[mediawiki/core@master] phpunit.xml.template: Don't use the magic 'generatePHPUnitConfig' string in the template

https://gerrit.wikimedia.org/r/1249399

Change #1249399 merged by jenkins-bot:

[mediawiki/core@master] phpunit.xml.template: Don't use the magic 'generatePHPUnitConfig' string in the template

https://gerrit.wikimedia.org/r/1249399

Change #1248924 merged by jenkins-bot:

[mediawiki/core@master] phpunit: Print content of non-autogenerated phpunit.xml in quibble

https://gerrit.wikimedia.org/r/1248924

From https://integration.wikimedia.org/ci/job/quibble-vendor-mysql-php84/1439/console and with my patch we now know what's inside the failing config file:

Error in bootstrap script: RuntimeException:
The PHPUnit config override does not appear to be auto-generated. Generate it manually by running `composer phpunit:config`, or automatically by running tests via `composer phpunit`.
Full content:

#0 /workspace/src/vendor/phpunit/phpunit/src/Util/FileLoader.php(66): include_once()
#1 /workspace/src/vendor/phpunit/phpunit/src/Util/FileLoader.php(49): PHPUnit\Util\FileLoader::load()
#2 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(567): PHPUnit\Util\FileLoader::checkAndLoad()
#3 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(347): PHPUnit\TextUI\Command->handleBootstrap()
#4 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(114): PHPUnit\TextUI\Command->handleArguments()
#5 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(99): PHPUnit\TextUI\Command->run()
#6 /workspace/src/vendor/phpunit/phpunit/phpunit(107): PHPUnit\TextUI\Command::main()
#7 /workspace/src/vendor/bin/phpunit(122): include('...')
#8 {main}

So... It's empty! I don't have a good way to prove it, but the only possible theory is that this is really a race condition due to the concurrent config writes. I'm not familiar with the internal of file_put_contents, but 1) it empties the file before writing (which I suppose makes sense) and 2) it doesn't lock the file by default, so it's entirely possible that a file_get_contents in another process happens right at that time. Presumably this could be confirmed by checking the C implementation, but I don't think it's necessary. There's also https://github.com/php/php-src/issues/20108 which is somewhat related and seems to suggest this is what's happening (although I only skimmed the issue). The simpler fix would be, I hope, to lock the file with LOCK_EX upon writes. I'm going to make a patch for that.

Change #1249951 had a related patch set uploaded (by Daimona Eaytoy; author: Daimona Eaytoy):

[mediawiki/core@master] phpunit: lock config file while writing in generatePHPUnitConfig.php

https://gerrit.wikimedia.org/r/1249951

Change #1249951 merged by jenkins-bot:

[mediawiki/core@master] phpunit: lock config file while writing in generatePHPUnitConfig.php

https://gerrit.wikimedia.org/r/1249951

So, this issue should be fixed now. The only other thing left for this task is re-enabling the proper test, which is r1248848. Other than that, I'll keep an eye out for new failures and call this resolved if there are none.

Not sure, but it seems this job was running/started after the merge and fails (log shows 8c1655900275c88e3c2014477d15ae82174242eb, that is after a7169c44be9c1fe6af09f3eed7261f0adaa6a437)

https://integration.wikimedia.org/ci/job/quibble-vendor-mysql-php83/49446/console

21:01:50 Using PHP 8.3.30
21:01:50 Running with MediaWiki settings because there might be integration tests
21:01:50 PHPUnit 9.6.34 by Sebastian Bergmann and contributors.
21:01:50 
21:01:50 Error in bootstrap script: RuntimeException:
21:01:50 The PHPUnit config override does not appear to be auto-generated. Generate it manually by running `composer phpunit:config`, or automatically by running tests via `composer phpunit`.
21:01:50 Full content:
21:01:50 
21:01:50 #0 /workspace/src/vendor/phpunit/phpunit/src/Util/FileLoader.php(66): include_once()
21:01:50 #1 /workspace/src/vendor/phpunit/phpunit/src/Util/FileLoader.php(49): PHPUnit\Util\FileLoader::load()
21:01:50 #2 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(567): PHPUnit\Util\FileLoader::checkAndLoad()
21:01:50 #3 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(347): PHPUnit\TextUI\Command->handleBootstrap()
21:01:50 #4 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(114): PHPUnit\TextUI\Command->handleArguments()
21:01:50 #5 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(99): PHPUnit\TextUI\Command->run()
21:01:50 #6 /workspace/src/vendor/phpunit/phpunit/phpunit(107): PHPUnit\TextUI\Command::main()
21:01:50 #7 /workspace/src/vendor/bin/phpunit(122): include('...')
21:01:50 #8 {main}
21:01:50 Script phpunit handling the phpunit event returned with error code 1
21:01:50 Script @phpunit was called via phpunit:entrypoint
21:01:50 Worker exited with status 1

It happened to me too just now at https://integration.wikimedia.org/ci/job/quibble-vendor-mysql-php83/49479/console

It doesn't seem to be effecting all repos and patches this time around (?)

I didn't realize that flock is an advisory lock, and needs to be called by everyone accessing the file. So, in our case, that would mean adding flock( $f, LOCK_SH ) to all readers as well. Which is doable, although a bit impractical... On top of that, the PHP docs for file_put_content's flags say:

In other words, a flock() call happens between the fopen() call and the fwrite() call.

I'm not familiar with the PHP internals, but if file_put_content's fopen-equivalent call is actually the equivalent of a fopen( ..., 'w' ) (i.e. truncating the file), then the locking also happens too late. As above, this could probably be verified by looking at the source, but maybe it's not necessary.

Instead, I'm going to implement a simpler solution: since all these config writes are redundant, we can check if the write would be a no-op and avoid writing in that case.

I'm not familiar with the PHP internals, but if file_put_content's fopen-equivalent call is actually the equivalent of a fopen( ..., 'w' ) (i.e. truncating the file), then the locking also happens too late. As above, this could probably be verified by looking at the source, but maybe it's not necessary.

I ended up verifying anyway. When LOCK_EX is passed, the file is opened in 'c' mode (ref) and truncated later. So, having readers call flock would be sufficient to fix this. However, I'm still going with the "prevent pointless writes" approach anyway, rather than updating all reads: there's not just the bootstrap, but also PHPUnitConfigTest... And presumably PHPUnit itself also needs to open this file :)

Change #1250098 had a related patch set uploaded (by Daimona Eaytoy; author: Daimona Eaytoy):

[mediawiki/core@master] phpunit: Avoid unnecessary writes in generatePHPUnitConfig.php

https://gerrit.wikimedia.org/r/1250098

Is there any reason each of the PHPUnit process reads from the same shared phpunit.xml? Would it be possible to generate the config for each subprocess to a temporary file and point the child PHPUnit processes to them? That'll save you from having to manage a file lock. Then I haven't looked at the code or what it is aiming at so feel free to dismiss :)

Change #1250098 merged by jenkins-bot:

[mediawiki/core@master] phpunit: Avoid unnecessary writes in generatePHPUnitConfig.php

https://gerrit.wikimedia.org/r/1250098

IIUIC this is supposed to be fixed by rMWc47f1b756d46: Generate local PHPUnit config before preparing parallel runs, but the error is still happening:

15:01:26 Error in bootstrap script: RuntimeException:
15:01:26 The PHPUnit config override does not appear to be auto-generated. Generate it manually by running `composer phpunit:config`, or automatically by running tests via `composer phpunit`.
15:01:26 #0 /workspace/src/vendor/phpunit/phpunit/src/Util/FileLoader.php(66): include_once()
15:01:26 #1 /workspace/src/vendor/phpunit/phpunit/src/Util/FileLoader.php(49): PHPUnit\Util\FileLoader::load()
15:01:26 #2 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(567): PHPUnit\Util\FileLoader::checkAndLoad()
15:01:26 #3 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(347): PHPUnit\TextUI\Command->handleBootstrap()
15:01:26 #4 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(114): PHPUnit\TextUI\Command->handleArguments()
15:01:26 #5 /workspace/src/vendor/phpunit/phpunit/src/TextUI/Command.php(99): PHPUnit\TextUI\Command->run()
15:01:26 #6 /workspace/src/vendor/phpunit/phpunit/phpunit(107): PHPUnit\TextUI\Command::main()
15:01:26 #7 /workspace/src/vendor/bin/phpunit(122): include('...')
15:01:26 #8 {main}
15:01:26 Script phpunit handling the phpunit event returned with error code 1
15:01:26 Script @phpunit was called via phpunit:entrypoint
15:01:26 Worker exited with status 1

It should've been fixed by r1250098, merged yesterday, so not yet included in wmf/1.46.0-wmf.19 (which is what that build failed on). It took a few attempts to identify why it was still failing despite the config being autogenerated.

Is the fix easy to backport? It's nice not to have CI breaks in live production branches.

Change #1251106 had a related patch set uploaded (by Daimona Eaytoy; author: Daimona Eaytoy):

[mediawiki/core@wmf/1.46.0-wmf.19] phpunit: Avoid unnecessary writes in generatePHPUnitConfig.php

https://gerrit.wikimedia.org/r/1251106

Is the fix easy to backport? It's nice not to have CI breaks in live production branches.

I made a patch, it had a conflict to fix but a simple one, and it's just test code anyway.

Change #1251106 merged by jenkins-bot:

[mediawiki/core@wmf/1.46.0-wmf.19] phpunit: Avoid unnecessary writes in generatePHPUnitConfig.php

https://gerrit.wikimedia.org/r/1251106

Mentioned in SAL (#wikimedia-operations) [2026-03-12T20:35:55Z] <tgr@deploy2002> Started scap sync-world: Backport for [[gerrit:1251087|Set 'sub' JWT field in client credentials access tokens (T417278)]], [[gerrit:1251088|Set 'sub' JWT field in client credentials access tokens (T417278)]], [[gerrit:1251106|phpunit: Avoid unnecessary writes in generatePHPUnitConfig.php (T419107)]]

Mentioned in SAL (#wikimedia-operations) [2026-03-12T20:37:42Z] <tgr@deploy2002> tgr, daimona: Backport for [[gerrit:1251087|Set 'sub' JWT field in client credentials access tokens (T417278)]], [[gerrit:1251088|Set 'sub' JWT field in client credentials access tokens (T417278)]], [[gerrit:1251106|phpunit: Avoid unnecessary writes in generatePHPUnitConfig.php (T419107)]] synced to the testservers (see https://wikitech.wikimedia.org/wiki/Mwdebug). Changes can now be verified there.

Mentioned in SAL (#wikimedia-operations) [2026-03-12T20:43:32Z] <tgr@deploy2002> Finished scap sync-world: Backport for [[gerrit:1251087|Set 'sub' JWT field in client credentials access tokens (T417278)]], [[gerrit:1251088|Set 'sub' JWT field in client credentials access tokens (T417278)]], [[gerrit:1251106|phpunit: Avoid unnecessary writes in generatePHPUnitConfig.php (T419107)]] (duration: 07m 37s)