Account created on 12 June 2008, almost 17 years ago
#

Merge Requests

More

Recent comments

🇦🇺Australia mstrelan

#13 - the proposal is not to change all instances everywhere, it is to allow either. Issues to switch from one to another should be closed won't fix unless the maintainers actively want to switch.

🇦🇺Australia mstrelan

Currently someone adding image styles would already need to add the convert action, so I guess this setting would just provide the default format at that point? Or would we look to at the conversion to all image styles? Also, not all image styles have dimensions so I guess the source filesize could be useful there

🇦🇺Australia mstrelan

This is a pretty simple one. In the test we load a page with an iframe and immediately start making assertions about it. But the content of the iframe takes some time to load. Most of the time it's very quick, but if we inject some artificial slowness in to \Drupal\media\Controller\OEmbedIframeController::render then we can reliably reproduce it. On my local it is sufficient to add usleep(50000);.

Here's the failing job (2/500) - https://git.drupalcode.org/issue/drupal-3519621/-/jobs/4992589

Pushing up a fix

🇦🇺Australia mstrelan

Submitted a review but it seems to be the same stuff @longwave already suggested and was apparently fixed, so maybe a rebase went wrong?

🇦🇺Australia mstrelan

Yes but we're talking about whether to convert to AVIF or webp, not whether to run the image style at all.

Right, same thing. In most cases we already know the dimensions of the output. So if the image style is for a small thumbnail, just enable the convert to webp plugin. If it's for a hero image then enable the convert with fallback plugin (or just convert to avif if you know its supported). Point is, the source image could be very large or very small but the output dimensions are the same.

I've attached an example in a zip since we can't upload webp or avif here. Original image is 7.4 MB. When I upload it to the media library we get a thumbnail by default. As a WEBP that's 3.3 KB but if I convert to AVIF it's 2.6 KB. That would fall under the "not worth the CPU cycles" threshold, but since the original is 7.4 MB we convert it anyway.

🇦🇺Australia mstrelan

Some more conversions at 📌 [PP-1] Convert functional tests in navigation module to kernel tests Postponed .

I was able to work around more issues with multiple drupalGet calls, this time with lazy builders. The issue was that we needed to reset the MemoryBackend cache after the first drupalGet. This is something we already do in UiHelperTest by calling $this->refreshVariables. Here is the commit in that issue in case we want to add it here.

But I ran in to another issue - installing modules doesn't reset the hook implementations. So in NavigationDefaultBlockDefinitionTest::testNavigationDefaultBeforeNavigation where it tries to install navigation_test_block first, and navigation later, the hook_page_top implementation in navigation module is never invoked. I'm not sure a way to solve that yet.

🇦🇺Australia mstrelan

I don't think we can generate two outputs to compare and pick one to use. The URL to the file is generated before the file is generated and as catch pointed out they would have different file extensions.

🇦🇺Australia mstrelan

