Updated: Comment #0

Problem/Motivation

If we want to improve the page cache by removing the "content" cache tag (see #2124957: Replace 'content' cache tag with 'rendered' and use it sparingly), then we must ensure that cache tags exist for all user-modifiable pieces of content on the page. Including comments, custom blocks, nodes, taxonomy terms and users. They already set cache tags in their render arrays, but lack test coverage.

Proposed resolution

Add test coverage.

Remaining tasks

None.

User interface changes

None.

API changes

None.

CommentFileSizeAuthor
#49 interdiff.txt1.21 KBwim leers
#49 entity_cache_tags_tests-2188565-49.patch56.42 KBwim leers
#43 interdiff.txt9.21 KBwim leers
#43 entity_cache_tags_tests-2188565-43.patch56.38 KBwim leers
#37 interdiff.txt2.06 KBwim leers
#37 entity_cache_tags_tests-2188565-36.patch57.16 KBwim leers
#31 entity_cache_tags_tests-2188565-30.patch59.17 KBwim leers
#30 interdiff.txt1.63 KBwim leers
#30 entity_cache_tags_tests-2188565-29.patch59.23 KBwim leers
#29 interdiff.txt2.79 KBwim leers
#29 entity_cache_tags_tests-2188565-28.patch58.87 KBwim leers
#26 interdiff.txt908 byteswim leers
#26 entity_cache_tags_tests-2188565-26-debug.patch57.94 KBwim leers
#24 interdiff.txt7.78 KBwim leers
#24 entity_cache_tags_tests-2188565-24.patch57.77 KBwim leers
#23 entity_cache_tags_tests-2188565-23.patch4.54 KBberdir
#21 interdiff.txt15.91 KBwim leers
#21 entity_cache_tags_tests-2188565-21.patch61.91 KBwim leers
#18 interdiff.txt7.17 KBwim leers
#18 entity_cache_tags_tests-2188565-18.patch46.88 KBwim leers
#15 interdiff.txt745 byteswim leers
#15 entity_cache_tags_tests-2188565-15.patch44.99 KBwim leers
#12 interdiff.txt5.68 KBwim leers
#12 entity_cache_tags_tests-2188565-12.patch45.7 KBwim leers
#10 interdiff.txt6.3 KBwim leers
#10 entity_cache_tags_tests-2188565-10.patch45.05 KBwim leers
#8 interdiff-move-menu-test.txt6.47 KBwim leers
#8 interdiff.txt38.11 KBwim leers
#8 entity_cache_tags_tests-2188565-8.patch40.04 KBwim leers
#5 term_cache_tags_test-2188565-5.patch4.51 KBwim leers
#1 term_cache_tags_test-2188565-1.patch4.45 KBwim leers

Comments

wim leers’s picture

Status: Active » Needs review
StatusFileSize
new4.45 KB
wim leers’s picture

Title: Test coverage for Term entity cache tags » Test coverage for Taxonomy Term entity cache tags

Status: Needs review » Needs work

The last submitted patch, 1: term_cache_tags_test-2188565-1.patch, failed testing.

wim leers’s picture

Status: Needs work » Needs review
wim leers’s picture

Issue tags: -quickfix +Quick fix
StatusFileSize
new4.51 KB

Straight reroll.

Status: Needs review » Needs work

The last submitted patch, 5: term_cache_tags_test-2188565-5.patch, failed testing.

berdir’s picture

Hm, Similar to my comment in the issue, but even more in this case (because it depends on the taxonomy field type 100% provided by this module), we should also test entities that have term references.

In both directions, meaning, have an entity tagged with a term, rename the term and make sure the tagged entity render cache is updated (this should work with any entity type). And in reverse, update the entity and make sure the cached taxonomy term content list is updated properly (this only works for nodes as that page only lists nodes).

That's the kind of stuff that we need to have test coverage for and make it work without the content cache tag :)

A negative test would also be cool, but that will only work once the content tag is gone. Meaning, have a second entity that does have the same field but does not reference this specific term, so a change should not touch the validity of that cache.

wim leers’s picture

Title: Test coverage for Taxonomy Term entity cache tags » Test coverage for Comment, Custom Block, Node, Taxonomy Term and User entity cache tags
Component: taxonomy.module » cache system
Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Quick fix
StatusFileSize
new40.04 KB
new38.11 KB
new6.47 KB

#7: agreed.

Done.

Implemented in a generic way, so which allows us to easily add test coverage for all entity types for which we want cache tag test coverage. I talked to Berdir & nielsvm, both agreed it'd be better to add tests for many entity types at once: less patch review/core committer overhead.

This patch adds cache tags test coverage for the following entity types:

  • Comment
  • Custom Block
  • Node
  • Taxonomy Term
  • User

In addition, I've converted the tests for Menu (that were added in #2179083: Rendered menus (e.g. menu blocks) should set cache tags to inform the page cache) to use the newly added base class.

I tried to also add test coverage for File entities, but entity reference fields to File entities don't render, and hence don't get cache tags. Entity reference thinks no user has access to it, so quite possibly this is related to #2128791: File resource needs an access controller.


Added base classes

  1. Drupal\system\Tests\Cache\PageCacheTagsTestBase: the base class that should be used by every cache tags test. Enables page caching and comes with a handy verifyPageCache($path, $hit_or_miss, $tags = FALSE) method.
  2. \Drupal\system\Tests\Entity\EntityCacheTagsTestBase, extends PageCacheTagsTestBase: must be subclassed on a per-entity type basis, automatically will test the scenario Berdir described above, and more: create an entity of the "entity_test" type, reference an entity of the type being tested, verify the cache tags of that referencing entity, list all entities referencing our entity of interest, delete the referencing entity, modify the referenced entity, delete the referenced entity, and so on.
  3. \Drupal\system\Tests\Entity\EntityWithUriCacheTagsTestBase, extends EntityCacheTagsTestBase: similar to the above, but also tests "the full entity page" for entities that have that (i.e. this must be used if and only if the entity type has a URI where you can see it). I.e. Comment, Node, Taxonomy Term and User use this, but Custom Block and File don't.

This of course has the huge benefit of being able to add more test scenarios to all these entity types at once, by modifying a single base class :)

