Problem/Motivation

Fresh D9 git clone, with only composer install and a core/phpunit.xml added:

$ time vendor/bin/phpunit --configuration core/phpunit.xml core/modules/ckeditor5/tests/src/Kernel/ValidatorsTest.php 
PHPUnit 8.5.21 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\ckeditor5\Kernel\ValidatorsTest
..............................                                    30 / 30 (100%)

Time: 20.33 seconds, Memory: 8.00 MB

OK (30 tests, 50 assertions)

real	0m20.421s
user	0m8.002s
sys	0m11.805s

versus in my dev environment, where I've got 57 contrib modules installed, with most of them git clones (for development), it takes 3.6 times longer:

$ time vendor/bin/phpunit --configuration core/phpunit.xml core/modules/ckeditor5/tests/src/Kernel/ValidatorsTest.php
PHPUnit 8.5.21 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\ckeditor5\Kernel\ValidatorsTest
..............................                                    30 / 30 (100%)

Time: 1.2 minutes, Memory: 8.00 MB

OK (30 tests, 50 assertions)

real	1m12.087s
user	0m17.227s
sys	0m53.724s

Steps to reproduce

  1. Install many modules, preferably using git clone
  2. Do development on them, and have a few modules with a node_modules directory (find them using find . -name 'node_modules' -type d -prune from your Druapl root)

Proposed resolution

  1. drupal_phpunit_contrib_extension_directory_roots() lists every directory that could contain Drupal extensions. Each of those is passed to drupal_phpunit_find_extension_directories(), which scans them recursively … INFINITELY!.

    Ironically, @sun warned all of us about this 7 years ago: https://www.php.net/manual/en/class.recursivedirectoryiterator.php#114504

    Search results only turned up #2900208: Improve performance of functional tests by caching Drupal installations — but that's about speeding up the DB installation part of functional tests. This is about discovering the tests in the first place.

    Fixing this brings it down to:

    $ time vendor/bin/phpunit --configuration core/phpunit.xml core/modules/ckeditor5/tests/src/Kernel/ValidatorsTest.php
    PHPUnit 8.5.21 by Sebastian Bergmann and contributors.
    
    Testing Drupal\Tests\ckeditor5\Kernel\ValidatorsTest
    ..............................                                    30 / 30 (100%)
    
    Time: 56 seconds, Memory: 8.00 MB
    
    OK (30 tests, 50 assertions)
    
    real	0m56.051s
    user	0m15.277s
    sys	0m40.484s
    

    Now it's "only" 2.8 times slower.

  2. This still leaves ~36 seconds performance delta. Still unacceptable. There must be some directory scanning somewhere else.

    Found root cause; fixed in #5, cleaned up in #7. Now only ~2 times slower.

  3. The remaining ~20 second performance delta can only be optimized away in one of two ways: a new caching mechanism (do we really want that in tests?) or tweaking Drupal's PHPUnit bootstrap.php to not construct a fresh autoloader on every run.

    Why does this matter? Because there are two factors that make this very noticeable in day-to-day (core) development:

    • Worse: drupal_phpunit_populate_class_loader() is called every single time you run tests. So it does all this work every time you run tests 🙃
    • Worst: as part of debugging this, I discovered that for each returned value by a @dataProvider, PHPUnit ends up calling drupal_phpunit_populate_class_loader() again. So one test class with a single test method will call it once, but if that single test has a data provider with 10 cases, then the class loader will be computed eleven times. → this part is not addressed in this issue, but it makes the impact of this improvement bigger still…

    I tried two dead-simple caching approaches in #8. First using APCu: it gets stored correctly, but gets wiped immediately. Not sure by what yet. But it's probably going to be hard to get rid of. Second using mtime of the Drupal root. While not perfect, this would allow caching the autoloader (which BTW only needs to be changed when modules are added or removed from disk!), and you'd only have to do touch . in the Drupal root (we could make it listen in more places) to get it to rebuild it.

    Still, this seems to add too much risk and contentiousness to the proposed patch, which now hopefully remains RTBC'able.

🤓 Bonus: I suspect this will also speed up DrupalCI…

→ turned out to be true possible but uncertain — see #25 and #28.

Remaining tasks

None.

User interface changes

None.

API changes

