[BUGFIX] Skip class loading info dump in Composer mode#730
Conversation
Testbase::dumpClassLoadingInformation() is called unconditionally, also from the unit test bootstrap, which runs in the scope of the outer Composer installation. TYPO3 v14.3.1 changed where the classic mode autoload information of the testing context is written: the dump directory is now derived from Environment::getExtensionsPath(), which resolves to "<projectRoot>/packages/ext" in Composer mode. Unit test runs therefore create "<projectRoot>/packages/autoload-tests/", colliding with the directory many projects use for their own local extensions. That dump is a no-op in Composer mode anyway, because PackageManager::scanAvailablePackages() bails out early there and leaves UnitTestPackageManager without any registered package. The generated files have always been empty in that case, on v13 as well - only their location changed, from build output to the project root. Skip the dump in Composer mode, mirroring the guard TYPO3 Core uses on all of its own call sites. Functional tests are unaffected: setUpBasicTypo3Bootstrap() forces Composer mode to false, so their instances keep receiving the class loading information they need for their fixture extensions. The Core mono repository keeps its current behaviour for the same reason. Note that a "packages/autoload-tests/" directory left behind by an earlier test run has to be removed manually once. Resolves: #725 Releases: main, 9
|
Additional verification against Vendored
Commands used: rm -rf vendor/ packages/ composer.lock && \
Build/Scripts/runTests.sh -t 13 -p 8.2 -s composerUpdate && \
Build/Scripts/runTests.sh -t 13 -p 8.2 -s unit && \
Build/Scripts/runTests.sh -t 13 -p 8.2 -s functional && \
rm -rf vendor/ packages/ composer.lock && \
Build/Scripts/runTests.sh -t 14 -p 8.2 -s composerUpdate && \
Build/Scripts/runTests.sh -t 14 -p 8.2 -s unit && \
Build/Scripts/runTests.sh -t 14 -p 8.2 -s functionalThe decisive bit: with the guard in place the functional test instances still receive the full classic-mode dump, including the fixture extension and all
'TYPO3\JsonResponse\' => typo3conf/ext/json_response/Classes
'TYPO3\PrivateContainer\' => typo3conf/ext/private_container/Classes
'WebVision\Deepl\Base\' => typo3conf/ext/deepl_base/Classes
'WebVision\Deepl\Base\Core13\' => typo3conf/ext/deepl_base/Core13/Classes
'WebVision\Deepl\Base\Tests\' => typo3conf/ext/deepl_base/Tests
'WebVision\Deepltranslate\Core\' => typo3conf/ext/deepltranslate_core/Classes
'WebVision\Deepltranslate\Core\Core13\' => typo3conf/ext/deepltranslate_core/Core13
'WebVision\Deepltranslate\Core\Core14\' => typo3conf/ext/deepltranslate_core/Core14
'WebVision\Deepltranslate\Core\Testing\' => typo3conf/ext/deepltranslate_core/TestClasses
'WebVision\Deepltranslate\Core\Tests\' => typo3conf/ext/deepltranslate_core/Tests
'WebVision\TestingFrameworkBackendUserHandlerReplacement\'
=> typo3conf/ext/deepltranslate_core/Tests/Functional/Fixtures/Extensions/
testing_framework_backenduserhandler_replacement/Classesplus 100 class map entries, with all five extensions correctly symlinked into the instance's So the guard drops only the empty Composer-mode dump in the outer project scope and leaves the classic-mode instance dump untouched. |
Closes #725
Problem
Testbase::dumpClassLoadingInformation()is called unconditionally — also fromResources/Core/Build/UnitTestsBootstrap.php, which runs in the scope of the outerComposer installation.
TYPO3 v14.3.1 changed where the classic-mode autoload information of the testing context
is written.
ClassLoadingInformation::getClassLoadingInformationDirectory()now derivesthe directory from
Environment::getExtensionsPath(), and that resolves to<projectRoot>/packages/extin Composer mode:getExtensionsPath()(Composer mode)<public>/typo3conf/ext<project>/packages/ext<public>/typo3conf/autoload-tests/<project>/packages/autoload-tests/So every unit test run now creates
<projectRoot>/packages/autoload-tests/— collidingwith the directory many projects use for their own local extensions (the layout documented
in TYPO3's Composer best-practices guide). Previously the same dump landed in the web dir,
i.e. inside gitignored build output, and nobody noticed.
Accountable Core change:
edfb03ae775/770c5383930"[TASK] Allow public folder inclassic mode", forge #109470, Gerrit
93491 /
93799. First released in
v14.3.1 — v14.0/14.2/14.3.0 are not affected, so this is not a testing-framework
version regression but a Core patch-level one.
Why the dump can simply be skipped
It is a no-op in Composer mode and always has been.
PackageManager::scanAvailablePackages()returns early when
Environment::isComposerMode()is true — identical code in v13.4.33 andv14.3.5 — so
UnitTestPackageManagerregisters zero packages and the generated files areempty:
Only the location regressed. Nothing can be lost by not writing them.
Every other consumer of this API in
typo3/cms-core(DumpAutoloadCommand,MaintenanceController,SetupService,ClassLoadingInformationUpdater) already guards onComposer mode.
Testbasewas the only unguarded call site.Functional tests are not affected
This is the important part, because functional test instances genuinely do need the
classic-mode dump for their fixture extensions:
UnitTestsBootstrap.php(extension/project)TYPO3_COMPOSER_MODE→trueUnitTestsBootstrap.php(Core mono-repository)falseTestbase::setUpBasicTypo3Bootstrap()(all functional tests)false(Testbase.php:756)Verified after the change: functional instances still get a non-empty dump at
.Build/Web/typo3temp/var/tests/functional-*/typo3conf/autoload-tests/, with all fixtureand extension PSR-4 prefixes including
…\Tests\, and a 71-line class map.The fix has to live in
Testbase, not inUnitTestsBootstrap.php: that file is boilerplatewhich extensions are encouraged to copy, so guarding it there would not reach any of the
already-copied bootstraps.
No Core bugfix is required —
dirname(getExtensionsPath())is the correct anchor forclassic-mode autoload information, and Core itself never calls the dump in Composer mode.
Steps to reproduce
With
web-vision/deepl-writeonmain(project root ≠ web root,web-dir = .Build/Web):Test results
web-vision/deepl-write, PHP 8.2, testing-framework patched with this change:-s unitpackages/(before:packages/autoload-tests/created)-d sqlite -s functional-s unitpackages/, notypo3conf/autoload-tests/either-d sqlite -s functionalTYPO3 Core mono-repository (
main, v15-dev), PHP 8.4, vendored testing-framework patched:-s unit -- --filter GeneralUtilityTesttypo3conf/autoload-tests/still written, behaviour unchanged-d sqlite -s functional -- typo3/sysext/core/Tests/Functional/Package/-d sqlite -s functional -- typo3/sysext/extbase/Tests/Functional/Persistence/This repository's own gates, PHP 8.2:
-s composerUpdate-s cgl -n-s lint-s phpstan-s unitBranches
Releases: main, 9. Branch9is the branch v14 users actually consume today, so the portshould not lag behind. No core-version-aware conditional is needed there:
Environment::isComposerMode()exists unchanged since v9, and the Composer-mode earlyreturn in
PackageManager::scanAvailablePackages()is identical on v12, v13, v14 and main.Note for users
A
packages/autoload-tests/directory left behind by an earlier test run has to be removedmanually once — this change only stops new ones from being created.