Fixed bugs

EntityViewBuilder only sets cache tags if the entity is render cacheable, but that's wrong: it should always set cache tags, but only set cache keys/granularity/bin if the entity is render cacheable. Cache tags must always exist, otherwise the page cache cannot be informed!

Status: Needs review » Needs work

The last submitted patch, 8: entity_cache_tags_tests-2188565-8.patch, failed testing.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new45.05 KB
new6.3 KB

It seems that just before I posted the patch, the field_entity entity type was renamed to field_config and field_instance to field_instance_config. Great changes, but they broke my patch :)

Testbot also surfaced NodePageCacheTest as being broken (yay!), which was introduced by #1841900: Node deletion should clear page cache. It inappropriately uses the content cache tag to ensure all affected nodes are deleted from the page cache. The test coverage in this patch demonstrates that that is not necessary. The test coverage in this patch is also a superset of what was added there, so removing NodePageCacheTest.

Status: Needs review » Needs work

The last submitted patch, 10: entity_cache_tags_tests-2188565-10.patch, failed testing.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new45.7 KB
new5.68 KB

That was very painful to debug, but this should do the trick.

Status: Needs review » Needs work

The last submitted patch, 12: entity_cache_tags_tests-2188565-12.patch, failed testing.

The last submitted patch, 12: entity_cache_tags_tests-2188565-12.patch, failed testing.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new44.99 KB
new745 bytes

xdebug_break() call… STUPID!

nielsvm’s picture

Wim,

I applied the latest patch against core 96e7aa9a331f1f4651f862c7ddb5039512cba945 and ran all the test that have been touched, they ran without a single fail or exception. I have also reviewed the full patch in-context of all files and besides a few minor things I think this can go entirely RTBC, it's looking thorough and very good.

Niels

core/lib/Drupal/Core/Entity/EntityViewBuilder.php

  • Looks good, changes make sense.

core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php

  • 490: perhaps set cache.page.max_age higher than 300 to exclude the theory where a (really super, super) slow and long running test would invalidate the page.
  • 515: perhaps put "test-page" in a var as its reused.
  • 539: also consider testing when the menu link was deleted.
  • 539: also consider testing when the block was changed assignment, but perhaps that needs to go elsewhere..

core/modules/node/lib/Drupal/node/Form/DeleteMultiple.php

  • 126: very nice :-), nothing to add here.

