Problem/Motivation

This blocks #2450993: Rendered Cache Metadata created during the main controller request gets lost.

Proposed resolution

This is the part of the patch at #2450993-92: Rendered Cache Metadata created during the main controller request gets lost that can be split off, see #2450993-87: Rendered Cache Metadata created during the main controller request gets lost.

Remaining tasks

None.

User interface changes

None.

API changes

None.

Data model changes

None.

BETA EVAL:

Spin-off of #2450993: Rendered Cache Metadata created during the main controller request gets lost and hence a hard blocker for that one.

CommentFileSizeAuthor
#1 2511472-1.patch168.69 KBWim Leers
#6 2511472-6.patch169.08 KBWim Leers
#6 interdiff.txt745 bytesWim Leers
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Wim Leers’s picture

Fabianx’s picture

Status: Needs review » Reviewed & tested by the community

RTBC, I reviewed all interdiffs already.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 1: 2511472-1.patch, failed testing.

dawehner’s picture

Looks pretty great in general!

  1. +++ b/core/modules/simpletest/src/Tests/KernelTestBaseTest.php
    @@ -291,11 +293,11 @@ function testEnableModulesTheme() {
       /**
    diff --git a/core/modules/simpletest/src/Tests/SimpleTestTest.php b/core/modules/simpletest/src/Tests/SimpleTestTest.php
    
    diff --git a/core/modules/simpletest/src/Tests/SimpleTestTest.php b/core/modules/simpletest/src/Tests/SimpleTestTest.php
    index 2514d9d..479ca39 100644
    
    index 2514d9d..479ca39 100644
    --- a/core/modules/simpletest/src/Tests/SimpleTestTest.php
    
    --- a/core/modules/simpletest/src/Tests/SimpleTestTest.php
    +++ b/core/modules/simpletest/src/Tests/SimpleTestTest.php
    
    +++ b/core/modules/simpletest/src/Tests/SimpleTestTest.php
    +++ b/core/modules/simpletest/src/Tests/SimpleTestTest.php
    @@ -24,7 +24,7 @@ class SimpleTestTest extends WebTestBase {
    
    @@ -24,7 +24,7 @@ class SimpleTestTest extends WebTestBase {
        *
        * @var array
        */
    -  public static $modules = array('simpletest', 'test_page_test');
    +  public static $modules = ['simpletest'];
     
       /**
        * The results array that has been parsed by getTestResults().
    

    This change is really not obvious ...

  2. +++ b/core/tests/Drupal/Tests/Core/Form/EventSubscriber/FormAjaxSubscriberTest.php
    @@ -64,9 +58,8 @@ protected function setUp() {
    -    $this->renderer = $this->getMock('\Drupal\Core\Render\RendererInterface');
         $this->stringTranslation = $this->getStringTranslationStub();
    
    @@ -171,9 +164,21 @@ public function testOnExceptionBrokenPostRequest() {
    +    $renderer = $this->getMockBuilder('Drupal\Core\Render\Renderer')
    +      ->disableOriginalConstructor()
    +      ->getMock();
    +    $renderer->expects($this->once())
           ->method('renderRoot')
    -      ->willReturn($rendered_output);
    +      ->with()
    +      ->willReturnCallback(function (&$elements) use ($rendered_output) {
    +        $elements['#attached'] = [];
    +        return $rendered_output;
    +      });
    +    $container = new ContainerBuilder();
    +    $container->set('renderer', $renderer);
    +    \Drupal::setContainer($container);
     
    

    This is a bit confusing, why can we no longer mock the interface? ... I think it is actually a step backward, as we seem to call out to the global container now, but haven't earlier

andypost’s picture

few things are filed as child issues in related

Wim Leers’s picture

Status: Needs work » Needs review
FileSize
745 bytes
169.08 KB

GAH! *One* stupid error in splitting up a 270 K patch :P Why couldn't that have been zero? :(


#4.1: unnecessary change, but I debugged the failures in the SimpleTestTest for a VERY long time, and turns out it is installing a module that it never uses/relies upon. To make further debugging easier, this helps reduce the search space of possible reasons.

#4.2: because of

+++ b/core/lib/Drupal/Core/Form/EventSubscriber/FormAjaxSubscriber.php
@@ -94,7 +83,7 @@ public function onException(GetResponseForExceptionEvent $event) {
-      $response->addCommand(new ReplaceCommand(NULL, $this->renderer->renderRoot($status_messages)));
+      $response->addCommand(new ReplaceCommand(NULL, $status_messages));

this. This doesn't do the rendering anymore, instead leaving the rendering to \Drupal\Core\Ajax\CommandWithAttachedAssetsTrait. The code you quoted is the mocking necessary for that trait.

(The original would've worked as well, but this was resolved during a rebase conflict, at which time I did have a good reason to do this, but I don't remember.)

Fabianx’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community

Back to RTBC, there are still some inconsistencies e.g. rendering vs. not rendering in Ajax responses, but that had been present before, such this is not making it worse, but better, because early rendering is moved to rely on the real renderRoot or renderPlain functions that should be used.

dawehner’s picture

I still don't get why we need to mock the actual instance of the class

Wim Leers’s picture

I still don't get why we need to mock the actual instance of the class

If you remove the mocked renderer service in the container, then this happens:


There was 1 error:

1) Drupal\Tests\Core\Form\EventSubscriber\FormAjaxSubscriberTest::testOnExceptionBrokenPostRequest
Drupal\Core\DependencyInjection\ContainerNotInitializedException: \Drupal::$container is not initialized yet. \Drupal::setContainer() must be called with a real container.

/Users/wim.leers/Work/drupal-tres/core/lib/Drupal.php:129
/Users/wim.leers/Work/drupal-tres/core/lib/Drupal.php:157
/Users/wim.leers/Work/drupal-tres/core/lib/Drupal/Core/Ajax/CommandWithAttachedAssetsTrait.php:38
/Users/wim.leers/Work/drupal-tres/core/lib/Drupal/Core/Ajax/ReplaceCommand.php:38
/Users/wim.leers/Work/drupal-tres/core/lib/Drupal/Core/Ajax/AjaxResponse.php:53
/Users/wim.leers/Work/drupal-tres/core/lib/Drupal/Core/Form/EventSubscriber/FormAjaxSubscriber.php:86
/Users/wim.leers/Work/drupal-tres/core/tests/Drupal/Tests/Core/Form/EventSubscriber/FormAjaxSubscriberTest.php:187
/Users/wim.leers/Work/drupal-tres/core/vendor/phpunit/phpunit/phpunit:36

i.e.: the test calls

$this->subscriber->onException($event);

which calls

$
response->addCommand(new ReplaceCommand(NULL, $status_messages));

which calls

$this->commands[] = $command->render();

which calls

'data' => $this->getRenderedContent(),

which calls

$html = \Drupal::service('renderer')->renderRoot($this->content);

… hence we need to mock the renderer. Just like before. But instead of injecting a mocked renderer into FormAjaxSubscriber, we now do it on the container, because \Drupal\Core\Ajax\CommandWithAttachedAssetsTrait uses the renderer, and that trait is used by AJAX commands that render HTML. I believe you helped land that at #2347469: Rendering forms in AjaxResponses does not attach assets automatically.

Fabianx’s picture

The question is why:

+ $renderer = $this->getMockBuilder('Drupal\Core\Render\Renderer')

and not

+ $renderer = $this->getMockBuilder('Drupal\Core\Render\RendererInterface')

It should not matter in difference ...

effulgentsia’s picture

Priority: Major » Critical

Spin-off of #2450993: Rendered Cache Metadata created during the main controller request gets lost and hence a hard blocker for that one.

Therefore: Critical.

Wim Leers’s picture

#10: Oh, nice nitpick find :) Should not matter indeed.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed 68d4f0b and pushed to 8.0.x. Thanks!

diff --git a/core/tests/Drupal/Tests/Core/Form/EventSubscriber/FormAjaxSubscriberTest.php b/core/tests/Drupal/Tests/Core/Form/EventSubscriber/FormAjaxSubscriberTest.php
index 007781a..8d0f6bb 100644
--- a/core/tests/Drupal/Tests/Core/Form/EventSubscriber/FormAjaxSubscriberTest.php
+++ b/core/tests/Drupal/Tests/Core/Form/EventSubscriber/FormAjaxSubscriberTest.php
@@ -166,9 +166,7 @@ public function testOnExceptionBrokenPostRequest() {
     $rendered_output = 'the rendered output';
     // CommandWithAttachedAssetsTrait::getRenderedContent() will call the
     // renderer service via the container.
-    $renderer = $this->getMockBuilder('Drupal\Core\Render\Renderer')
-      ->disableOriginalConstructor()
-      ->getMock();
+    $renderer = $this->getMock('Drupal\Core\Render\RendererInterface');
     $renderer->expects($this->once())
       ->method('renderRoot')
       ->with()

Yep indeed this is better. Fixed on commit and ran tests with PHPUnit.

  • alexpott committed 68d4f0b on 8.0.x
    Issue #2511472 by Wim Leers, Fabianx, dawehner: Refactor all usages of...
dawehner’s picture

If you remove the mocked renderer service in the container, then this happens:

Yeah I'm not stupid ... the thing is, once you mock in a hard coded way, there is less guarantee that you can write alternative implementations one day.

andypost’s picture

Closed as duplicate #2509606: book_node_view() breaks node render caching
but other 2 issues still needs review

Wim Leers’s picture

@andypost: which 2 are that?

andypost’s picture

Status: Fixed » Closed (fixed)

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