API addition: \Drupal\Core\Extension\Discovery\RecursiveGenericExtensionFilterIterator extracted from \Drupal\Core\Extension\Discovery\RecursiveExtensionFilterIterator, to keep the complexity of the code for low-level test infrastructure to a minimum. The pre-existing RecursiveExtensionFilterIterator now extends the simpler/more generic RecursiveGenericExtensionFilterIterator.

Data model changes

None.

Release notes snippet

TBD

Issue fork drupal-3249443

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

Wim Leers created an issue. See original summary.

wim leers’s picture

Status: Active » Needs review
StatusFileSize
new1.82 KB
longwave’s picture

Duplicate of #3223881: Speed up test discovery with \RecursiveCallbackFilterIterator?

edit: and you even came up with basically the same approach :)

Wim Leers credited sun.

wim leers’s picture

StatusFileSize
new3.64 KB
new3.58 KB

#2 passed tests! It finished testing in 59 minutes, versus 60 minutes for 9.3.x — too little a difference to be confident it is helping.

Explain the remaining performance delta

This still leaves ~36 seconds performance delta. Still unacceptable. There must be some directory scanning somewhere else. Working on it…

Looks like this is mighty difficult to analyze because it requires cross-process PHP debugging … since the PHPUnit process is triggering individual requests to be built.

I suspect that it's simply because there are still far more directories to analyze in the "dev" vs "fresh" envs. So let's observe the performance delta for a simpler (faster) test:

$ time vendor/bin/phpunit --configuration core/phpunit.xml core/modules/ckeditor5/tests/src/Kernel/ConfigurablePluginTest.php 
PHPUnit 8.5.21 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\ckeditor5\Kernel\ConfigurablePluginTest
.                                                                   1 / 1 (100%)

Time: 889 ms, Memory: 6.00 MB

OK (1 test, 1 assertion)

real	0m0.936s
user	0m0.311s
sys	0m0.615s

vs

$ time vendor/bin/phpunit --configuration core/phpunit.xml core/modules/ckeditor5/tests/src/Kernel/ConfigurablePluginTest.php
PHPUnit 8.5.21 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\ckeditor5\Kernel\ConfigurablePluginTest
.                                                                   1 / 1 (100%)

Time: 2.84 seconds, Memory: 8.00 MB

OK (1 test, 1 assertion)

real	0m2.896s
user	0m0.725s
sys	0m2.149s

… yep, still ~3x slower! So it really is still just that. What I did in #2 doesn't go far enough.

Dig more

I did some more digging, because if tests are slow then surely Drupal itself must be slow too, right?

That's how I ended up finding RecursiveExtensionFilterIterator introduced by #2188661: Extension System, Part II: ExtensionDiscovery, which is where @sun actually did the work that led to him posting https://www.php.net/manual/en/class.recursivedirectoryiterator.php#114504 🤪

Why … reinvent the wheel and not just reuse that? Simply doing that gets us to a point where the number of modules installed and complexity of directory trees used in development (git/npm/…) does not matter at all anymore, because it brings performance to 2x:

$ time vendor/bin/phpunit --configuration core/phpunit.xml core/modules/ckeditor5/tests/src/Kernel/ConfigurablePluginTest.php
PHPUnit 8.5.21 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\ckeditor5\Kernel\ConfigurablePluginTest
.                                                                   1 / 1 (100%)

Time: 1.9 seconds, Memory: 8.00 MB

OK (1 test, 1 assertion)

real	0m1.956s
user	0m0.507s
sys	0m1.432s

+

$ time vendor/bin/phpunit --configuration core/phpunit.xml core/modules/ckeditor5/tests/src/Kernel/ValidatorsTest.php 
PHPUnit 8.5.21 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\ckeditor5\Kernel\ValidatorsTest
..............................                                    30 / 30 (100%)

Time: 43.23 seconds, Memory: 8.00 MB

OK (30 tests, 50 assertions)

real	0m43.313s
user	0m12.396s
sys	0m30.191s
wim leers’s picture

StatusFileSize
new619 bytes
new3.65 KB

phpcs

wim leers’s picture

Issue summary: View changes
StatusFileSize
new13.07 KB
new12.28 KB

#3 #5 makes things more complicated. It's overriding a class in a special place. It'd be far better and less risky if the test suite didn't reuse the more complex pieces of RecursiveExtensionFilterIterator.