core/modules/node/lib/Drupal/node/Form/NodeDeleteForm.php

  • Nothing special

core/modules/node/lib/Drupal/node/Tests/NodePageCacheTest.php

  • 37: same cache.page.max_age concern, perhaps 3600 is safer (for testing)
  • 61: We're trying to get rid of "content:1", so is it in this assertion just temporarily then?
  • 89: why are you simulating a form post while entity_delet()/node_delete() should cause the same wipe to happen? What I'm saying is, it would be bad to rely on form submissions to wipe cache tags, it needs to happen on a lower level. E.g. Drush scripts deleting/saving should also cause cache invalidations.

core/modules/system/lib/Drupal/system/Tests/Entity/EntityViewBuilderTest.php

  • Yes these changes make sense, page cache is hard to escape from for example.

core/modules/system/tests/modules/entity_test/entity_test.routing.yml

  • Nothing important

core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Controller/EntityTestController.php

  • 41: style, dot at end of sentence.
  • 62,64: unneeded whitespace?

Status: Needs review » Needs work

The last submitted patch, 15: entity_cache_tags_tests-2188565-15.patch, failed testing.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new46.88 KB
new7.17 KB

#16: Thanks for the review!

I'm afraid that you reviewed the patch incorrectly though:

  • you reviewed MenuTest, where there's no cache tags test anymore, it's been moved to MenuCacheTagsTest. I've applied your remarks to the code there. Block assignment changing is for the upcoming block cache test coverage at #2158003: Remove Block Cache API in favor of blocks returning #cache with cache tags.
  • you also reviewed NodePageCacheTest, which was removed completely, so all of your remarks (all of which I agree with!) are no longer relevant :)

Also fixed the remarks for EntityTestController.

Finally, also fixed the two failures, which I did fix locally but forgot to stage and therefor got lost :/ Stupid!

nielsvm’s picture

That's been quite stupid from me, coffee!

berdir’s picture

Hm, this is interesting, but for the most part, we're essentially testing the same thing over and over again, just differently painted, or am I missing something? Most of what's being tested is generic and the same for all entity types, right? What do we gain from doing it for all entity types? Asking from a test performance standpoint, web tests are pretty slow...

Do we need more test coverage for things that make each entity type special? Most things are handled by the generic referencedEntities() implementation and everything being entity references now, so I guess my own argument is now saying that we don't need to test fun stuff like user signatures on comments, because it's from the author, or inline information about the comment parent, as that's an entity reference too. Cool :)

As far as access goes, as long as it's by-role, we should be good. Wondering if there are things in core that are not that we need to think about. "'view own unpublished content'" could be an interesting case, that is essentially per-user for unpublished content? Real user profiles often contain personalized stuff for the viewer but it's not a core problem (as user profile are empty/useless out of the box) and affected sites will probably just disable the render cache..