I would have though the threshold would be based on the file size of the original image (e.g. what @andypost says in #6), so wondering why you think it would be useless?

If your image style is a 16x16 pixel thumbnail and your original image is 100MB the JPG thumbnail will still be very small.

🇦🇺Australia mstrelan

I would suggest adding to the new AvifConvert plugin. What is the logic for the threshold, is it the original file size? File size after converting (tricky)? Dimensions? The first one is fairly useless, the second one I think impossible since the derivative won't exist first time, and third one you can just opt not to use the convert plugin on the image style.

🇦🇺Australia mstrelan

I don't think \Drupal\Tests\Composer\Plugin\Scaffold\Fixtures::createIsolatedComposerCacheDir actually works. It creates the dir and sets the env var, but composer doesn't actually use it.

I verified this by putting a breakpoint after the composer require command and inspecting the tmp dir and seeing it's empty. Then I added the following command before composer require and when I step through it the cache gets populated.

$this->mustExec("composer config cache-dir " . getenv('COMPOSER_CACHE_DIR'), $sut);.

So if we want to pre-populate the cache then we need to ensure the cache dir actually works.

🇦🇺Australia mstrelan

You're right, it did, see https://git.drupalcode.org/issue/drupal-3354138/-/jobs/4978417/viewer

I suppose we could run it a few more times to see if it's consistently in that realm, but it's pretty slow (48 mins for 500 runs). Then we'd need to run the fix that many times as well.

🇦🇺Australia mstrelan

Had a look in to this and not sure it is entirely accurate anymore. I started by disabling wifi and running ScaffoldTest, yet it passed every time. Possibly there is a composer cache somewhere, but it passed even after clearing my local composer cache. Regardless, the test apparently creates an isolated cache for each test run.

Then I tried ScaffoldUpgradeTest, but it is currently skipped because 8.8.0 doesn't support Composer 2. If I unskip it and bump the requirement to 9.5.0 it then complains that the path repo with 11.x-dev has higher priority. I've managed to work around that and have opened 📌 Unskip ScaffoldUpgradeTest Active to fix it. With wifi disabled I then get "Could not resolve host: repo.packagist.org", and once I enable wifi the test passes.

So we need to verify that ScaffoldTest is indeed accessing packagist (maybe the path repo is taking priority now) and we need a solution for ScaffoldUpgradeTest when repo.packagist.org is down. Maybe we can set up a mock mirror or we can prepopulate the cache from a fixture.

🇦🇺Australia mstrelan

mstrelan changed the visibility of the branch 3496319-multiple-run-as-is to hidden.

🇦🇺Australia mstrelan

mstrelan changed the visibility of the branch 3496319-multiple-runs-key-value to hidden.

🇦🇺Australia mstrelan

mstrelan changed the visibility of the branch 3393137-repeat to hidden.

🇦🇺Australia mstrelan

Fine by me, restoring status from #10 since nothing has changed to review.

🇦🇺Australia mstrelan

I don't think we're gonna catch this in the repeating test job. Should have snuck it in to #3041318: [random test failure] Various fails when a random string is used in an xpath selector but too late now. MR with the fix is up.

🇦🇺Australia mstrelan

Ran it 7000 times without the fix and couldn't get it to fail.

1000x https://git.drupalcode.org/issue/drupal-3393137/-/jobs/4978095
1000x https://git.drupalcode.org/issue/drupal-3393137/-/jobs/4978103
5000x https://git.drupalcode.org/issue/drupal-3393137/-/jobs/4978177

Maybe it's less frequent now or doesn't happen at all. Guess we just leave this until we see it in the wild again?

🇦🇺Australia mstrelan

Upstream PR is merged, just need a release then we can bump php-tuf/composer-stager. Or maybe we postpone again on 📌 Update Composer dependencies for 11.2.0 Active .

🇦🇺Australia mstrelan

Do we even need this function? It's only used when throwing this exception:

throw new \RuntimeException(sprintf('%s registered its own error handler (%s) without restoring the previous one before or during tear down. This can cause unpredictable test results. Ensure the test cleans up after itself.',
  $this->name(),
  self::getCallableName($handler),
));

Wouldn't it be enough without self::getCallableName($handler)?

🇦🇺Australia mstrelan

This looks great and is so much simpler.

🇦🇺Australia mstrelan

Yes please. While we're at it, can we add a var for number of repeats? It's currently hardcoded at --repeat "100". Would be good if we could set this var via the UI like REPEAT_TEST_CLASS.

We can do a separate issue for that, or we can re-title / re-purpose this issue to include this.

🇦🇺Australia mstrelan

We'll probably need to split this in to 5 separate issues, but adding all to one MR for now.

🇦🇺Australia mstrelan

Rebased the MR and fixed all the deprecated calls. Have also updated the CR.

I guess when we remove $message in 12.x we'll need to deprecate passing NULL as the third param, and then only allow a string in 13.x

🇦🇺Australia mstrelan

Non-exhaustive review. Added some thoughts to the MR. I tend to find enums most useful when you can pass them around to functions rather than just relying on them for their backed values. In an ideal would you could use the enum for field config as well rather than the int value.

🇦🇺Australia mstrelan

Apologies, the MR that had the random fail was older than 🐛 [random test failure] FilterEntityReferenceTest Active and did not have the fix.

🇦🇺Australia mstrelan

Core issue commited, probably the issue could be moved to core

AVIF conversion with WEBP fallback Active is open against core now.

Actually the Convert plugin in core already supports AVIF if the GD toolkit supports it. This issue in the AVIF contrib module is for providing the same conversion without GD, e.g. via ImageMagick or CAVIF.

🇦🇺Australia mstrelan

Switched to keyvalue instead of state

🇦🇺Australia mstrelan

There are two sides to this, both encoding and decoding. I think encoding is less important, as it only happens once. It's possible that over time decoders will become more efficient, e.g. by using AV1 hardware decoding instead of software decoding.

A few links

🇦🇺Australia mstrelan

Sniffs were not discussed here. What, if any, changes are required in Coder?

We don't need to change anything to allow the proposed changes, only if we want to restrict them.

I tested this by updating the @param doc on a constructor param to use a variety of different types listed in the phpstan docs. I also started putting random strings in, and they mostly passed, unless I used any of @#,.. For example, @param zDSA[]|<>D-&* $date_formatter is acceptable, but @param zDSA[]|<>D-&*# $date_formatter is not.

🇦🇺Australia mstrelan

Updated the IS, hope that helps.

🇦🇺Australia mstrelan

This is pretty hard to debug without knowing what $block_selector, $block_plugin or $new_page_text is. Either way, the block selector element is becoming visible (we're asserting that) but disappearing by the time we try to click it. But if sleeping for 100ms fixes it then I guess the element is eventually being replaced again. Maybe there is something real we can fix to prevent that, but otherwise we probably just need to wait until the element is really ready to be clicked. We could put the whole element find / mouseover / click in to a waitFor callback as a bandaid.

🇦🇺Australia mstrelan

@quietone the problem is more hypothetical and the update here is for best practice. I'll try to explain the problem.

  • In \Drupal\system\Controller\DbUpdateController::helpfulLinks we check if the user has the 'administer site configuration' permission before displaying the "Status report" link.
  • In \Drupal\Tests\system\Functional\UpdateSystem\UpdateScriptTest::testSuccessfulMultilingualUpdateFunctionality we create a user with a bunch of permissions. This includes both 'access site reports' and 'administer site configuration'. Then we assert that the "Status report" link exists.
  • Core later decides that the permission required to access the 'system.status' route should actually be 'access site reports' and not 'administer site configuration' so the route is updated. The test still passes because that user has both permissions. But a user with 'administer site configuration' and not 'access site reports' will still see the link, even though they won't be able to access the route.
  • The same problem could arise if a contrib or custom module decides to alter the permissions required for the route. For example, they might override the status report page and provide a custom permission for it. The link will still appear for users with the original permission.

By changing to Url::access we don't need to worry about what permission the route requires, just whether the logged in user can access it or not.

Can we add a test for this?

I think the test mentioned above is sufficient, not sure it's worth the effort to expand that further.

🇦🇺Australia mstrelan

Updated title and issue summary, hope that's clearer

🇦🇺Australia mstrelan

Added explanation inline. It can check up to 10 times within the 100ms timeout, but that assumes it takes no time at all to check.

🇦🇺Australia mstrelan

Yep and I think we should leave it for now until we find a need for it.

🇦🇺Australia mstrelan

Can you explain a bit more about where this path appending thing happens? Is it something we can maybe fix?

I'm offline for over a week now but when from what I recall you can see it in the html output for ExperimentalHelpTest if you remove the slash and run the test. Didn't look at what was causing it.

Why would the block report as being broken? What's causing it to be broken? This test needs to explain what it is doing!

IIRC there is a test module that includes config for a block, but that block is referencing the uuid of a block content entity that doesn't exist. Couldn't tell you why, but it's not really relevant. I think let's ignore that test for now.

🇦🇺Australia mstrelan

Added 2 more, HelpTest and HelpTopicTest, both of this are much faster now but I don't have the numbers. I did have a go at HelpTopicsSyntaxTest but it was actually significantly slower!

🇦🇺Australia mstrelan

@dww sure, I've created an MR against 11.x. As a bonus you don't have to review it one commit at a time because all the changes are limited to the help module, other than a7f43433.

🇦🇺Australia mstrelan

Added a comment in #3517299-4: [PP-1] Convert functional tests in help module to kernel tests that the only thing blocking multiple requests in the tests I've looked at is the missing preceding slash.

UiHelperTrait has a buildUrl method that ensures the path is absolute, I think we need to do the same thing here.

🇦🇺Australia mstrelan

I investigated the multiple requests issue a little further, and it turns out the only issue is that the paths weren't prefixed with a preceding slash, so the path was appended to the path of the previous request resulting in 404s. After fixing those the updated timing is below.

MySQL
ExperimentalHelpTest - Kernel 3.246s, Functional 13.550s
HelpBlockTest - Kernel 2.818s, Functional 13.642s
HelpPageOrderTest - Kernel 3.216s, Functional 14.067s
HelpPageReverseOrderTest - Kernel 3.212s, Functional 13.407s
NoHelpTest - Kernel 3.831s, Functional 15.771s

Total: Kernel 16.323s, Functional 70.437s

MySQL w/ tmpfs
ExperimentalHelpTest - Kernel 1.739s, Functional 6.374s
HelpBlockTest - Kernel 1.634s, Functional 5.254s
HelpPageOrderTest - Kernel 1.686s, Functional 5.254s
HelpPageReverseOrderTest - Kernel 1.700s, Functional 5.404s
NoHelpTest - Kernel 1.754s, Functional 5.754s

Total: Kernel 8.513s, Functional 28.04s

Those numbers make this much more compelling.

🇦🇺Australia mstrelan

Added an MR against 3390193-add-drupalget-with-mink-to-kerneltestbase but since it's against that branch it doesn't appear on the issue page, and the pipelines don't work. But I did it this way so we can see only the changes to Help module and not all the changes in the parent issue.

https://git.drupalcode.org/issue/drupal-3517299/-/merge_requests/1

It was a little annoying having to deal with the fact that we can't perform multiple requests in the same test, but overall it's still faster for the cases that I split. My test times below:

MySQL
ExperimentalHelpTest - Kernel 6.348s, Functional 13.550s
HelpBlockTest - Kernel 8.376s, Functional 13.642s
HelpPageOrderTest - Kernel 3.216s, Functional 14.067s
HelpPageReverseOrderTest - Kernel 3.212s, Functional 13.407s
NoHelpTest - Kernel 7.468s, Functional 15.771s

Total: Kernel 28.62s, Functional 70.437s

MySQL w/ tmpfs
ExperimentalHelpTest - Kernel 3.396s, Functional 6.374s
HelpBlockTest - Kernel 4.992s, Functional 5.254s
HelpPageOrderTest - Kernel 1.686s, Functional 5.254s
HelpPageReverseOrderTest - Kernel 1.700s, Functional 5.404s
NoHelpTest - Kernel 3.574s, Functional 5.754s

Total: Kernel 15.348, Functional 28.04s

So for MySQL with a normal filesystem this is a massive improvement! For tmpfs it's a decent improvement for the tests that only had one drupalGet, but it's much less of an improvement when the test had to be split and we repeat the setup tasks. It might be worth waiting for 📌 Allows DrupalKernel::handle to handle more than one requests (rough support for PHP-PM) Needs work for those tests.

🇦🇺Australia mstrelan

mstrelan changed the visibility of the branch 3390193-add-drupalget-with-mink-to-kerneltestbase to hidden.

🇦🇺Australia mstrelan

I'm not sure whether to:

a. call AssertContentTrait::setRawContent in drupalGet()
b. change getTextContent() to use Mink, since that's now available? And then we can later on deprecate setRawContent().

I'm not sure either. I don't think we can deprecate setRawContent because I think some tests use it after directly rendering things not using drupalGet. Note that UiHelperTrait::drupalGet has this comment that I think is not true either, because setRawContent only happens in KernelTestBase.

   * @return string
   *   The retrieved HTML string, also available as $this->getRawContent()

@mstrelan could you try adding this to the top of AssertContentTrait::getTextContent()?

Yeah that worked. I think probably the simplest solution is to call $this->content = $out; from the new drupalGet, that also makes it work.

Could you push your work on that test somewhere so I can have a look at it?

Added patches for POC I did on block_content and help tests.

The docs on HttpKernelUiHelperTrait::drupalGet() say that page caching modules won't work. Should that list of warnings be moved from the method docs to the trait docs, so they're more visible?

I must admit I didn't look at the docs, I just expected it would work like BrowserTestBase. I don't think moving them would make a difference. I do think we could probably work around this though by either replacing that policy or modifying it to use a service that can be replaced or decorated to pretend it's not the CLI. But this is best suited to a follow up.

🇦🇺Australia mstrelan

I tried to convert a few BrowserTestBase tests to kernel tests to try this out and have a couple observations.

1. \Drupal\Tests\help\Functional\HelpPageOrderTest
This calls $this->getTextContent() which in BrowserTestBase resolves to \Drupal\Tests\UiHelperTrait::getTextContent, but in KernelTestBase resolves to \Drupal\KernelTests\AssertContentTrait::getTextContent which depends on AssertContentTrait::setRawContent being called. Of course the test could be refactored to not call $this->getTextContent(), but I'm wondering if we should do something about that here, such as calling AssertContentTrait::setRawContent in drupalGet. Once I worked around it the Kernel test passed in 3 seconds as opposed to 12 seconds before.

2. \Drupal\Tests\block_content\Functional\BlockContentPageViewTest
This required lots of refactoring, which is as expected, but I couldn't get the foobar_gorilla block to load in ::testPageEdit. I was able to manually place the system_powered_by_block and get that to load, so I'm willing to concede that there's probably something I'm missing, rather than blocks not appearing because of the new drupalGet.

3. \Drupal\Tests\dynamic_page_cache\Functional\DynamicPageCacheIntegrationTest
This was probably a bit ambitious. The first blocker I couldn't easily work around was that the default cache policy for DPC prevents caching if PHP_SAPI is cli, which it is now that we're in a Kernel test. This might lead to other gotchas down the track if folks are expecting DPC to work when using drupalGet in Kernel tests.

That's as much as I've got time for today. Unfortunately I didn't find an existing test that could be converted cleanly, but nonetheless I'm quite excited about this.

🇦🇺Australia mstrelan

I feel a bit uneasy about the test case. The existing tests run through a number of valid and invalid scenarios for the default validator. But currently you're replacing the default validator, so now we don't know if the scenarios would pass or fail with the original validator.

I think instead we should have an additional test case that is explicitly to test that swapping out the validator is respected by ::validateProps.

🇦🇺Australia mstrelan

Honestly I don't know why we need to be testing the behaviour of the codeblock plugin. This is provided by CKE5 core and is thoroughly tested there. We should only be testing that we can configure the languages, and that the languages get passed to the plugin. I'd argue we don't need a JS test at all for this, but I guess a basic smoke test that the plugin is loading and the configured languages are available would be reasonable.

🇦🇺Australia mstrelan

Came across this triaging issues for Bug Smash Initiative and have a few thoughts:

  1. Since we're moving to Navigation module I checked if that is also affected and it is
  2. Since Claro and Starterkit Theme are unaffected should we really be fixing it for Stark?
  3. As per bnjmnm a stylesheet is certainly better than a style attribute. Not just for customisations, but for Content Security Policy also.
  4. I don't think toolbar.module is the right component for this since the issue is really with the dialog. Probably Javascript or Stark would be better. Even if it's a css fix, it's a javascript component we're styling.
🇦🇺Australia mstrelan

Converted to an MR, updated line numbers in the IS.

Fixed \Drupal\Tests\views\Kernel\Plugin\ExposedFormRenderTest::testExposedFormRawInput.

🇦🇺Australia mstrelan

mstrelan made their first commit to this issue’s fork.

🇦🇺Australia mstrelan

Is this still relevant since Use one-time login link instead of user login form in BrowserTestBase tests Fixed ? In most cases the test no longer requires the login form, unless the $useOneTimeLoginLinks property is false. Furthermore, the report in the issue summary suggests you're using Drupal Test Traits , so you could always override the drupalLogin method in your own test base class.

🇦🇺Australia mstrelan

Thanks @mondrake, some great points there. My initial thoughts on those:

1. I think automatically applying this rule everywhere in contrib and custom code would be quite disruptive, so it's almost a nice side effect that it would be opt-in. Ultimately I don't really care where it lives. It could probably even be a phpcs sniff that can be auto-fixed with phpcbf.

2. I think that could be handled separately in a follow up? Better to make progress than to get it perfect first go. Unless doing this makes things worse than the current state.

3. Absolutely. Keen to get more feedback first though.

🇦🇺Australia mstrelan

Managed to fix 405 files and only had one fail. Have added a @phpstan-ignore to NodeAccessGrantsCacheContextTest for now. Changing from a Plan to a Task and setting Needs Review.

🇦🇺Australia mstrelan

The IS mentions both Kernel and Functional tests should use \Drupal::service, but according to alexpott in #2699565-27: Replace \Drupal:: with $this->container->get() in test classes that allow dependency injection of Basic Auth module this is only true for Functional tests.

I've created an MR with a phpstan rule to identify functional tests that access $this->container. See https://git.drupalcode.org/issue/drupal-2066993/-/jobs/4841841 for results. We could land this and add the existing violations to the baseline. Then we can open follow up issues to cleanup the baseline. I suspect it should be simple enough to write a rector rule to replace $this->container->get() with \Drupal::service().

🇦🇺Australia mstrelan

mstrelan made their first commit to this issue’s fork.

🇦🇺Australia mstrelan

I think this is great, do we need something more generic long term?

Yeah the attribute I mentioned in the proposed resolution would be good to investigate. We can probably make use of the native phpunit attribtues for tests that are skipped on requirements like php extensions. Might be good to see if we can do another attribute for skipping on certain database driver too. But long term any permanently skipped tests should be fixed :joy:

🇦🇺Australia mstrelan

Now we have yet-another-timeout to investigate - installing standard profile times out after 300 seconds:

    Package Update (Drupal\Tests\package_manager\Build\PackageUpdate)
     ✘ Package update
       ┐
       ├ Symfony\Component\Process\Exception\ProcessTimedOutException: The process "/usr/local/bin/php ./core/scripts/drupal install standard --no-ansi" exceeded the timeout of 300 seconds.
       │
       │ /builds/issue/drupal-3497701/vendor/symfony/process/Process.php:1182
       │ /builds/issue/drupal-3497701/vendor/symfony/process/Process.php:451
       │ /builds/issue/drupal-3497701/vendor/symfony/process/Process.php:252
       │ /builds/issue/drupal-3497701/core/tests/Drupal/BuildTests/Framework/BuildTestBase.php:336
       │ /builds/issue/drupal-3497701/core/tests/Drupal/BuildTests/QuickStart/QuickStartTestBase.php:40
       │ /builds/issue/drupal-3497701/core/modules/package_manager/tests/src/Build/TemplateProjectTestBase.php:187
       │ /builds/issue/drupal-3497701/core/modules/package_manager/tests/src/Build/TemplateProjectTestBase.php:334
       │ /builds/issue/drupal-3497701/core/modules/package_manager/tests/src/Build/PackageUpdateTest.php:22
       ┴
🇦🇺Australia mstrelan

This failed for me on local the second time I ran it. I set up a job to repeat it 100 times and it failed 5/100 times, see https://git.drupalcode.org/issue/drupal-3389365/-/jobs/4840855

🇦🇺Australia mstrelan

mstrelan made their first commit to this issue’s fork.

🇦🇺Australia mstrelan

The plot thickens. Looks like package manager has a bunch of special handling around composer patches. I've managed to run a test locally that will patch php-tuf/composer-stager to pass the timeout through to the rsync command. I tested it my setting the timeout to 1 second in ApiController::createAndApplyStage and it failed after 1 second instead of 120.

I have a repeat job running with the timeout set to 180 - https://git.drupalcode.org/issue/drupal-3497701/-/jobs/4832276. If that passes (maybe we run it a few times), then we can probably postpone this on https://github.com/php-tuf/composer-stager/pull/414

🇦🇺Australia mstrelan

Is there a way we can refactor the core MR to do this? E.g. maybe CoreServiceProvider passes a container param with some hints of where to scan, the custom module can modify the container param and then the BundleClassCollectorPass can find them.

🇦🇺Australia mstrelan

Wondering if this can be incorporated in to the core MR which now does its own discovery outside of plugins - https://git.drupalcode.org/project/drupal/-/merge_requests/11545

In its current state it searches for an Entity subdir in all container.namespaces. Would be worth seeing if it can be made to work with this use case.

🇦🇺Australia mstrelan

I think this is by design:

   * This function loads the body part of a partial HTML document and returns a
   * full \DOMDocument object that represents this document.

and

   * @param string $html
   *   The partial HTML snippet to load. Invalid markup will be corrected on
   *   import.

Both suggest it's only intended to deal with partial snippets, not full documents.

🇦🇺Australia mstrelan

Pushed an update to assert the response content, and restore the previous execution time to see if that catches anything.

The 120 timeout is still curious. I can't get xdebug working inside the php local server so it's hard to step through. Looks like it would be passing 300 all the way down to \PhpTuf\ComposerStager\Internal\FileSyncer\Service\FileSyncer::sync which calls $this->environment->setTimeLimit($timeout); but I'm not sure that actually affects anything, e.g. in \PhpTuf\ComposerStager\Internal\FileSyncer\Service\FileSyncer::runCommand the timeout is not passed to $this->rsync->run so it looks like it would just fallback to 120.

🇦🇺Australia mstrelan

1. We should try to optimise the test and/or package_manager so we don't need a 30 second timeout.

I must admit I haven't tried to grok everything this test is trying to achieve, but it feels like PackageUpdateTest::testPackageUpdate could use a mocked response from the controller, and the controller could be tested independently. But maybe that's losing end-to-end coverage that we're trying to test for.

2. We should try to make sure that fatal errors result in a 500 instead of 200 so we don't get false negatives on 200 assertions.

Another approach would be to return a success string from the controller and assert that we get that in the response. That would catch the OOM and PHP timeout issues we were seeing locally.

https://git.drupalcode.org/project/drupal/-/jobs/4824652 is the repeat test class job running with that change, it's varying between 400-700 seconds to complete, so very slow indeed, but so far each iteration is passing.

That job passed 96 times and failed 4 times. This time instead of there being no error response we have an error to look at which I've included below, I've replaced html encoded entities for readability. The TL;DR is the rsync command is sometimes timing out after 2 minutes. This timeout seems to come from \PhpTuf\ComposerStager\API\Process\Service\ProcessInterface::DEFAULT_TIMEOUT, although it looks like \Drupal\package_manager\StageBase::create should be passing its own default, which is 300, so I'm not sure what's going on there.

Error response: The website encountered an unexpected error. Try again later.Drupal\package_manager\Exception\StageException: Failed to run process: <em class="placeholder">The process "'/usr/bin/rsync' '--archive' '--checksum' '--delete-after' '--verbose' '--exclude=/PACKAGE_MANAGER_FAILURE.yml' '--exclude=/web/sites/simpletest' '--exclude=/vendor/.htaccess' '--exclude=/web/sites/default/files' '--exclude=/web/sites/default/files/.sqlite' '--exclude=/web/sites/default/files/.sqlite-shm' '--exclude=/web/sites/default/files/.sqlite-wal' '--exclude=/recipes' '--exclude=/web/sites/default/default.settings.php' '--exclude=/web/sites/default/default.services.yml' '--exclude=/web/sites/default/settings.php' '--exclude=/web/sites/default/settings.local.php' '--exclude=/web/sites/default/services.yml' '--exclude=/package_manager_test_event.log' '--exclude=/tmp/.package_managerd1e3013e-0986-48a6-993d-25ac3459c1b2/ccKD8PwqcDLB4Q2kf2hMBv1EFnJulEs6' 'tmp/build_workspace_29b4565cc0c9b8a68abd3d8a6d0e7b8fGPvmzn/project/' 'tmp/.package_managerd1e3013e-0986-48a6-993d-25ac3459c1b2/ccKD8PwqcDLB4Q2kf2hMBv1EFnJulEs6'"; exceeded the timeout of 120 seconds.</em> in Drupal\package_manager\StageBase->rethrowAsStageException() (line 371 of core/modules/package_manager/src/StageBase.php). Symfony\Component\Process\Process->wait() (Line: 252)
       ├ Symfony\Component\Process\Process->run(Object, Array) (Line: 269)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
       ├ Symfony\Component\Process\Process->mustRun(Object) (Line: 105)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
       ├ PhpTuf\ComposerStager\Internal\Process\Service\Process->mustRun(Object) (Line: 81)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
       ├ PhpTuf\ComposerStager\Internal\Process\Service\AbstractProcessRunner->run(Array, Object, Array, Object) (Line: 121)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
       ├ PhpTuf\ComposerStager\Internal\FileSyncer\Service\FileSyncer->runCommand(Object, Object, Object, Object) (Line: 58)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
       ├ PhpTuf\ComposerStager\Internal\FileSyncer\Service\FileSyncer->sync(Object, Object, Object, Object, 300) (Line: 38)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
       ├ PhpTuf\ComposerStager\Internal\Core\Beginner->begin(Object, Object, Object, Object, 300) (Line: 43)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
       ├ Drupal\package_manager\LoggingBeginner->begin(Object, Object, Object, Object, 300) (Line: 354)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
       ├ Drupal\package_manager\StageBase->create() (Line: 111)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
       ├ Drupal\package_manager_test_api\ApiController->createAndApplyStage(Object) (Line: 73)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
       ├ Drupal\package_manager_test_api\ApiController->run(Object)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
       ├ call_user_func_array(Array, Array) (Line: 123)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
       ├ Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 593)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
       ├ Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 121)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
       ├ Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
       ├ Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 183)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
       ├ Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 76)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
       ├ Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 53)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
       ├ Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
       ├ Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 28)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
       ├ Drupal\Core\StackMiddleware\ContentLength->handle(Object, 1, 1) (Line: 32)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
       ├ Drupal\big_pipe\StackMiddleware\ContentLength->handle(Object, 1, 1) (Line: 116)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
       ├ Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 90)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
       ├ Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
       ├ Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
       ├ Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 53)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
       ├ Drupal\Core\StackMiddleware\AjaxPageState->handle(Object, 1, 1) (Line: 51)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
       ├ Drupal\Core\StackMiddleware\StackedHttpKernel->handle(Object, 1, 1) (Line: 715)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
       ├ Drupal\Core\DrupalKernel->handle(Object) (Line: 19)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
       ├ require('/tmp/build_workspace_29b4565cc0c9b8a68abd3d8a6d0e7b8fGPvmzn/project/web/index.php') (Line: 71)
