Closed (fixed)
Project:
Drupal core
Version:
8.0.x-dev
Component:
cache system
Priority:
Critical
Category:
Task
Assigned:
Issue tags:
Reporter:
Created:
4 Feb 2014 at 13:20 UTC
Updated:
29 Jul 2014 at 23:21 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #1
wim leersComment #2
wim leersComment #4
wim leers1: term_cache_tags_test-2188565-1.patch queued for re-testing.
Comment #5
wim leersStraight reroll.
Comment #7
berdirHm, 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.
Comment #8
wim leers#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:
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
Drupal\system\Tests\Cache\PageCacheTagsTestBase: the base class that should be used by every cache tags test. Enables page caching and comes with a handyverifyPageCache($path, $hit_or_miss, $tags = FALSE)method.\Drupal\system\Tests\Entity\EntityCacheTagsTestBase, extendsPageCacheTagsTestBase: 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.\Drupal\system\Tests\Entity\EntityWithUriCacheTagsTestBase, extendsEntityCacheTagsTestBase: 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
EntityViewBuilderonly 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!Comment #10
wim leersIt seems that just before I posted the patch, the
field_entityentity type was renamed tofield_configandfield_instancetofield_instance_config. Great changes, but they broke my patch :)Testbot also surfaced
NodePageCacheTestas being broken (yay!), which was introduced by #1841900: Node deletion should clear page cache. It inappropriately uses thecontentcache 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 removingNodePageCacheTest.Comment #12
wim leersThat was very painful to debug, but this should do the trick.
Comment #15
wim leersxdebug_break()call… STUPID!Comment #16
nielsvm commentedWim,
I applied the latest patch against core
96e7aa9a331f1f4651f862c7ddb5039512cba945and 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
core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php
core/modules/node/lib/Drupal/node/Form/DeleteMultiple.php
core/modules/node/lib/Drupal/node/Form/NodeDeleteForm.php
core/modules/node/lib/Drupal/node/Tests/NodePageCacheTest.php
core/modules/system/lib/Drupal/system/Tests/Entity/EntityViewBuilderTest.php
core/modules/system/tests/modules/entity_test/entity_test.routing.yml
core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Controller/EntityTestController.php
Comment #18
wim leers#16: Thanks for the review!
I'm afraid that you reviewed the patch incorrectly though:
MenuTest, where there's no cache tags test anymore, it's been moved toMenuCacheTagsTest. 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.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!
Comment #19
nielsvm commentedThat's been quite stupid from me, coffee!
Comment #20
berdirHm, 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 ;)
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 :)
Creative ;)
Why not just make it abstract? :)
PhpUnit says these two are unused.
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.
Comment #21
wim leersSome 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
NodeTypeshould also affectNode, 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.
Yes! See the above example.
Agreed, but that's a different case of "specialness" when compared to the above example, wouldn't you agree?
Agreed. Where per-user content is rendered, it's the responsibility of the thing that does per-user rendering to set
#cache = FALSE.That's exactly what this patch needs! :)
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 overridingcreateReferenceTestEntities(), but I figured I'd keep the door open.TestBase::getInfo()for another such example.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.
Comment #23
berdir1. 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.
Nitpick: add should start with an uppercase character.
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 :)
Comment #24
wim leersThe 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
statickeyword, which I want to be there for the above reason. If I try what you did, but restore thestatickeyword, 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_blockentities, whose bundle entity type iscustom_block_type. So far, I'd only added the additional test cases to thetestEntityUri()test case (which is not run for custom blocks, since they don't have a URI), and not yet also to thetestReferencedEntity()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 inVocabularyare gone,NodeTypebecame a bit simpler, and no more changes toCustomBlockTypeare necessary.Anybody can think of yet more test cases? :)
Comment #26
wim leersIt seems this fatal error is nigh impossible to debug… The review log says this:
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…
Comment #28
berdir1. & 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.
Comment #29
wim leersSo, #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.
Comment #30
wim leersBerdir 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 :)
Comment #31
wim leersStraight reroll, #1987694: Convert entity_test callbacks to a new style controller broke this.
Comment #32
damiankloip commentedWhy 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.
Comment #33
wim leers#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?
Comment #34
damiankloip commentedHang 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.
Comment #35
wim leersSorry, I meant
getInfo():From
TestBase:So:
Comment #36
damiankloip commentedYes, but this is static for the reason that we can collect all test info data without having to create instances for all of them...
Comment #37
wim leersI 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
contentcache 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 —NodeTypealready 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 thecontentcache tag, because that'd cause one test failure, since it invalidates too much)Comment #38
moshe weitzman commentedSolid expansion of our test coverage. Code looks good.
Comment #39
damiankloip commentedSo, the same concerns brought up by both me and berdir will get ignored? Ok :)
Comment #40
wim leers#39: from #30:
Comment #41
catchComment #42
tim.plunkettI agree with @damiankloip and @Berdir, I think the use of static methods here is overkill and confusing.
Comment #43
wim leersAll statics removed.
Comment #44
wim leersBack to RTBC now that all statics have been removed.
Comment #45
damiankloip commented+1 on that.
Comment #46
wim leersThis blocks #2124957: Replace 'content' cache tag with 'rendered' and use it sparingly, which is critical. Hence marking this critical.
Comment #47
catchOverall 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:
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.
Comment #48
wim leersI'm happy to say the answer is simple: "It's just stupid git diff context" :)
Because in both cases, it's actually
postSave!The context that git provides is just misleading!
Comment #49
wim leerscatch remarked in IRC that the cache invalidation in
FieldConfig::postSave()had a small logic flaw: it should only invalidate when updating an existingfield_config, because when you create a newfield_config, it doesn't affect any entity, it only will once there is afield_instance_configfor it that associates it with a specific bundle.Trivial fix. Tests locally are green.
Comment #50
catchCommitted/pushed to 8.x, thanks!
Comment #51
wim leersYES! Thanks! :)
Now we can continue with other subissues of #2124957: Replace 'content' cache tag with 'rendered' and use it sparingly! :)
Comment #52
sunThese tests appear to use two
WebTestBasemethods only:1x
drupalGet()inverifyPageCache()1x
drupalGetHeader()Would be great to convert these tests into DUTB (leveraging
HttpKernel) in a follow-up issue.Comment #53
wim leers#52: I spent *a lot* of time trying to achieve precisely that — I avoid using
WebTestBaselike the plague… if I can.IIRC/AFAICT the problem is that Drupal's page cache sits *on top* of
HttpKernel. Therefor, code likedoes 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.
Comment #54
damiankloip commentedYeah, 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?