As you can see, I'm trying everything to find possible flaws ;)

  1. +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCacheTagsTestBase.php
    @@ -0,0 +1,336 @@
    +
    +    // Create a referencing and a non-referencing entity.
    +    list(
    +      $this->referencing_entity,
    +      $this->non_referencing_entity,
    +    ) = static::createReferenceTestEntities($this->entity);
    +  }
    

    Calling static methods like this is pretty uncommon in a test. I personally wouldn't have done it and assigned $this->referencing_entity and so on directly in the helper. This is a pretty crazy trick IMHO. Would be interested in some more opinions here, maybe it's just me :)

  2. +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCacheTagsTestBase.php
    @@ -0,0 +1,336 @@
    +  protected static function generateStandardizedInfo($entity_type_label, $group) {
    +    return array(
    +      'name' => "$entity_type_label entity cache tags",
    +      'description' => "Test the $entity_type_label entity's cache tags.",
    +      'group' => $group,
    +    );
    +  }
    

    Creative ;)

  3. +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCacheTagsTestBase.php
    @@ -0,0 +1,336 @@
    +  /**
    +   * Creates the entity to be tested.
    +   *
    +   * @return \Drupal\Core\Entity\EntityInterface
    +   *   The entity to be tested.
    +   */
    +  protected static function createEntity() {
    +    // PHP doesn't allow us to declare this method as abstract protected static,
    +    // so we simply throw an exception here if this has not been implemented by
    +    // a child class.
    +    throw new \RuntimeException(String::format('@class must implement \Drupal\system\Tests\Entity\EntityCacheTagsTestBase::createEntity().', array(
    +      '@class' => get_called_class(),
    +    )));
    +  }
    +
    

    Why not just make it abstract? :)

  4. +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCacheTagsTestBase.php
    @@ -0,0 +1,336 @@
    +    $referencing_entity_type = $this->referencing_entity->getEntityTypeId();
    +    $non_referencing_entity_type = $this->non_referencing_entity->getEntityTypeId();
    

    PhpUnit says these two are unused.

  5. +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Controller/EntityTestController.php
    @@ -37,4 +37,30 @@ public function testAdmin() {
    +  public function listReferencingEntities($entity_reference_field_name, $referenced_entity_type, $referenced_entity_id) {
    +    // Early return if the referenced entity does not exist (or is deleted).
    +    if (entity_load($referenced_entity_type, $referenced_entity_id) === NULL) {
    +      return array();
    +    }
    +
    +    $query = \Drupal::service('entity.query')
    +      ->get('entity_test')
    +      ->condition($entity_reference_field_name . '.target_id', $referenced_entity_id);
    +    $entities = entity_load_multiple('entity_test', $query->execute());
    +    return entity_view_multiple($entities, 'full');
    +  }
    

    I'm not sure I understand why you're going through the trouble with all the referencing stuff and not just list all of them? Wouldn't that essentially be the same?

    Also, this should probably do it "properly" by working with the storage controller/view builder directly.

  6. One more thing that I noticed, for comments, you make sure that they're published and for nodes, you don't but grant anon users the by pass node access permission? Why not make them published too?
wim leers’s picture

StatusFileSize
new61.91 KB
new15.91 KB

Hm, this is interesting, but for the most part, we're essentially testing the same thing over and over again, just differently painted, or am I missing something? Most of what's being tested is generic and the same for all entity types, right? What do we gain from doing it for all entity types? Asking from a test performance standpoint, web tests are pretty slow...

Some entity types override the base entity view builder or storage controller. Therefore they might break caching. We want to ensure that's not the case. Hence it's necessary.

Plus, as we discover entity type-specific edge cases, I will add entity type-specific tests too. #2151459-75: Enable node render caching made me realize that changes to NodeType should also affect Node, so that's one I'm adding in this reroll.

Having done that, I thought of also ensuring that when you change field settings or field instance settings, the affected entities' render cache entries should be invalidated. That was NOT yet the case. In this reroll, I fixed that, and there's test coverage for it.

Do we need more test coverage for things that make each entity type special?

Yes! See the above example.

Most things are handled by the generic referencedEntities() implementation and everything being entity references now, so I guess my own argument is now saying that we don't need to test fun stuff like user signatures on comments, because it's from the author, or inline information about the comment parent, as that's an entity reference too. Cool :)

Agreed, but that's a different case of "specialness" when compared to the above example, wouldn't you agree?

As far as access goes, as long as it's by-role, we should be good. Wondering if there are things in core that are not that we need to think about. "'view own unpublished content'" could be an interesting case, that is essentially per-user for unpublished content?

Agreed. Where per-user content is rendered, it's the responsibility of the thing that does per-user rendering to set #cache = FALSE.

As you can see, I'm trying everything to find possible flaws ;)

That's exactly what this patch needs! :)

  1. I can remove it for the example you cited, but the static::createEntity() call needs to remain, because we need late static binding for it. I don't think there will be many (if any) tests overriding createReferenceTestEntities(), but I figured I'd keep the door open.
  2. :) Consistency & DRY FTW!
  3. Because I can't. I really, really tried. See the comment. Also see TestBase::getInfo() for another such example.
  4. Good find! How did you get PHPUnit to report that to you?
  5. Fixed "improper" function calls. And no, because we create a referencing and a non-referencing entity. Modifying the non-referencing entity must only affect the non-referencing entity's page cache entry. Modifying the referencing entity must affect both the referencing entity and the listing of referencing entities. Etc. Just like *you* described/requested in #7… :) Am I missing something?
    However, thanks to your critical remark here, I noticed that I wasn't actually modifying the non-referencing entity yet and verifying its effects. As of this reroll, this patch does that too.
  6. Great catch, fixed!

