Problem/Motivation
Please refer the problem/motivation section of #2737719: EntityResource: Provide comprehensive test coverage: for every entity type, every format, every method
Proposed resolution
Write EntityResourceTestBase subclass for the FieldStorageConfig entity.
Unfortunately, FieldStorageConfig
does not have an access control handler at all yet, so that needs to be added too. Fortunately, the FieldConfig
config entity type has an access control handler that actually looks up the FieldStorageConfig
entity that's associated with a FieldConfig
entity. So, the logic from that access control handler can be extracted into FieldStorageConfigAccessControlHandler
, and then FieldConfigAccessControlHandler
can be updated to delegate to FieldStorageConfigAccessControlHandler
!
Remaining tasks
- Create
access
handler forFieldStorageConfig
- Write
FieldStorageConfigResourceTestBase
+ subclasses for concrete tests
References
1. Follow-up of #2737719: EntityResource: Provide comprehensive test coverage: for every entity type, every format, every method
2. Subtask of #2824572: Write EntityResourceTestBase subclasses for every other entity type.
Comment | File | Size | Author |
---|---|---|---|
#59 | rest_field_storage_config-2843756-59.patch | 20.87 KB | Wim Leers |
#52 | interdiff.txt | 6.49 KB | Anonymous (not verified) |
#52 | rest_field_storage_config-2843756-51.patch | 20.38 KB | Anonymous (not verified) |
#50 | rest_field_storage_config-2843756-50.patch | 19.02 KB | Wim Leers |
#50 | interdiff.txt | 1.46 KB | Wim Leers |
Comments
Comment #3
jamesdeee CreditAttribution: jamesdeee as a volunteer and at manifesto commentedHey - I'm keen to help out with this. Just wondering, should I change it so the version is 8.4? I was reading through the allowed changes documentation and it doesn't seem like this fits any of the allowed changes:
...though i guess it might count as internal code cleanup?
Comment #4
jamesdeee CreditAttribution: jamesdeee as a volunteer and at manifesto commentedComment #5
jamesdeee CreditAttribution: jamesdeee as a volunteer and at manifesto commentedI'm trying my best to understand this but I'm drawing a bit of a blank. Based on reading around the comments in this group of issues, what I understand is the following:
There are already a group of test classes, in the modules/rest/tests/src/Functional/EntityResource directory, that extend the EntityResourceTestBase class. The ones I can see are for Block, Comment, ConfigTest, EntityTest, MenuLinkContext, Node, Role, Term, User and Vocabulary.
What's missing are tests for - amongst other things - FieldStorageConfig.
So the task here is to provide tests - presumably following the pattern in the existing directories (that is to say, NodeJsonAnonTest, NodeJSonBasicAuthTest, etc), for FieldStorageConfig?
My second question is - I'm struggling a little with running the tests. I'd assumed you'd run the test files as follows:
From docroot/core run ../vendor/bin/phpunit modules/rest/tests/src/Functional/EntityResource/Node/NodeResourceTestBase.php (for example)...
But when I do that I get the following error:
Class 'modules/rest/tests/src/Functional/EntityResource/Node/NodeResourceTestBase' could not be found in '/var/www/site/docroot/core/modules/rest/tests/src/Functional/EntityResource/Node/NodeResourceTestBase.php'.
Am I missing something? Should I run the tests differently?
I'd be really grateful if someone could help me out!
Comment #6
Wim Leers#3: this should be solely adding tests. Adding more tests to prove correctness and prevent regressions is acceptable in 8.3.
#5:
\Drupal\Tests\rest\Functional\EntityResource\FieldStorageConfig\FieldStorageConfigTestResourceTestBase
,\Drupal\Tests\rest\Functional\EntityResource\FieldStorageConfig\FieldStorageConfigTestJsonAnonTest
,\Drupal\Tests\rest\Functional\EntityResource\FieldStorageConfig\FieldStorageConfigTestJsonCookieTest
and\Drupal\Tests\rest\Functional\EntityResource\FieldStorageConfig\FieldStorageConfigTestJsonBasicAuthTest
NodeJsonAnonTest
instead. Or, if you want to run all tests in that directory, doP.S.: to run all
rest
tests, dophp vendor/bin/phpunit -c core --group rest
. To run allhal
tests, runphp vendor/bin/phpunit -c core --group hal
.Comment #7
jamesdeee CreditAttribution: jamesdeee as a volunteer and at manifesto commentedGreat - thanks very much, Wim - running the tests like that works fine. And thanks for confirming my assumption about what needs to be done. I'll get started!
Comment #8
Wim LeersThanks a lot, @jamesdesq :)
Comment #9
jamesdeee CreditAttribution: jamesdeee as a volunteer and at manifesto commentedHey - I'm trying to get a response out of the endpoint itself before I start testing, just so I can see how it's meant to work in real life. I'm not 100% what parameter should be passed to the endpoint - the UI just gives:
/entity/field_storage_config/{field_storage_config}
Looking at the data, it looks as though the field storage config is stored as follows:
i've tried passing both the UID and the name (i.e. field.node.article_body) as the parameter, and I either get an empty message, or the following message:
Am I passing the correct parameter?
Thanks
James
Comment #10
Wim LeersGo to
/admin/config/development/configuration/single/export
. Select in the first dropdown. The values in the second dropdown list allfield_storage_config
IDs.Alternatively:
Comment #11
jamesdeee CreditAttribution: jamesdeee as a volunteer and at manifesto commentedCheers Wim.
I've found the field_storage_config ID as you describe, but I'm still having some trouble with this.
I think I'm probably passing the credentials in the wrong way. I'm using Postman to make a request to /entity/field_storage_config/node.body?_format=hal_json. I've set the endpoint to accept basic authentication, and I'm passing the credentials in using the Postman basic authentication UI. I'm also using Content-Type: application/hal+json in the header.
I've put some breaks in the code, and I can see that where I'm having trouble is in EntityResource.php, where it looks as though $entity_access is being set to AccessResultNeutral, and so is returning an access error.
I can see that previous versions of RESTful defined CRUD permissions on the item in question, but that doesn't appear to be happening in 8.3. I can access, for instance, node resources via the API, and I can create content using the credentials I've provided.
I can also see in the access function in Drupal\Core\Entity the account parameter is null. Is this because I'm passing the credentials incorrectly in the get request?
Sorry for all the preliminary questions. I'll get there in the end.
Comment #12
jamesdeee CreditAttribution: jamesdeee as a volunteer and at manifesto commentedOK, so it looks like I can get a lot further with the view entity, so I figure for the time being I'm going to put this one on hold and write tests for the view entity (https://www.drupal.org/node/2824572). Hopefully on the way I'll learn some more stuff about how the REST module works and I'll be able to come back to this one.
Comment #13
Wim Leers\Drupal\field\Entity\FieldStorageConfig
has this entity type annotation:As you can see, it specifies only one handler: a
storage
handler. This means it inherits the defaultaccess
handler:\Drupal\Core\Entity\EntityAccessControlHandler
.The problem here is that basically nothing so far has been trying to
view
FieldStorageConfig
entities.In order for this to work, you'll need to create a new
FieldStorageConfigAccessControlHandler
. Which means this is not a issue after all. Sorry about that!Comment #14
Anonymous (not verified) CreditAttribution: Anonymous commentedHandler
FieldStorageConfigAccessControlHandler
made like copy ofFieldConfigAccessControlHandler
.Comment #15
Wim Leerss/field/field storage config/
Just change this to:
class FieldStorageConfigAccessControlHandler extends class FieldConfigAccessControlHandler {}
:)
Comment #16
Wim LeersOops!
Comment #17
naveenvalecha#15 change is the novice one. Adding Novice tag
Comment #18
brentschuddinck CreditAttribution: brentschuddinck as a volunteer commentedChanged
class FieldStorageConfigAccessControlHandler extends EntityAccessControlHandler
toclass FieldStorageConfigAccessControlHandler extends FieldConfigAccessControlHandler
(#15)Comment #19
Wim Leers@brentschuddinck I'm afraid that's not what your patch is doing :) Can you post the right patch? Thanks!
Comment #20
Wim LeersComment #21
Anonymous (not verified) CreditAttribution: Anonymous commented15.1 - eagle eyes @Wim Leers!
15.2 - hah!
18 - thanks for help @brentschuddinck, let me correct my mistakes too ;)
Comment #22
Wim LeersCan't we hardcode this?
Once this is fixed (or answered), this is RTBC.
Comment #23
Anonymous (not verified) CreditAttribution: Anonymous commentedDone, thanks!
Comment #24
Wim LeersComment #25
Anonymous (not verified) CreditAttribution: Anonymous commentedNot reason for get id programmatically. With "hardcode" look really harmonious and homogeneous. Thanks for this hint!
Comment #26
Wim Leersnp :)
Comment #27
alexpottCommitted and pushed df2fd66 to 8.4.x and bfaa4f5 to 8.3.x. Thanks!
Committed to to 8.3.x because it is mostly adding test coverage. Yes there is a change to the entity access handling but calling the same access handler as for FieldConfig entities for FieldStorageConfig makes perfect sense and likely will help avoid access mistakes in the future. The lack of an access handler is a bug.
Comment #30
alexpott@jamesdesq - nice efforts on this issue and I hope you get the chance to learn more about the REST API. And thank you for explaining everything you were thinking on the issue. This really helps others follow along. Whilst I did not give you patch credit in the git log because you didn't contrib to the patch I am going to give you issue credit for the effort you took to document what you were trying and how you were learning along the way.
Comment #31
Wim Leers#27: RE access handler: exactly :)
#30: <3
Comment #32
jamesdeee CreditAttribution: jamesdeee as a volunteer and at manifesto commentedThanks guys - that's really nice to hear! I'm sorry I couldn't help more - I've had a really busy couple of weeks. Next time!
Comment #33
Anonymous (not verified) CreditAttribution: Anonymous commented@jamesdesq, nice to hear. You really helped clarify this issue, and get more knowledge. Attack on #2824572: Write EntityResourceTestBase subclasses for every other entity type. has just begun ;)
Comment #34
tstoecklerUnfortunately this should be rolled back. The choice to re-use the field config access handler is not correct for the
delete
case.Therefore calling
Now yields:
whereas it worked before.
Luckily neither our UIs nor Rest are calling this, but there is still the chance of contrib using this.
Comment #36
alexpott@tstoeckler nice spot thanks... obviously we're missing testing coverage of actually calling the delete via REST with the correct permission.
Comment #37
alexpottComment #38
alexpottSo that's why we didn't get a test fail with this.
Comment #39
tstoecklerThis still needs to be reverted in 8.3.x, as far as I can tell.
Comment #40
alexpott@tstoeckler it appears you put way too much faith in the git to d.o integration :) http://cgit.drupalcode.org/drupal/commit/?h=8.3.x&id=68571abcac07e7c6b20...
Comment #41
Wim Leers#34: Wow, great find!
#39: yeah, unfortunately commits scarily often are not mentioned on d.o issues :(
So… how do we add test coverage for something that we literally can't test? Functional test coverage for this is impossible, because deleting config entities is simply not yet supported. I'd say
, but\Drupal\field\FieldConfigAccessControlHandler
also doesn't have unit test coverage. So… that's kind of sad, and out of scope to fix here :(I started looking into this. And I noticed that
FieldConfigAccessControlHandler
was actually retrieving aFieldStorageConfig
object to check whether it can/should be deleted. So… we can actually flip things around: we can move 99% of the logic inFieldConfigAccessControlHandler
toFieldStorageConfigAccessControlHandler
, and then letFieldConfigAccessControlHandler
extendFieldStorageConfigAccessControlHandler
, and let it call the parent implementation!I think that addresses all concerns? Thoughts?
Comment #42
tstoecklerWhy are we not calling
$field_storage_entity->access()
? I think that would be more explicit and would allow us to not extend the field storage access handler. So if someone swaps that out things would still work.Comment #43
Wim Leers#42: Field access != entity access.
EDIT: except that this is using entity access so you're totally right :) Rerolling.
Comment #44
Wim LeersAddresses #42.
Comment #46
tstoecklerThanks, looks good to me!
Minor nitpick:
Missing newline here.
Comment #47
Anonymous (not verified) CreditAttribution: Anonymous commentedI tried adding tests (before #41), should I transfer them to a follow-up issue? Unfortunately, the cache does not dependence from
'locked'
property, so two separate entity instead of$entity->setLocked(TRUE/FALSE)->save()
for testing'delete'
case.And maybe bit cleanup checkAccess? Like:
Comment #48
Wim Leers#47: if you'd make this a unit test, then calling
setLocked(TRUE/FALSE)->save()
would work just fine.See
\Drupal\Tests\user\Unit\UserAccessControlHandlerTest
for an example.At first I was not planning to let this issue add test coverage. But with #47 already doing that in part, we might as well get it done.
Comment #49
Anonymous (not verified) CreditAttribution: Anonymous commentedThanks for the tip! Unfortunately, the Unit is not easy for me. I tried to do test, but obviously did it wrong. Therefore, a rude hack:
$this->accessControlHandler->resetCache();
Comment #50
Wim LeersNo, you're not wrong. I didn't even know
EntityAccessControlHandler
had its own static cache. That's … a bit silly.Static caches don't respect cache tag invalidation. Hence the need for that "rude hack" as you put it. It's really the only solution. Nothing "rude" about it :)
The anonymous user is always user zero. So it's a bit strange to see
1
here. Fixed.Also added a comment regarding resetting the static cache.
Still left to be done: unit test for
FieldConfigAccessControlHandler
. You'll be able to mostly duplicate\Drupal\Tests\field\Unit\FieldStorageConfigAccessControlHandlerTest
:)Comment #51
Wim LeersNW for #50.
at the end ofComment #52
Anonymous (not verified) CreditAttribution: Anonymous commented#50: Thank you for the very quick and helpful explanation @Wim Leers!
#51: of course, sorry for delay with response. I'm just looking for a way to reduce the copy-paste between these tests.
Comment #53
Wim LeersThis looks great, thank you so much, @vaplas! This is very helpful :)
P.S.: this is definitely crossing the
boundary. Hope you're learning useful things here!Comment #54
jamesdeee CreditAttribution: jamesdeee as a volunteer and at manifesto commentedDon't know if anyone can help me out with this, but I'm having a heck of a time getting Xdebug working with PHPStorm and PHPUnit. What I want to be able to do is drop a breakpoint in the tests and debug them from there. I've got Xdebug working for the site itself and I can run the tests from within PHPStorm, but I can't seem to get debugging working. I've got Storm configured as described here (https://www.drupal.org/docs/8/phpunit/running-phpunit-tests-within-phpstorm).
Am I missing something obvious? Is that how you guys are doing it, or should I be doing it differently?
If anyone can point me towards anything that'll help me get set up I'd be really grateful.
Comment #55
Wim LeersNote these are not typical PHPUnit tests. They use PHPUnit as a test runner, but they're not unit tests, they're functional tests. They make requests etc. #2866056: ResourceTestBase should not have a timeout will probably help.
Comment #56
Anonymous (not verified) CreditAttribution: Anonymous commented@jamesdesq, maybe this article will helpful too. See "CONFIGURE PHPSTORM" section, special note on
Preferences > Languages & Frameworks > PHP > Debug
settings.Comment #57
jamesdeee CreditAttribution: jamesdeee as a volunteer and at manifesto commentedThanks both. @wim-leers - that's an important distinction, and one which I hadn't really understood until you pointed it out.
If anyone else is following this thread and, like me, has failed to understand the difference between ordinary unit tests and functional tests, here is a useful tutorial:
https://www.drupal.org/docs/8/phpunit/phpunit-browser-test-tutorial
Comment #58
alexpottI think this needs a comment about why delegating access control to the field storage is the correct thing to do. The new unit tests look great.
Comment #59
Wim LeersDone.
Comment #60
alexpottCommitted a6b84bf and pushed to 8.4.x. Thanks!
I think this should be backported to 8.3.x because adding the access handler is a bug fix. But cause of BC etc I want to get another committer opinion first.
Coding standards fixed on commit.
Comment #62
alexpottIt'd be great if the issue handler can be updated so to make it clear why this became more than just adding tests.
Comment #63
Wim LeersDone.
Comment #64
Gábor HojtsyWhat is the BC concern here for Drupal 8.3.x? That services accessing field storage config had full access before and now governed by permissions?
Comment #65
alexpottLooking at the code I don't think that there full access before - in fact I think everything would have been denied because in core the access check for field storages would return neutral.
So actually I'm not sure there are any BC concerns here actually. And adding or changing access control handlers is explicitly exempt in the BC policy. Still given the complexities of BC judgements it'd be great if another reviewer can confirm my thoughts are correct.
Comment #66
Wim LeersThat's correct:
\Drupal\field\Entity\FieldStorageConfig
did not specify anaccess
handler, nor did it specify anadmin_permission
. Which means this code ran in\Drupal\Core\Entity\EntityAccessControlHandler
:The middle return never ran. So always forbidden or neutral.
And:
The first return never ran, so always neutral.
Therefore indeed this should be safe: where access was never granted before, now it is, given sufficient permissions.
Comment #67
Gábor HojtsyThanks for confirming. Merged to 8.3.x.