Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Wim Leers created an issue. See original summary.

gabesullice’s picture

Assigned: Unassigned » gabesullice
Wim Leers’s picture

gabesullice’s picture

I'm still working on this, but here's the progress.

Wim Leers’s picture

  1. +++ b/tests/modules/jsonapi_test_field_access/jsonapi_test_field_access.module
    @@ -7,15 +7,20 @@
    +    return (($account->hasPermission($permission))
    

    Übernit: that's a lot of parentheses!

  2. +++ b/tests/src/Functional/ResourceTestBase.php
    @@ -247,7 +248,7 @@ abstract class ResourceTestBase extends BrowserTestBase {
    -        'target_bundles' => [$account_bundle => $account_bundle],
    +        'target_bundles' => NULL,
    

    Hm, I suspect the code in HEAD is incorrect, and you needed to change it? (But without consequences in HEAD, which is why HEAD's passing tests just fine?)

  3. +++ b/tests/src/Functional/ResourceTestBase.php
    @@ -729,10 +730,18 @@ abstract class ResourceTestBase extends BrowserTestBase {
    -    $this->assertSame(array_keys($expected_document), array_keys($actual_document), 'The documents must share the same top-level members');
    +    $expected_keys = array_keys($expected_document);
    +    $actual_keys = array_keys($actual_document);
    +    $missing_member_names = array_diff($expected_keys, $actual_keys);
    +    $extra_member_names = array_diff($actual_keys, $expected_keys);
    +    if (!empty($missing_member_names) || !empty($extra_member_names)) {
    +      $message_format = "The document members did not match the expected values. Missing: [ %s ]. Unexpected: [ %s ]";
    +      $message = sprintf($message_format, implode(', ', $missing_member_names), implode(', ', $extra_member_names));
    +      $this->assertSame($expected_document, $actual_document, $message);
    +    }
    

    +1 — this improves testing/debugging DX. We have something very similar for cache tags/contexts headers test assertions :)

  4. +++ b/tests/src/Functional/ResourceTestBase.php
    @@ -1228,7 +1237,7 @@ abstract class ResourceTestBase extends BrowserTestBase {
    -   * Tests GETing relationships of an individual resource.
    +   * Tests CRUD of individual resource relationship data.
    
    @@ -1237,13 +1246,32 @@ abstract class ResourceTestBase extends BrowserTestBase {
    -  public function testGetRelationships() {
    +  public function testRelationships() {
    

    Why?

    Why not create testPostRelationships() etc?

  5. +++ b/tests/src/Functional/ResourceTestBase.php
    @@ -1322,6 +1352,50 @@ abstract class ResourceTestBase extends BrowserTestBase {
    +    // Test POST: empty body.
    +    // Test POST: empty data.
    +    // Test POST: data as resource identifier, not array of identifiers.
    +    // Test POST: missing field.
    +    // Test POST: invalid target.
    +    // Test POST: internal resource type target.
    +    // Test POST: success.
    

    Nice todo list!

gabesullice’s picture

1. ✅
2. Yeah. This current code is a valid field configuration for an ER field to a bundle-able entity type, but it's not what would actually be created for a User ER field AFAICT. This change is what prompted #2976371: Impossible to POST|PATCH relationship to bundle-less entity or entity reference field without target bundles and that's why it's not broken in HEAD.
3. Glad you like it. It seems I change this in every round of testing, but it keeps getting more helpful (I hope).
4. To keep the number of tests (read, time) down. See doTestRelationships(Get|Post) for the separated versions.
5 :)

gabesullice’s picture

This should fix some of the errors.

gabesullice’s picture

This should get the remaining fails. Now to start on that todo list!

gabesullice’s picture

Well... I started on that list only to find these new errors... bummer. Anyway, easy fix.

gabesullice’s picture

Getting some of the todos set up, most need follow up issues.

Wim Leers’s picture

  1. +++ b/tests/modules/jsonapi_test_field_access/jsonapi_test_field_access.permissions.yml
    @@ -0,0 +1,7 @@
    +field_jsonapi_test_entity_ref update access:
    +  description: 'Gives access to to PATCH, POST or DELETE values of the relationship test field.'
    +  title: 'Update JSON API relationship test field'
    +
    +field_jsonapi_test_entity_ref edit access:
    +  description: 'Gives access to to PATCH, POST or DELETE values of the relationship test field.'
    +  title: 'Update JSON API relationship test field'
    

    These are nearly identical… this is very confusing! 😵 I think one is intended for updating, the other for creating?

  2. +++ b/tests/src/Functional/ResourceTestBase.php
    @@ -1237,13 +1245,32 @@ abstract class ResourceTestBase extends BrowserTestBase {
    +    // Test GET.
    ...
    +    // Test POST.
    

    PATCHing relationships is not yet tested?

  3. +++ b/tests/src/Functional/ResourceTestBase.php
    @@ -1322,6 +1351,96 @@ abstract class ResourceTestBase extends BrowserTestBase {
    +      // Test POST: missing field.
    +      // @todo write this test.
    +      // Test POST: invalid target.
    +      // @todo write this test.
    +      // Test POST: internal resource type target.
    +      // @todo write this test.
    

    These are still intended to happen in this issue, I think?

  4. +++ b/tests/src/Functional/ShortcutTest.php
    @@ -56,7 +56,7 @@ class ShortcutTest extends ResourceTestBase {
    -        'uri' => 'internal:/admin/content/comment',
    +        'uri' => 'internal:/user/logout',
    

    Why this change?

  5. +++ b/tests/src/Functional/UserTest.php
    @@ -104,6 +104,7 @@ class UserTest extends ResourceTestBase {
    +    $user->setEmail("$key@example.com");
    

    Why this change?

gabesullice’s picture

#12.1: Yes, something like that, it was very confusing! I'm not even sure it's necessary to have these defined at all, I might just be able to add them in the test, in which case I'll put comments there.
12.2: Correct, and that will be done in this issue
12.3: Correct, see attached!
12.4/5: Because PATCHing a relationship triggers validation of the entity. A shortcut uri field has a validation contraint that it be accessible by the user, and a user email field has a validation constraint that the email be unique. Surprisingly, this didn't come up before because we were saving these entities from within the test container without calling validate first.

gabesullice’s picture

+++ b/tests/src/Functional/ResourceTestBase.php
@@ -1397,11 +1397,19 @@ abstract class ResourceTestBase extends BrowserTestBase {
-      // Test POST: internal resource type target.
-      // @todo write this test.

Note that I did not end up writing a test for this. I think it would require unnecessary work to get set up.

Wim Leers’s picture

Just FYI: #13's interdiff looks great :)

  1. +++ b/tests/src/Functional/ResourceTestBase.php
    @@ -1397,11 +1397,19 @@ abstract class ResourceTestBase extends BrowserTestBase {
           // Test POST: missing field.
    ...
    +      $request_options[RequestOptions::BODY] = Json::encode(['data' => array_intersect_key($target_identifier, ['id' => 'id'])]);
    

    This is not just missing a field, this is missing essential information. Updating the comment is sufficient.

  2. +++ b/tests/src/Functional/ResourceTestBase.php
    @@ -1418,14 +1426,20 @@ abstract class ResourceTestBase extends BrowserTestBase {
           //// Test POST: success, relationship already exists, with unique arity.
    

    Übernit: not yet unindented :)

gabesullice’s picture

#15.1: done
15.2. fixed


This adds PATCH+DELETE coverage.


CS patch to follow along w/ any unexpected failures.

gabesullice’s picture

gabesullice’s picture

gabesullice’s picture

Assigned: gabesullice » Unassigned
Status: Active » Needs review

😅whew. done for now :)

Status: Needs review » Needs work

The last submitted patch, 18: 2972808-18.patch, failed testing. View results

Wim Leers’s picture

Status: Needs work » Needs review
FileSize
968 bytes
26.85 KB

EPIC EPIC EPIC work!

+++ b/tests/src/Functional/ResourceTestBase.php
@@ -1440,12 +1440,12 @@ abstract class ResourceTestBase extends BrowserTestBase {
       // @todo: Uncomment the following two assertions in https://www.drupal.org/project/jsonapi/issues/2977659.
-      //// Test POST: success, relationship already exists, no arity.
-      //$response = $this->request('POST', $url, $request_options);
-      //$this->assertResourceResponse(204, NULL, $response);
+      // Test POST: success, relationship already exists, no arity.
+      $response = $this->request('POST', $url, $request_options);
+      $this->assertResourceResponse(204, NULL, $response);

I'm 99% certain Gabe only meant to remove the extraneous slashes on line 1447, but in doing so, PHPStorm helpfully also uncommented lines 1448 and 1449. All failures are on line 1448.

So, reverting this.

Wim Leers’s picture

So, review time!


My review in #12:

  1. #12.1 was addressed by #17: it removed that.
  2. #12.2+#12.3 were implemented by subsequent patches.
  3. #12.4+#12.5 were answered/clarified in #13

Issues discovered here (yay for test coverage to find places where things were not quite working the right way!):

  1. #2977653: Spec Compliance: Return 204 or 200, not 201 for relationship POST requests.
  2. #2977659: Spec Compliance: POST|PATCH|DELETE on relationships should respect arity rules
  3. #2976371: Impossible to POST|PATCH relationship to bundle-less entity or entity reference field without target bundles

The last of those three is already fixed, and already shipped with the 1.19 release!


Issues not discovered here, but related: #2956084: Impossible to raise an error when an `include` is requested for an inaccessible relationship field.. In #8, @gabesullice said that issue would solve problems encountered in this issue. I took it as meaning that #2956084 was a blocker for this issue, but obviously it isn't.


Re-review of the patch:

  1. +++ b/tests/src/Functional/ResourceTestBase.php
    @@ -1323,6 +1352,214 @@ abstract class ResourceTestBase extends BrowserTestBase {
    +      // Test DELETE: no existing relationships, no op, success.
    ...
    +      $this->assertResourceResponse(201, $expected_document, $response);
    +      /* $this->assertResourceResponse(204, NULL, $response); */
    

    Woah! This makes sense, but I had to think it through. Idempotency means this must indeed be a 204 response.

  2. +++ b/tests/src/Functional/ResourceTestBase.php
    @@ -1323,6 +1352,214 @@ abstract class ResourceTestBase extends BrowserTestBase {
    +      // Test PATCH: success, new value is different than existing value.
    +      $request_options[RequestOptions::BODY] = Json::encode(['data' => [$target_identifier, $target_identifier]]);
    ...
    +      // Test DELETE: two existing relationships, both removed because no arity
    +      // was specified.
    

    This is great, but I have one question/reservation: we're never testing the deleting of a specific arity.

    What if the first quoted line would create three relationships instead of two, we'd then delete the "middle" one by specifying the appropriate arity, verify this in the response, and then delete without specifying an arity, which should result in no relationships being left?

    Perhaps this is something that is up to #2977659: Spec Compliance: POST|PATCH|DELETE on relationships should respect arity rules to add?

That second point is the only remaining question I have! After it's answered/addressed, this is RTBC :)

gabesullice’s picture

Status: Needs review » Reviewed & tested by the community

I'm 99% certain Gabe only meant to remove the extraneous slashes on line 1447, but in doing so, PHPStorm helpfully also uncommented lines 1448 and 1449. All failures are on line 1448.

So, reverting this.

🙏❤️

This is great, but I have one question/reservation: we're never testing the deleting of a specific arity.

You're correct that we can't test it until #2977659: Spec Compliance: POST|PATCH|DELETE on relationships should respect arity rules lands. BUT, there is coverage that just needs to be uncommented:

+++ b/tests/src/Functional/ResourceTestBase.php
@@ -1323,6 +1352,214 @@ abstract class ResourceTestBase extends BrowserTestBase {
+      // @todo: Uncomment the following block in https://www.drupal.org/project/jsonapi/issues/2977659.
+      // @codingStandardsIgnoreStart
+      //// Test DELETE: two existing relationships, one removed.
+      //$request_options[RequestOptions::BODY] = Json::encode(['data' => [
+      //  $target_identifier + ['meta' => ['arity' => 0]],
+      //]]);
+      //$response = $this->request('DELETE', $url, $request_options);
+      //// @todo Remove 3 lines below in favor of commented line in https://www.drupal.org/project/jsonapi/issues/2977653.
+      //$resource->set($relationship_field_name, [$target_resource]);
+      //$expected_document = $this->getExpectedGetRelationshipDocument($relationship_field_name, $resource);
+      //$this->assertResourceResponse(201, $expected_document, $response);
+      //// $this->assertResourceResponse(204, NULL, $response);
What if the first quoted line would create three relationships instead of two, we'd then delete the "middle" one by specifying the appropriate arity, verify this in the response

I don't think it's necessary to test with 3 relationships and verify 2 remaining, since arity is not a stored value, it is a calculated one.

IOW, there's no difference in final result if I delete the 0th, 1st or 2nd arity item—I'll always end up with [{id: A, arity: 0}, {id: A, arity: 1}] in the end.

then delete without specifying an arity, which should result in no relationships being left?

That's is in there too :)

+++ b/tests/src/Functional/ResourceTestBase.php
@@ -1323,6 +1352,214 @@ abstract class ResourceTestBase extends BrowserTestBase {
+      // Test DELETE: two existing relationships, both removed because no arity
+      // was specified.
+      $request_options[RequestOptions::BODY] = Json::encode(['data' => [$target_identifier]]);

That second point is the only remaining question I have! After it's answered/addressed, this is RTBC :)

I think I've thoroughly addressed it, so moving to RTBC!

Wim Leers’s picture

BUT, there is coverage that just needs to be uncommented:

🙈 OMG! 😳

That's what I looked for, but I only looked further down in the patch rather than up. Which doesn't even make sense. If I'd seen that, I'd have committed it already.

I don't think it's necessary to test with 3 relationships and verify 2 remaining, since arity is not a stored value, it is a calculated one.

Right again; I misremembered arity for its original implementation (synonym for Drupal's delta), but obviously that's not what it is.

That's is in there too :)

Yep, that's the portion that's already being run/tested :)

RTBC confirmed, committing…

Wim Leers’s picture

Status: Reviewed & tested by the community » Fixed

🍻

gabesullice’s picture

🎊🤘

Status: Fixed » Closed (fixed)

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