Status: Needs review » Needs work

The last submitted patch, 21: entity_cache_tags_tests-2188565-21.patch, failed testing.

berdir’s picture

StatusFileSize
new4.54 KB

1. Hm, not sure I understand why this needs LSB. Overriding non-static methods shouldn't be a problem at all? Non-static methods don't need LSB because they're not static and are always called on the current object anyway?
3. Ah, it's a strict notice. Because I tried and PhpStorm was happy with it ;) It does work just fine for me if it's non-static, see attached interdiff :)
4. It highlights unused variables grey for me.
5. Hm :) What I meant was the detail page of the non-referenced entity, which you are already testing. For a list, it shouldn't matter. If you have a list with entity A and B, and the cache tag for A has been deleted, then the whole list should be rebuilt. Not just when the list only contains A. And it's irrelevant if B is in there or not. I would actually say it would be better to test with both entities? If anything, then you could be testing that a list that only contains B still has a valid cache? Not sure that's useful though as you already tested the entity itself.

  1. +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCacheTagsTestBase.php
    @@ -57,9 +57,41 @@ public function setUp() {
    +      // add field, so we can modify the Field and FieldInstance entities to
    +      // verify that changes to those indeed clear cache tags
    

    Nitpick: add should start with an uppercase character.

  2. +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Vocabulary.php
    @@ -129,6 +129,10 @@ public function postSave(EntityStorageControllerInterface $storage_controller, $
           entity_invoke_bundle_hook('rename', 'taxonomy_term', $this->getOriginalId(), $this->id());
         }
    +    else {
    +      // Invalidate the render cache for all terms.
    +      \Drupal::entityManager()->getViewBuilder('taxonomy_term')->resetCache();
    +    }
         $storage_controller->resetCache($update ? array($this->getOriginalId()) : array());
    

    For Node/NodeType, it's needed because that has settings that affect the output, like displaying the author/date. Vocabulary AFAIK doesn't have any of those but fine, probably doesn't hurt :)

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new57.77 KB
new7.78 KB

The two failures for #21 are unrelated to this patch.


1. I want those methods to be static, because I don't want them setting things on the object. Therefor, I must use late static binding. I tried again to do without, but I can't. The very first example listed at http://php.net/lsb is precisely the problem I'd encounter otherwise.
3. Huh!? PHP wouldn't run at all while I did what you're doing in that interdiff!? But then again, you've removed the static keyword, which I want to be there for the above reason. If I try what you did, but restore the static keyword, things break again.
5. I'm still having trouble grokking what your concern is :) I do see that it doesn't really matter whether the "listing page" contains only referencing entities or simply all entities. But what's the value of changing what I have ("list referencing entities") in the patch today? The reason I went for "list all referencing entities" is simple: it's precisely what the "taxonomy term page" does (but only for entities of type Node), and therefor it's a simple-to-grok listing use case, so I just went with that.

Nitpick fixed. Regarding that render cache invalidation for taxonomy terms: agreed, that's only a theoretical addition/improvement for the functionality in Drupal core, but I think it's very conceivable that taxonomy term pages in the real world might list the name of the vocabulary they're part of, and in that case it's definitely necessary.
This actually points me to a case where this is not yet correctly happening: custom_block entities, whose bundle entity type is custom_block_type. So far, I'd only added the additional test cases to the testEntityUri() test case (which is not run for custom blocks, since they don't have a URI), and not yet also to the testReferencedEntity() test case. I fixed that now.
In doing so, I noticed that I could implement this in a generic way in Drupal\Core\Entity\Entity, so now the changes in Vocabulary are gone, NodeType became a bit simpler, and no more changes to CustomBlockType are necessary.


Anybody can think of yet more test cases? :)

Status: Needs review » Needs work

The last submitted patch, 24: entity_cache_tags_tests-2188565-24.patch, failed testing.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new57.94 KB
new908 bytes

It seems this fatal error is nigh impossible to debug… The review log says this:

…
Breakpoint media query tests 2 passes, 0 fails, 0 exceptions
PHP Fatal error:  Call to a member function getBundleOf() on a non-object in /var/lib/drupaltestbot/sites/default/files/checkout/core/lib/Drupal/Core/Entity/Entity.php on line 329
Comment route enhancer test 3 passes, 0 fails, 0 exceptions
…

