Problem/Motivation

Every day you get one more yard.
You take it on faith; you take it to the heart.
The waiting is the hardest part.

In #2917655: [9.4.x only] Drop official PHP 7.3 support in Drupal 9.4, we discovered that QuickStartTest will wait forever for expected installer errors that never appear. The process timeout does not work. See https://dispatcher.drupalci.org/job/drupal_patches/115031/console for an example of the test timing out on the DrupalCI maximum execution time of 110 minutes (for a unit test that is normally done in less than a minute).

Proposed resolution

Use the correct APIs for waiting in a Symfony Process.

The current merge request replaces the while loops in QuickStartTest with situationally appropriate APIs (via @longwave).

#22, #23, and #27 are failing testing patches to prove that the replacements for the while loops now cause the tests to fail properly when the timeout is reached, rather than executing an infinite loop.

Remaining tasks

Need review.

User interface changes

N/A

API changes

N/A

Data model changes

N/A

Release notes snippet

N/A

Issue fork drupal-3265291

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:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

xjm created an issue. See original summary.

xjm’s picture

Status: Active » Needs review
xjm’s picture

I checked and no other core tests that use Symfony\Component\Process\Process have such potentially infinite loops in them.

xjm’s picture

Priority: Major » Critical

Critical really (blocks one, and makes the test un-debuggable).

longwave’s picture

Should we try to use Process::wait() or ::waitUntil() instead of handling this ourselves?

xjm’s picture

I was referring to the Process docs, which say:

For long running commands, it is your responsibility to perform the timeout check regularly:

$process->setTimeout(3600);
$process->start();

while ($condition) {
    // ...

    // check if the timeout is reached
    $process->checkTimeout();

    usleep(200000);

I think Process::wait() is for when you have two asynchronously running processes, and you want one to wait on the other. Whereas this waiting within a single process, using a pattern in the docs.

longwave’s picture

To me the docs mean that you should run the loop yourself if you want to do any other processing while the process runs in the background, but you can use wait() if you just want to wait for it to finish.

In the simple case we can just use the synchronous ::run().

For the more complicated case we can use ::waitUntil(), as implemented in the attached patch.

I also think the 500 second timeout is really excessive; should we drop it to 30?

xjm’s picture

FileSize
1.94 KB

Here's a test patch which should prove that the timeouts are now working as expected. Edit: Crosspost.

xjm’s picture

I also think the 500 second timeout is really excessive; should we drop it to 30?

That seems risky; I wouldn't want to introduce a bunch of unpredictable random fails due to slow testbots. We should look back at the issue that added it originally and see if there's justification for the choice there.

xjm’s picture

The 500 timeout was added with the original introduction of the quick-start command.

xjm’s picture

Yeah, I read over the original issue and people were getting timeouts at 300 seconds, so they increased it to 500. This was probably with Composer 1, mind, so we might not need such a timeout anymore in D10. Still, I think it's best to keep it for now. 500 seconds is much better than the effectively infinite timeout currently. ;)

xjm’s picture

The fail-only patch in #9 fails as expected and proves that the timeouts are now working.

#8 fails QuickStartTest with:

[ayrton:core | Fri 13:02:53] $ ../vendor/bin/phpunit tests/Drupal/Tests/Core/Command/QuickStartTest.php
PHPUnit 8.5.21 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\Core\Command\QuickStartTest
.SF..                                                               5 / 5 (100%)

Time: 8.87 seconds, Memory: 6.00 MB

There was 1 failure:

1) Drupal\Tests\Core\Command\QuickStartTest::testQuickStartInstallAndServerCommands
Failed asserting that 'Drupal development server started: <http://127.0.0.1:8896>\n
This server is not meant for production use.\n
' contains "127.0.0.1:8896/user/reset/1/".

/Users/xjm/git/drupal-test-site/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php:119
/Users/xjm/git/drupal-test-site/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php:55
/Users/xjm/git/drupal-test-site/core/tests/Drupal/Tests/Core/Command/QuickStartTest.php:212
/Users/xjm/git/drupal-test-site/vendor/phpunit/phpunit/src/Framework/TestResult.php:703