To address that, I extracted the simple foundations of that class into RecursiveGenericExtensionFilterIterator and made that the base class for the pre-existing logic in core. That allows the test to use as little code from Drupal core as possible.

wim leers’s picture

Assigned: »

It is so unfortunate that the remaining ~20 second performance delta is still there, because it really is extremely silly: all that time is going to rebuilding exactly the same class autoloader again and again and again … even though it will only be different when modules are added/removed from disk! 😮‍💨

I tried two dead-simple caching approaches:

  1. First using APCu: it gets stored correctly, but gets wiped immediately. Not sure by what yet. But it's probably going to be hard to get rid of.
  2. Second using mtime of the Drupal root. While not perfect, this would allow caching the autoloader (which BTW only needs to be changed when modules are added or removed from disk!), and you'd only have to do touch . in the Drupal root (we could make it listen in more places) to get it to rebuild it.

Still, this seems to add too much risk and contentiousness to the proposed patch, which now hopefully remains RTBC'able. So only adding these as do-not-test patches.

wim leers’s picture

Ugh, d.o ate my patches… and it broke the "assigned" state change and also didn't mention I updated the issue summary 😬

EDIT: nope, it didn't eat them, it just didn't list them. I'll add manual links to #8…

wim leers’s picture

@longwave in #3: 😬 wow, I spent 30 mins searching and couldn't find anything, couldn't believe it. I guess my search-fu is weak :| None of them mention drupal_phpunit_find_extension_directories(), that's probably why.

wim leers’s picture

#7 finished testing in 55 minutes, versus 60 minutes for 9.3.x — now that is a pretty sizable difference!

Queued more tests to see if this delta is reproducible. 🤞

wim leers’s picture

Commented at #3223881-27: Speed up test discovery with \RecursiveCallbackFilterIterator why I believe it may be best to continue in this issue. I'm happy to transfer issue credits of course. In any case already crediting @larowlan because the fact that he built essentially the same technical solution but in a different shape already is an important piece of validation :)

larowlan’s picture

+++ b/core/lib/Drupal/Core/Extension/Discovery/RecursiveGenericExtensionFilterIterator.php
@@ -0,0 +1,113 @@
+ * RecursiveExtensionFilterIterator::$skippedFolders property.

this class name now needs updating

This looks good to me - I'm happy either way.

I've been running my own phpunit.xml for at least 3 years to bypass this problem (and we have an even more optimized one on client projects where we know where tests will live). That's probably why this hasn't been fixed, because phpunit.xml.dist can be freely modified as phpunit.xml - so thank you for also coming back to try and improve this for everyone.

larowlan credited Spokje.

larowlan credited TR.

larowlan credited catch.

larowlan credited daffie.

larowlan’s picture

Crediting participants in the other issue and marking it as a duplicate

larowlan credited drumm.

larowlan’s picture

andypost’s picture

quietone’s picture