Neither the preceding nor following test name triggers the PHP fatal error. So… then how are we supposed to figure out what's causing the test failure?

I'm adding debug output that will hopefully help…

Status: Needs review » Needs work

The last submitted patch, 26: entity_cache_tags_tests-2188565-26-debug.patch, failed testing.

berdir’s picture

1. & 3: Yes, I'm fully aware that you need LSB (which is the standard now anyway) and can not use abstract if you have static. I'm not questioning that, I'm just questioning the need to use static in the first place. My point is simply that not using it might be a bit less correct architecturally, but being able to make that method abstract would even that out IMHO :)

As for 5, I mentioned taxonomy node listings, because that's an actual existing thing, while your referenced list code IMHO introduces more complexity (mostly in being able to understand/read/follow your test) without actually testing anything specific. It's not wrong, it just seems unnecessary to me.

Anyway, I will stop talking about those points now, although I'd still be interested in what others think about those things.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new58.87 KB
new2.79 KB

So, #26 was utterly useless. To make debugging failed tests like that less miserable, we have #2189317: Get a PHPUnit job type running that is separate and independent from the Simpletest Job type, fix the d.o integration so that we can run the PHPUnit tests independently.

Much thanks to Berdir for the golden tip: just run all PHPUnit tests locally, because most fatal errors are PHPUnit tests. I did it, and I found the cause immediately. The fix is simple. This is an interdiff against #24, not #26.

wim leers’s picture

StatusFileSize
new59.23 KB
new1.63 KB

Berdir wanted confirmation from somebody else that the way the base classes added here use static methods to enforce a strict contract is acceptable. We discussed it with alexpott in IRC, and he thinks that if there's a comment explaining this, we're fine. Thus: adding the necessary comments :)

wim leers’s picture

StatusFileSize
new59.17 KB
damiankloip’s picture

Why do we need to enforce a 'strict contract' here? This seems extreme. This is not a new api, this is test coverage. Also, this will never have any use outside of an instance anyway?

What are you worried people will do in this method? As long as it is documented what return value is expected I don't see a problem.

wim leers’s picture

#32: This is nothing extreme, \Drupal\simpletest\TestBase::setUp() does exactly the same already.

Can we please not focus on a tiny implementation detail in tests?

damiankloip’s picture

Can we please not focus on a tiny implementation detail in tests?

Hang on, isn't this issue predominantly about tests? :) Sorry to seem nitpicky, this is just not a pattern we have generally enforced.

TestBase::setUp() just defines an abstract method, not a static one.

Otherwise, don't get me wrong - this looks like some great and thorough test coverage.

wim leers’s picture

Sorry, I meant getInfo():

From TestBase:

  public static function getInfo() {
    // PHP does not allow us to declare this method as abstract public static,
    // so we simply throw an exception here if this has not been implemented by
    // a child class.
    throw new \RuntimeException(String::format('@class must implement \Drupal\simpletest\TestBase::getInfo().', array(
      '@class' => get_called_class(),
    )));
  }

So:

  • it wants to be abstract, but can't, because of PHP limitations
  • it most definitely is static!
damiankloip’s picture

Yes, but this is static for the reason that we can collect all test info data without having to create instances for all of them...

wim leers’s picture

StatusFileSize
new57.16 KB
new2.06 KB

I want to make it as easy as possible to RTBC/commit this issue. That's what I'm trying to do in this reroll.