FAILURES!
Tests: 5, Assertions: 10, Failures: 1, Skipped: 1.

The last submitted patch, , failed testing. View results

ressa’s picture

I am just following along here from the sideline, but loving the Tom Petty reference. And what a fine song, all the way from 1981: https://www.youtube.com/watch?v=uMyCa35_mOg

The frustration of the waiting can be excruciating. You start ... and wait ... and it breaks. Argh. That's also why I am so thankful for the gradual improvements in the Drupal code you all are working on here, as well as Composer with version 2.2. Every second (or even millisecond) counts.

xjm’s picture

@ressa :)

I tested #8 locally and confirmed that it does make the processes respect the timeout; shortening the timeout to 1 second fails as expected. I also tested with the original change from #2917655: [9.4.x only] Drop official PHP 7.3 support in Drupal 9.4 on PHP 7.3 and confirmed that the test now times out correctly rather than getting stuck in an infinite loop. So that's probably a better approach; we just need to get that third hunk working.

xjm’s picture

Status: Needs review » Needs work
xjm’s picture

xjm’s picture

I moved #8 to a new MR and I think I fixed it.

xjm’s picture

Patch of this combined with #2917655: [9.4.x only] Drop official PHP 7.3 support in Drupal 9.4 to demonstrate that PHP 7.3 should now time out properly rather than waiting forever.

xjm’s picture

And, a version with artificially low timeouts to prove the other cases will time out properly as well.

Status: Needs review » Needs work

The last submitted patch, 23: 3265291-23-FAIL.patch, failed testing. View results

xjm’s picture

#22 has:

Command.Drupal\Tests\Core\Command\QuickStartTest
✗	
Drupal\Tests\Core\Command\QuickStartTest
exception: [Other] Line 0 of sites/default/files/simpletest/phpunit-105.xml:
PHPUnit Test failed to complete; Error: PHPUnit 8.5.21 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\Core\Command\QuickStartTest
SES..                                                               5 / 5 (100%)

Time: 8.36 minutes, Memory: 4.00 MB

There was 1 error:

1) Drupal\Tests\Core\Command\QuickStartTest::testPhpRequirement
Symfony\Component\Process\Exception\ProcessTimedOutException: The process "'/usr/local/bin/php' 'core/scripts/drupal' 'quick-start' 'standard' '--site-name='\''Test site test32770308'\''' '--suppress-login'" exceeded the timeout of 500 seconds.

/var/www/html/vendor/symfony/process/Process.php:1254
/var/www/html/vendor/symfony/process/Process.php:430
/var/www/html/vendor/symfony/process/Process.php:251
/var/www/html/core/tests/Drupal/Tests/Core/Command/QuickStartTest.php:158
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestResult.php:703

ERRORS!
Tests: 5, Assertions: 2, Errors: 1, Skipped: 2.
✗	
Unknown

#23 has:

Drupal\Tests\Core\Command\QuickStartTest
exception: [Other] Line 0 of sites/default/files/simpletest/phpunit-105.xml:
PHPUnit Test failed to complete; Error: PHPUnit 9.5.14 by Sebastian Bergmann and contributors.

Warning:       Your XML configuration validates against a deprecated schema.
Suggestion:    Migrate your XML configuration using "--migrate-configuration"!

Testing Drupal\Tests\Core\Command\QuickStartTest
ES...                                                               5 / 5 (100%)

Time: 00:10.072, Memory: 4.00 MB

There was 1 error:

1) Drupal\Tests\Core\Command\QuickStartTest::testQuickStartCommand
Symfony\Component\Process\Exception\ProcessTimedOutException: The process "'/usr/local/bin/php' 'core/scripts/drupal' 'quick-start' 'standard' '--site-name='\''Test site test54067442'\''' '--suppress-login'" exceeded the timeout of 1 seconds.

/var/www/html/vendor/symfony/process/Process.php:1254
/var/www/html/vendor/symfony/process/Process.php:471
/var/www/html/core/tests/Drupal/Tests/Core/Command/QuickStartTest.php:116
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestResult.php:726

testQuickStartInstallAndServerCommands() doesn't seem to be timing out, though.