🇦🇺Australia mstrelan

That's the same experience I had. Most likely it is timing out after 1 sec but still a 200. If you assert that the response is empty it will probably fail and show the timeout error.

Side note I wonder if we can get htmlOutput to work here.

🇦🇺Australia mstrelan

AFK now but there is a constant in one of the test base classes that's setting it to 20 seconds. I'm not sure if there is something else about my local that's causing it to time out though.

🇦🇺Australia mstrelan

FWIW I can replicate the exact error by adding this to the start of \Drupal\package_manager_test_api\ApiController::run

http_response_code(500);
die();
🇦🇺Australia mstrelan

Running this test locally always fails for me, but it fails asserting the expected versions. That means makePackageManagerTestApiRequest is passing.

I found it odd that the Error response: in the output is empty, thinking maybe an error was thrown and system.logging error_logging was set to hide instead of verbose, but that's not the case. I explicitly put some errors in \Drupal\package_manager_test_api\ApiController::run but I could always see the error response in the output.

I then thought maybe there is an OOM or timeout. I didn't have much luck down the OOM route, but I did find that if I add this line to makePackageManagerTestApiRequest it would fail, even after asserting the 200 status code.

$this->assertSame('Finish', $session->getPage()->getContent());

1) Drupal\Tests\package_manager\Build\PackageUpdateTest::testPackageUpdate
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
-'Finish'
+'<br />
+<b>Fatal error</b>:  Maximum execution time of 20 seconds exceeded in <b>/tmp/build_workspace_4d8944e5916659803141418ed3171c99nCcLIM/project/vendor/php-tuf/composer-stager/src/Internal/Finder/Service/FileFinder.php</b> on line <b>68</b><br />'