There was a very slight amount of scope creep: three content cache tags were removed because they're now obsolete, but since this issue focuses on test coverage, they shouldn't be removed here. Only one removal was necessary, two were optional. (See interdiff to find out what's been restored.)

Now it's solely about test coverage for the Comment, Custom Block, Node, Taxonomy Term and User entity cache tags, with simple fixes in:

  • core/lib/Drupal/Core/Entity/Entity (to invalidate render cache of affected entities when modifying a bundle entity type — NodeType already had this, but now it's generalized)
  • Drupal/Core/Entity/EntityViewBuilder (to always set cache tags)
  • Drupal/field/Entity/FieldConfig (to invalidate render cache of affected entities)
  • Drupal/field/Entity/FieldInstanceConfig (to invalidate render cache of affected entities)
  • Drupal/taxonomy/VocabularyStorageController (to not invalidate the content cache tag, because that'd cause one test failure, since it invalidates too much)
moshe weitzman’s picture

Assigned: wim leers » catch
Status: Needs review » Reviewed & tested by the community

Solid expansion of our test coverage. Code looks good.

damiankloip’s picture

So, the same concerns brought up by both me and berdir will get ignored? Ok :)

wim leers’s picture

#39: from #30:

Berdir wanted confirmation from somebody else that the way the base classes added here use static methods to enforce a strict contract is acceptable. We discussed it with alexpott in IRC, and he thinks that if there's a comment explaining this, we're fine. Thus: adding the necessary comments :)

catch’s picture

Status: Reviewed & tested by the community » Needs review
tim.plunkett’s picture

I agree with @damiankloip and @Berdir, I think the use of static methods here is overkill and confusing.

wim leers’s picture

StatusFileSize
new56.38 KB
new9.21 KB

All statics removed.

wim leers’s picture

Status: Needs review » Reviewed & tested by the community

Back to RTBC now that all statics have been removed.

damiankloip’s picture

+1 on that.

wim leers’s picture

Priority: Major » Critical
Issue tags: +blocker

This blocks #2124957: Replace 'content' cache tag with 'rendered' and use it sparingly, which is critical. Hence marking this critical.

catch’s picture

Overall this looks great. I don't think this level of test coverage is actually blocking - we've never had that for cache_clear_all() which was called pretty inconsistently (although generally too much), but great if it makes the other patches easier to work on.

I've not had a lot of core time since Monday and only superficially reviewed.

One question though:

+++ b/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php
+++ b/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php
@@ -361,6 +361,13 @@ public function preSave(EntityStorageControllerInterface $storage_controller) {

Why is this preSave when the FieldConfig cache clear is in preSaveUpdated? I'm wondering if this covers the case where an empty value for a field instance affects the entity display If that's the case it could use a comment, if it's not then preSaveUpdated seems better.

wim leers’s picture

I'm happy to say the answer is simple: "It's just stupid git diff context" :)

Because in both cases, it's actually postSave!

--- a/core/modules/field/lib/Drupal/field/Entity/FieldConfig.php
+++ b/core/modules/field/lib/Drupal/field/Entity/FieldConfig.php
@@ -366,6 +366,13 @@ protected function preSaveUpdated(EntityStorageControllerInterface $storage_cont
  public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
--- a/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php
+++ b/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php
@@ -361,6 +361,13 @@ public function preSave(EntityStorageControllerInterface $storage_controller) {
  public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {

The context that git provides is just misleading!

wim leers’s picture

StatusFileSize
new56.42 KB
new1.21 KB

catch remarked in IRC that the cache invalidation in FieldConfig::postSave() had a small logic flaw: it should only invalidate when updating an existing field_config, because when you create a new field_config, it doesn't affect any entity, it only will once there is a field_instance_config for it that associates it with a specific bundle.

Trivial fix. Tests locally are green.

catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed to 8.x, thanks!

wim leers’s picture

Assigned: catch » wim leers
Issue tags: -sprint

YES! Thanks! :)

Now we can continue with other subissues of #2124957: Replace 'content' cache tag with 'rendered' and use it sparingly! :)

sun’s picture

These tests appear to use two WebTestBase methods only:

1x drupalGet() in verifyPageCache()
1x drupalGetHeader()

Would be great to convert these tests into DUTB (leveraging HttpKernel) in a follow-up issue.

wim leers’s picture

#52: I spent *a lot* of time trying to achieve precisely that — I avoid using WebTestBase like the plague… if I can.

IIRC/AFAICT the problem is that Drupal's page cache sits *on top* of HttpKernel. Therefor, code like

$subrequest = Request::create('/node/1', 'GET');¬
$response = $this->container->get('http_kernel')->handle($subrequest);

does not trigger the page cache, which is part of what's being tested here. If you can show me the light, I will follow it.

damiankloip’s picture

Yeah, I think that might be difficult as _drupal_bootstrap_page_cache() and friends happen pretty early. I don't think you could currently leverage calling kernel->handle() for stuff like that?

Or you want to modify these tests to just check that actual tags contained in the render arrays or something?

Status: Fixed » Closed (fixed)

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