xjm’s picture

Status: Needs work » Needs review
FileSize
2.59 KB
944 bytes

Ah, this will prove the timeout works for the last case -- it needs a failing condition.

xjm’s picture

With a dictionary word.

Status: Needs review » Needs work

The last submitted patch, 27: 3265291-27-FAIL.patch, failed testing. View results

xjm’s picture

There we go:

Drupal\Tests\Core\Command\QuickStartTest
exception: [Other] Line 0 of sites/default/files/simpletest/phpunit-105.xml:
PHPUnit Test failed to complete; Error: PHPUnit 9.5.14 by Sebastian Bergmann and contributors.

Warning:       Your XML configuration validates against a deprecated schema.
Suggestion:    Migrate your XML configuration using "--migrate-configuration"!

Testing Drupal\Tests\Core\Command\QuickStartTest
.SE..                                                               5 / 5 (100%)

Time: 00:20.367, Memory: 4.00 MB

There was 1 error:

1) Drupal\Tests\Core\Command\QuickStartTest::testQuickStartInstallAndServerCommands
Symfony\Component\Process\Exception\ProcessTimedOutException: The process "'/usr/local/bin/php' 'core/scripts/drupal' 'server' '--suppress-login'" exceeded the timeout of 1 seconds.

/var/www/html/vendor/symfony/process/Process.php:1254
/var/www/html/vendor/symfony/process/Process.php:471
/var/www/html/core/tests/Drupal/Tests/Core/Command/QuickStartTest.php:211
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestResult.php:726

This is ready for review again.

xjm’s picture

Issue summary: View changes

Updating the IS with a little more detail.

neclimdul’s picture

Are we sure this isn't just hitting the race condition that was identified several years ago? #2975644: Random Failure in Drupal\Tests\Core\Command\QuickStartTest There's a pretty simple fix.

xjm’s picture

@neclimdul, not in this case. It's definitely a 100% consistent fail non-failing infinite loop whenever the conditions those three tests are looking for are not met (for example, if the behavior of MINIMUM_SUPPORTED_PHP is changed). See the console output linked in the IS. Edit: Or if it's a race condition, the race is with infinity. ;)

It appears the tests were written with the assumption that built-in Process API for timeouts would terminate the test when needed despite the potentially infinite loops (programming 101...). However, Symfony's docs clearly indicate that the way the test was written before would have required manual checkTimeout() calls. I think @longwave's approach is cleaner though by using the actual API provided, which also works as proved in the test patches.

xjm’s picture

I think @longwave's approach will also fix #2975644: Random Failure in Drupal\Tests\Core\Command\QuickStartTest FWIW. Different bugs, one fix.

neclimdul’s picture

It doesn't. The first test I ran with these changes immediately failed. It looks like you can see the failure in the results on #8.

neclimdul’s picture

Status: Needs review » Reviewed & tested by the community

Weird, I just ran it for an hour and it worked and I see where the fix similar to 2975644 is so probably good.

xjm’s picture

@neclimdul, lol yep, I hacked those 500s timeouts down to 30s and then 1s locally so that it would complete sooner in the failing cases. Sounds like @longwave did too.

The fail in #8 was due to the loop exiting when only part of the output had been sent. I fixed that in 2f7382fab2.

xjm credited Spokje.

xjm’s picture

Adding credit for @Spokje, who was the one who figured out that this test was the reason #2917655: [9.4.x only] Drop official PHP 7.3 support in Drupal 9.4 was timing out.

neclimdul’s picture

Yeah, that race in #8 was what I documented in #21 in the other issue. 🤷 went ahead and closed it.

  • catch committed c97eb13 on 10.0.x
    Issue #3265291 by xjm, neclimdul, longwave, Spokje: QuickStartTest: The...
  • catch committed fbf951e on 9.3.x
    Issue #3265291 by xjm, neclimdul, longwave, Spokje: QuickStartTest: The...
  • catch committed df17f23 on 9.4.x
    Issue #3265291 by xjm, neclimdul, longwave, Spokje: QuickStartTest: The...
catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed to 10.0.x, cherry-picked to 9.4.x and 9.3.x, thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.