I'm not sure exactly how that helps, but hoping it can spark some ideas.

🇦🇺Australia mstrelan

Rebased and updated the MR with a suggested fix, updated proposed resolution.

🇦🇺Australia mstrelan

I repeated the original job that failed 1 in 3 times and now it's not failing at all. https://git.drupalcode.org/issue/drupal-3317520/-/jobs/4820216

Not sure what to make of that, maybe we don't need the trait after all. But I think the waitForElementVisible makes sense.

🇦🇺Australia mstrelan

Using WaitTerminateTestTrait seems to allow us to unskip ::testEditModeEnableDisable without splitting to a separate class - https://git.drupalcode.org/issue/drupal-3317520/-/jobs/4819919

But it failed once where I removed the usleep. Instead of usleep, why don't we just use waitForElementVisible? This seems to pass 100/100 times - https://git.drupalcode.org/issue/drupal-3317520/-/jobs/4819970. And once more for good measure https://git.drupalcode.org/issue/drupal-3317520/-/jobs/4819989.

Have created another MR with just these fixes and updated the issue summary.

🇦🇺Australia mstrelan

Perfect. I've reviewed the MR and can see the duplicate has been removed and there is still one Spell-checking job in tact. I checked the pipeline and can see the Spell-checking job is running as expected.

Production build 0.71.5 2024