I only read the comments and have some suggestions.

  1. +++ b/core/lib/Drupal/Core/Extension/Discovery/RecursiveExtensionFilterIterator.php
    @@ -3,20 +3,11 @@
    + * Filters a RecursiveDirectoryIterator to discover extensions in root folders.
    

    This would be clearer if 'root' was 'Drupal root'.

  2. +++ b/core/lib/Drupal/Core/Extension/Discovery/RecursiveExtensionFilterIterator.php
    @@ -3,20 +3,11 @@
    + * filter implementation hard-codes a range of assumptions. See the
    

    If this is saying see some documentation should there be an @see below to that class. At least, I was looking for it when I read this.

  3. +++ b/core/lib/Drupal/Core/Extension/Discovery/RecursiveExtensionFilterIterator.php
    @@ -130,12 +75,16 @@ public function getChildren() {
    +    // If this is a subdirectory of a base search path, only recurse into the
    

    I have trouble following this paragraph. Maybe it is just me. But it appears to be a duplicate of the comment that is below the if statement. So there are not two copies of this comment, one above the if and one inside.

  4. +++ b/core/lib/Drupal/Core/Extension/Discovery/RecursiveExtensionFilterIterator.php
    @@ -143,26 +92,12 @@ public function accept() {
    +    // Otherwise, respect the parent implementation's conclusion.
    

    Let's not use possessive on implementation. 'Otherwise, respect the implementation of the parent.'

  5. +++ b/core/lib/Drupal/Core/Extension/Discovery/RecursiveGenericExtensionFilterIterator.php
    @@ -0,0 +1,113 @@
    +      // 'config' directories are special-cased here, because every extension
    

    Can we have the first sentence start with a capital letter and remove the hyphen in special-cased. And there are extensions that do not have a config directory.

    'The 'config' directories are a special case because extensions may have a directory named 'config'.

  6. +++ b/core/lib/Drupal/Core/Extension/Discovery/RecursiveGenericExtensionFilterIterator.php
    @@ -0,0 +1,113 @@
    +      // because core happens to have a directory of an actual module that is
    +      // named 'config'. By explicitly testing for that case, we can skip all
    

    Clarify the name of the module and the machine name.

    "because the Configuration Manager module in core has the machine name 'config'."

  7. +++ b/core/lib/Drupal/Core/Extension/Discovery/RecursiveGenericExtensionFilterIterator.php
    @@ -0,0 +1,113 @@
    +      // (whereas it must be located directly in a modules directory).
    

    Not sure what this phrase is telling me. It 'it' the core config module?

  8. +++ b/core/tests/bootstrap.php
    @@ -22,15 +23,22 @@
    +  // symlinks (to allow extensions to be linked from elsewhere), and return
    

    Does this phrase really need to be in parenthesis?

edit: grammar fixes

wim leers’s picture

I wrote this in #11:

#7 finished testing in 55 minutes, versus 60 minutes for 9.3.x — now that is a pretty sizable difference!

That was using PHP 8.0 + MySQL 5.7.

Full list of results:

Env patch in #7 HEAD Δ Δ%
9.3.x + PHP 8.0 + MySQL 5.7 55 mins 60 mins -5 mins -8%
9.4.x + PHP 8.0 + MySQL 5.7 55 mins 60 mins -5 mins -8%
9.3.x + PHP 7.4 + MySQL 5.7 62 mins 64 mins -2 mins -3%
9.3.x + PHP 7.4 + SQLite 3.27 49 mins 51 mins -2 mins -4%

We can run more tests, but the benefits surely seem to hold up. It's interesting that for SQLite there's less impact. The same set of tests runs, so you'd think that the same absolute savings apply there. This seems to suggest that the DrupalCI servers are disk I/O-constrained for MySQL testing; it would seem that the MySQL disk activity (for parallel test jobs: concurrency is set to 15 in the current Drupal core drupalci.yml) slows down the constructing of the class autoloader for every test?

In any case, there seems to be too much data showing a benefit for this to be a coincidence. Saving 8% on the most common test environment (the issue testing default) is quite a nice win I think? 😊

wim leers’s picture

StatusFileSize
new2 KB
new12.44 KB
  1. I agree, but that pushes is beyond 80 chars, so I can't do that. 😞 I went with s/root folders/Drupal root/ — hope you like that.
  2. 👍 Added!
  3. This is a pre-existing comment. I just copy/pasted the comment 😅🙈😂 Removed the duplicate.
  4. 👍 Done.
  5. This is a pre-existing comment, it was only moved from RecursiveExtensionFilterIterator. Did not make changes.
  6. This is a pre-existing comment, it was only moved from RecursiveExtensionFilterIterator. Did not make changes.
  7. This is a pre-existing comment, it was only moved from RecursiveExtensionFilterIterator. Did not make changes.
  8. This is a pre-existing comment, it was only copied from \Drupal\Core\Extension\ExtensionDiscovery::scanDirectory(). Did not make changes.
wim leers’s picture

Issue summary: View changes

Cleaned up & updated issue summary.

wim leers’s picture

Issue summary: View changes

Hm … I see that the tests in #26 took just as long as the HEAD test: 59 minutes. Maybe there is just too much fluctuation to make these numbers comparable? 😬 Somebody with DrupalCI superpowers could run it on the exact same machine to determine whether this is actually helping Drupal core test runs. Meanwhile, updating the issue summary — I don't want to make false claims!

longwave’s picture

There is a lot of variation in DrupalCI runs. I also wonder if disk is even the issue here, the instances have plenty of RAM and have checked out the entire repository shortly before running the tests; to me this would imply that all the directories should be in cache and so while we are saving a bit of CPU time here, it is probably not all that much in terms of wall clock time compared to running the actual test suite.

However as this *does* markedly speed up runs on developer machines where the whole project is not necessarily in RAM already, this is still a good thing to fix.

longwave’s picture

Maybe this should be deferred to a followup but it feels like we should be able to combine a bit more of the test bootstrap and the iterator:

RecursiveExtensionFilterIterator stores this list:

  protected $allowedExtensionTypes = [
    'profiles',
    'modules',
    'themes',
  ];

drupal_phpunit_contrib_extension_directory_roots() builds a lot of lists containing these items:

  $paths = [
    $root . '/core/modules',
    $root . '/core/profiles',
    $root . '/core/themes',
    $root . '/modules',
    $root . '/profiles',
    $root . '/themes',
  ];
  $sites_path = $root . '/sites';
  // Note this also checks sites/../modules and sites/../profiles.
  foreach (scandir($sites_path) as $site) {
    if ($site[0] === '.' || $site === 'simpletest') {
      continue;
    }
    $path = "$sites_path/$site";
    $paths[] = is_dir("$path/modules") ? realpath("$path/modules") : NULL;
    $paths[] = is_dir("$path/profiles") ? realpath("$path/profiles") : NULL;
    $paths[] = is_dir("$path/themes") ? realpath("$path/themes") : NULL;
  }

I wonder if drupal_phpunit_contrib_extension_directory_roots() should start returning the top level directories instead and let RecursiveExtensionFilterIterator handle the modules, profiles and themes subdirectories?

wim leers’s picture

#30: I tried to keep changes to a minimum, but there's definitely more we could do.

longwave’s picture

Status: Needs review » Reviewed & tested by the community

I added some extra logging inside the iterators and the final loop in drupal_phpunit_find_extension_directories(). Before this patch there were 22,156 possible extensions naively returned by the iterator to consider. With the patch applied, there are only 547 entries which exactly matches the set of .info.yml files.

Testing this locally on a core checkout alone there is still an significant improvement. Before the patch:

$ ddev exec vendor/bin/phpunit -c core core/modules/ckeditor5/tests/src/Kernel/ValidatorsTest.php 
PHPUnit 8.5.21 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\ckeditor5\Kernel\ValidatorsTest
..............................                                    30 / 30 (100%)

Time: 19.46 seconds, Memory: 4.00 MB

OK (30 tests, 50 assertions)

After the patch:

$ ddev exec vendor/bin/phpunit -c core core/modules/ckeditor5/tests/src/Kernel/ValidatorsTest.php 
PHPUnit 8.5.21 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\ckeditor5\Kernel\ValidatorsTest
..............................                                    30 / 30 (100%)

Time: 16.61 seconds, Memory: 4.00 MB

OK (30 tests, 50 assertions)

This patch will speed up test runs for any developer using PHPUnit with Drupal. There is nothing left to do here, #30 can be tackled in a followup as it's a cleanup rather than any further performance improvement and so to me this is RTBC.

alexpott’s picture

Status: Reviewed & tested by the community » Needs review

The improvements to local testing look nice. I think though we should ask ourselves about the naming / class structure. I'm concerned about \Drupal\Core\Extension\Discovery\RecursiveGenericExtensionFilterIterator missing

      // If this is a subdirectory of a base search path, only recurse into the
      // fixed list of expected extension type directory names. Required for
      // scanning the top-level/root directory; without this condition, we would
      // recurse into the whole filesystem tree that possibly contains other
      // files aside from Drupal.
      if ($this->current()->getSubPath() == '') {
        return in_array($this->current()->getFilename(), $this->allowedExtensionTypes, TRUE);
      }

I think that we can do this all with less new code and different code paths (eventually).

If drupal_phpunit_contrib_extension_directory_roots returned:

[
  $root . '/core',
  $root,
  $root . '/sites' . $site, // It'll have to find all...
]

Then we would need two Iterators.

alexpott’s picture

Also I think we can improve things for contrib and custom by doing what ExtensionDiscovery does and passing $ignore_directories into the \Drupal\Core\Extension\Discovery\RecursiveExtensionFilterIterator::__construct... so we skip node_modules by default.

    // Allow directories specified in settings.php to be ignored. You can use
    // this to not check for files in common special-purpose directories. For
    // example, node_modules and bower_components. Ignoring irrelevant
    // directories is a performance boost.
    $ignore_directories = Settings::get('file_scan_ignore_directories', []);

alexpott’s picture

StatusFileSize
new7.46 KB

Something like this.

No interdiff because it's a different approach.

alexpott’s picture

StatusFileSize
new2.93 KB
new7.47 KB

Fixing coding standards.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

borisson_’s picture

Issue tags: +Bug Smash Initiative

Reading this issue summary is great! So much detailed information.
I would love to see performance differences between #26 and #36 because they are different approaches. So story in the IS is probably not exactly right anymore if we decided to follow that approach?

alex.skrypnyk’s picture

Tested #37 with 9.4 - works great.

The speed improvement on large codebase with multiple `node_modules` directories is significant (30s vs 10s).

One issue is that when running Unit tests settings are not picked up and this line $ignore_directories = Settings::get('file_scan_ignore_directories', []); will always return empty array. But maybe I ran it incorrectly. Manually populating that return value with ['node_modules'] did the trick.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new144 bytes

The Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

alex.skrypnyk’s picture

StatusFileSize
new7.73 KB

Re-rolled #37 for 9.5.x with the following changes:
1. Fixed $ignore_directories = Settings::get('file_scan_ignore_directories', []); not working as settings has not been initialised yet.
2. Updated deprecation messages to point to 9.6.x

alex.skrypnyk’s picture

When testing custom modules or themes using Drupal Core's PHPUnit configuration file, core/phpunit.xml.dist, note that the core/tests/bootstrap.php file scans all extension roots (core, modules, themes, etc.), and there is currently no way to opt out of this behavior. While we may want to use Drupal Core's bootstrap file to reuse PHPUnit behavior when testing custom modules or themes within real sites, we may not want to use the same targets.

In practice, the current implementation of core/tests/bootstrap.php can lead to longer test execution times that scale proportionally with the number of installed modules. For instance, if you have a site with 100 contributed modules and one custom module with 1 unit test, running that test will scan through core and 100s of contributed modules to then only run one test in your custom module.

And if you run these tests in a Docker container, the performance degradation can be even worse due to PHP's constant checking for directory and file existence while performing such a lookup.

UPDATE: Found https://www.drupal.org/project/drupal/issues/2943172

larowlan’s picture

We've been running the version from #3223881: Speed up test discovery with \RecursiveCallbackFilterIterator with our phpunit.xml referencing a custom bootstrap.php for ~4 years. You just need to update it from time to time as the major phpunit version changes.

mxr576’s picture

@alex.skrypnyk thanks for finding the other issue where I was also involved, or made an attempt to make a related change...

+ $ignore_directories = Settings::get('file_scan_ignore_directories', []);

I did the some, but @Lendude might have a valid point on the other issue

Also, are we really sure we want to re-use an existing setting? Does 'file_scan_ignore_directories' always match the pattern we want to use here? The current use case is to ignore dirs where we look for modules, do we really want to add 'and where we look for tests' to that? Sure, there might be a lot of overlap, but is this always 100%?

(Source https://www.drupal.org/project/drupal/issues/2943172#comment-13216764)

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

wim leers’s picture

@larowlan just reminded me of this. Still would be very nice to land this.

P.S.: I forgot I even created this. @larowlan talked about #3050881: Use RecursiveExtensionFilterIterator in drupal_phpunit_find_extension_directories for performance and then told me it's a duplicate of "mine" — this issue 🤣

mfb’s picture

I noticed that it recurses through .git directories too - that wouldn't be as bad as node_modules but, still seems like a waste

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

catch’s picture

Issue tags: +Test suite performance

longwave-bot made their first commit to this issue’s fork.

longwave’s picture

Status: Needs work » Needs review

Let's try and revive this, opened an MR with the simplest change that should work.

longwave’s picture

Added a static method to ExtensionDiscovery so we can reuse some code.

nicxvan’s picture

This is a good start, I wonder if this should be in the extension system since it's about extension discovery.

I think we'd want to patch this in contrib before we release this to make sure tests work properly still.

smustgrave’s picture

Any recommendation for testing this one?

Is the summary still accurate?