Problem/Motivation
At present our test discovery scans every folder in some key places to try and find any that contain an .info.yml file and hence could contain a module/theme etc.
Unfortunately, this means we're scanning folders where we know for sure modules can't be put including
- .git folders - if you work on core and contrib from the same space, you're likely to have a lot of .git folders - one for each contrib project
- src folder - this is only OO code, and will never hold modules
- config/install config/schema - for obvious reasons
Steps to reproduce
Start a timer at the top of bootstrap.php
Stop the timer at the end of the file.
Output the time.
For my local setup its 30sec on discovery alone.
Proposed resolution
Add a RecursiveCallbackFilterIterator to the iterator, and filter out folders we know don't contain modules.
We can use some of the list from RecursiveExtensionFilterIterator
With the attached patch discovery goes from 30sec to 5sec on my local.
Remaining tasks
Reviews
User interface changes
API changes
Data model changes
Release notes snippet
Comments
Comment #2
larowlanComment #3
larowlanwhoops
Comment #4
berdirInteresting. The actual .info.yml/module discovery has an exclusion list too, could we share that somehow. Will need to look up where that is.
Comment #5
andypostComment #6
larowlandrumm pointed out that icons is a valid module, so this has to go
Comment #7
larowlan@Berdir yeah I borrowed the starting point from
RecursiveExtensionFilterIteratorComment #8
tr commentedElsewhere we use ExtensionDiscovery, why not here? ExtensionDiscovery already excludes .git among other things. And ExtensionDiscovery already has built-in support for designating directories to ignore. Perhaps improve that if necessary and use it for test discovery as well?
Comment #9
larowlanI've been down that road before in #3050881: Use RecursiveExtensionFilterIterator in drupal_phpunit_find_extension_directories for performance
In that issue dawehner asked
And that's the same question for ExtensionDiscovery.
The new approach here is only using built-in PHP features so we're not making tests rely on code they're testing.
Comment #10
tr commentedYou can turn that around and ask if it's OK to use untested code like
drupal_phpunit_find_extension_directories()to run our tests. What if your code doesn't work as expected - do we have any way of knowing this? The excessive time taken to scan .git directories is something that wouldn't have ever happened if we used the well-tested core methods for extension discovery, as those methods get a lot of scrutiny when running on live sites. Maintaining a separate code base just for tests pretty much ensures that things will be done differently and that improvements in one or the other might not be cross-ported.I would say it makes the most sense to use *exactly* the same code to find .info.yml files in both core and in the tests.
Comment #11
tr commentedAlso, you didn't mention that when you quoted @dawehner asking:
the very next sentence says:
So the way I read it, @dawehner is saying that yes, it's OK in this case to use ExtensionDiscovery.
Comment #12
larowlanTo be clear, I'm happy with either approach, because I'm tired of waiting 30sec before PHPUnit even boots up.
On all our projects we've been running a version of #3050881: Use RecursiveExtensionFilterIterator in drupal_phpunit_find_extension_directories for performance for at least 2 years.
We just reference a custom bootstrap.php from phpunit.xml. I'm doing the same for my core/contrib folder too, even if it means from time to time I need to cherry-pick in changes from upstream.
But it would be great to get this fixed for everyone.
Comment #13
andypostComment #14
longwaveThe timer bits are causing PHPCS to fail.
Comment #15
vsujeetkumar commentedFixing PHPCS issues, Please have a look.
Comment #16
daffie commentedTestbot is not happy.
Comment #17
spokjeTrying to please TestBot and addressing #6.
Comment #18
spokjeSending any output to the console breaks the JSON output testing in
Drupal\Tests\Scripts\TestSiteApplicationTest.Since I wanted to see what the difference was between the times for bootstrapping with and without this patch, I took a stab at it here #3191612-47: [Ignore] In space (and/or this issue), no one can hear patches scream
Since the "timing-shizzle" isn't really required to get this patch in IMHO, I've included a patch here without the Timer to see if TestBot is happy with that.
Comment #19
spokjeComment #20
daffie commentedAll the code changes look good to me.
I have tested the speed change myself. There is a large speed improvement.
I do not see how we can get a test for this, other than a manual one.
For me it is RTBC.
For the committer: User @drumm also deserves a commit credit.
Comment #21
catchThere's an 'src' module. No code in it, but unless we introduce a list of reserved words for modules somehow I'm not sure we can do this.
https://www.drupal.org/project/src
Comment #23
catchComment #24
larowlanThe src module is not discoverable in D8+
See https://git.drupalcode.org/project/drupal/-/blob/9.2.x/core/lib/Drupal/C...
Comment #25
catchCan we add an @see to RecursiveExtensionFilterIterator? Marking needs work for that.
Also I think it's worth exploring just using that directly, but could be a follow-up.
Comment #26
larowlanCan do - we had #3050881: Use RecursiveExtensionFilterIterator in drupal_phpunit_find_extension_directories for performance for that, which I closed in favour of this.
I'm happy to close this in favour of that if you'd prefer it - please advise.
With the approach here, there's more code to maintain, but we're not relying on code that were testing in our tests.
The approach there is closer to what core is doing, but as dawehner points out - we're using production code to bootstrap tests, to test production code so there's a bit of a circular dependency.
Comment #27
wim leers@longwave pointed out that I basically duplicated this, see #3249443-10: drupal_phpunit_find_extension_directories() uses infinite recursion ⇒ more directories = slower tests.
I agree with @TR's assessment here: it's better to not duplicate code; it's better to use the same foundational discovery logic for finding extensions inside tests and outside tests.
But … I did have concerns around this too. Which is why I ended up with a hybrid approach: extract the absolute essentials out of
RecursiveExtensionFilterIteratorintoRecursiveGenericExtensionFilterIterator. Make the original class extend the new class, and add the special stuff. Let the test use the extracted (simpler) class.Currently awaiting test results at #3249443-11: drupal_phpunit_find_extension_directories() uses infinite recursion ⇒ more directories = slower tests, but it looks like this could be making Drupal core test runs ~8% faster.
I really wish I'd found this issue, then I'd have pushed this forward. But now it seems like the most pragmatic way forward here is for you to review what I proposed, @larowlan? I did uncover some facets/further improvements that are not yet mentioned here nor in #3050881: Use RecursiveExtensionFilterIterator in drupal_phpunit_find_extension_directories for performance 😇
Comment #28
larowlan#3249443: drupal_phpunit_find_extension_directories() uses infinite recursion ⇒ more directories = slower tests