diff --git a/core/modules/hal/tests/src/Functional/EntityResource/EntityTestLabel/EntityTestLabelHalJsonAnonTest.php b/core/modules/hal/tests/src/Functional/EntityResource/EntityTestLabel/EntityTestLabelHalJsonAnonTest.php new file mode 100644 index 0000000000000000000000000000000000000000..f95ea5ce06bf0da4f56adebcea47e94b33e895a5 --- /dev/null +++ b/core/modules/hal/tests/src/Functional/EntityResource/EntityTestLabel/EntityTestLabelHalJsonAnonTest.php @@ -0,0 +1,103 @@ +applyHalFieldNormalization($default_normalization); + + $author = User::load(0); + return $normalization + [ + '_links' => [ + 'self' => [ + 'href' => '', + ], + 'type' => [ + 'href' => $this->baseUrl . '/rest/type/entity_test_label/entity_test_label', + ], + $this->baseUrl . '/rest/relation/entity_test_label/entity_test_label/user_id' => [ + [ + 'href' => $this->baseUrl . '/user/0?_format=hal_json', + 'lang' => 'en', + ], + ], + ], + '_embedded' => [ + $this->baseUrl . '/rest/relation/entity_test_label/entity_test_label/user_id' => [ + [ + '_links' => [ + 'self' => [ + 'href' => $this->baseUrl . '/user/0?_format=hal_json', + ], + 'type' => [ + 'href' => $this->baseUrl . '/rest/type/user/user', + ], + ], + 'uuid' => [ + [ + 'value' => $author->uuid(), + ], + ], + 'lang' => 'en', + ], + ], + ], + ]; + } + + /** + * {@inheritdoc} + */ + protected function getNormalizedPostEntity() { + return parent::getNormalizedPostEntity() + [ + '_links' => [ + 'type' => [ + 'href' => $this->baseUrl . '/rest/type/entity_test_label/entity_test_label', + ], + ], + ]; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedCacheContexts() { + return [ + 'url.site', + 'user.permissions', + ]; + } + +} diff --git a/core/modules/hal/tests/src/Functional/EntityResource/EntityTestLabel/EntityTestLabelHalJsonBasicAuthTest.php b/core/modules/hal/tests/src/Functional/EntityResource/EntityTestLabel/EntityTestLabelHalJsonBasicAuthTest.php new file mode 100644 index 0000000000000000000000000000000000000000..b3824aa57fa601839dac49a7028bf68da9cd80fd --- /dev/null +++ b/core/modules/hal/tests/src/Functional/EntityResource/EntityTestLabel/EntityTestLabelHalJsonBasicAuthTest.php @@ -0,0 +1,24 @@ +urlInfo('canonical', ['absolute' => TRUE])->toString(TRUE); - return new ModifiedResourceResponse($entity, 201, ['Location' => $url->getGeneratedUrl()]); + $headers = []; + if (in_array('canonical', $entity->uriRelationships(), TRUE)) { + $url = $entity->urlInfo('canonical', ['absolute' => TRUE])->toString(TRUE); + $headers['Location'] = $url->getGeneratedUrl(); + } + return new ModifiedResourceResponse($entity, 201, $headers); } catch (EntityStorageException $e) { throw new HttpException(500, 'Internal Server Error', $e); diff --git a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php index 713d4032183c13f68f53f008bcbd592841043ad3..4a8c304fac0854c943ffeb816030275c482cbe48 100644 --- a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php +++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php @@ -610,15 +610,11 @@ public function testPost() { $request_options = []; - // DX: 404 when resource not provisioned, but HTML if canonical route. + // DX: 404 when resource not provisioned. HTML response because missing + // ?_format query string. $response = $this->request('POST', $url, $request_options); - if ($has_canonical_url) { - $this->assertSame(404, $response->getStatusCode()); - $this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type')); - } - else { - $this->assertResourceErrorResponse(404, 'No route found for "GET ' . str_replace($this->baseUrl, '', $this->getUrl()->setAbsolute()->toString()) . '"', $response); - } + $this->assertSame(404, $response->getStatusCode()); + $this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type')); $url->setOption('query', ['_format' => static::$format]); @@ -634,16 +630,12 @@ public function testPost() { $url->setOption('query', []); - // DX: 415 when no Content-Type request header, plain text if canonical URL. + // DX: 415 when no Content-Type request header. HTML response because + // missing ?_format query string. $response = $this->request('POST', $url, $request_options); - if ($has_canonical_url) { - $this->assertSame(415, $response->getStatusCode()); - $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type')); - $this->assertContains(htmlspecialchars('No "Content-Type" request header specified'), (string) $response->getBody()); - } - else { - $this->assertResourceErrorResponse(415, 'No "Content-Type" request header specified', $response); - } + $this->assertSame(415, $response->getStatusCode()); + $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type')); + $this->assertContains(htmlspecialchars('No "Content-Type" request header specified'), (string) $response->getBody()); $url->setOption('query', ['_format' => static::$format]); @@ -741,8 +733,13 @@ public function testPost() { // 201 for well-formed request. $response = $this->request('POST', $url, $request_options); $this->assertResourceResponse(201, FALSE, $response); - $location = $this->entityStorage->load(static::$firstCreatedEntityId)->toUrl('canonical')->setAbsolute(TRUE)->toString(); - $this->assertSame([$location], $response->getHeader('Location')); + if ($has_canonical_url) { + $location = $this->entityStorage->load(static::$firstCreatedEntityId)->toUrl('canonical')->setAbsolute(TRUE)->toString(); + $this->assertSame([$location], $response->getHeader('Location')); + } + else { + $this->assertSame([], $response->getHeader('Location')); + } $this->assertFalse($response->hasHeader('X-Drupal-Cache')); @@ -762,8 +759,13 @@ public function testPost() { // 201 for well-formed request. $response = $this->request('POST', $url, $request_options); $this->assertResourceResponse(201, FALSE, $response); - $location = $this->entityStorage->load(static::$secondCreatedEntityId)->toUrl('canonical')->setAbsolute(TRUE)->toString(); - $this->assertSame([$location], $response->getHeader('Location')); + if ($has_canonical_url) { + $location = $this->entityStorage->load(static::$secondCreatedEntityId)->toUrl('canonical')->setAbsolute(TRUE)->toString(); + $this->assertSame([$location], $response->getHeader('Location')); + } + else { + $this->assertSame([], $response->getHeader('Location')); + } $this->assertFalse($response->hasHeader('X-Drupal-Cache')); } @@ -796,7 +798,8 @@ public function testPatch() { $request_options = []; - // DX: 404 when resource not provisioned, but 405 if canonical route. + // DX: 404 when resource not provisioned, 405 if canonical route. Plain text + // or HTML response because missing ?_format query string. $response = $this->request('PATCH', $url, $request_options); if ($has_canonical_url) { $this->assertSame(405, $response->getStatusCode()); @@ -804,17 +807,22 @@ public function testPatch() { $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type')); } else { - $this->assertResourceErrorResponse(404, 'No route found for "PATCH ' . str_replace($this->baseUrl, '', $this->getUrl()->setAbsolute()->toString()) . '"', $response); + $this->assertSame(404, $response->getStatusCode()); + $this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type')); } $url->setOption('query', ['_format' => static::$format]); - // DX: 405 when resource not provisioned. + // DX: 404 when resource not provisioned, 405 if canonical route. $response = $this->request('PATCH', $url, $request_options); - $this->assertSame(['GET, POST, HEAD'], $response->getHeader('Allow')); - $this->assertResourceErrorResponse(405, 'No route found for "PATCH ' . str_replace($this->baseUrl, '', $this->getUrl()->setAbsolute()->toString()) . '": Method Not Allowed (Allow: GET, POST, HEAD)', $response); + if ($has_canonical_url) { + $this->assertResourceErrorResponse(405, 'No route found for "PATCH ' . str_replace($this->baseUrl, '', $this->getUrl()->setAbsolute()->toString()) . '": Method Not Allowed (Allow: GET, POST, HEAD)', $response); + } + else { + $this->assertResourceErrorResponse(404, 'No route found for "PATCH ' . str_replace($this->baseUrl, '', $this->getUrl()->setAbsolute()->toString()) . '"', $response); + } $this->provisionEntityResource(); @@ -822,16 +830,11 @@ public function testPatch() { $url->setOption('query', []); - // DX: 415 when no Content-Type request header, but HTML if canonical route. + // DX: 415 when no Content-Type request header. $response = $this->request('PATCH', $url, $request_options); - if ($has_canonical_url) { - $this->assertSame(415, $response->getStatusCode()); - $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type')); - $this->assertTrue(FALSE !== strpos((string) $response->getBody(), htmlspecialchars('No "Content-Type" request header specified'))); - } - else { - $this->assertResourceErrorResponse(415, 'No "Content-Type" request header specified', $response); - } + $this->assertSame(415, $response->getStatusCode()); + $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type')); + $this->assertTrue(FALSE !== strpos((string) $response->getBody(), htmlspecialchars('No "Content-Type" request header specified'))); $url->setOption('query', ['_format' => static::$format]); @@ -990,7 +993,8 @@ public function testDelete() { $request_options = []; - // DX: 404 when resource not provisioned, but 405 if canonical route. + // DX: 404 when resource not provisioned, but 405 if canonical route. Plain + // text or HTML response because missing ?_format query string. $response = $this->request('DELETE', $url, $request_options); if ($has_canonical_url) { $this->assertSame(405, $response->getStatusCode()); @@ -998,18 +1002,23 @@ public function testDelete() { $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type')); } else { - $this->assertResourceErrorResponse(404, 'No route found for "DELETE ' . str_replace($this->baseUrl, '', $this->getUrl()->setAbsolute()->toString()) . '"', $response); + $this->assertSame(404, $response->getStatusCode()); + $this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type')); } $url->setOption('query', ['_format' => static::$format]); - // DX: 405 when resource not provisioned. + // DX: 404 when resource not provisioned, 405 if canonical route. $response = $this->request('DELETE', $url, $request_options); - $this->assertSame(['GET, POST, HEAD'], $response->getHeader('Allow')); - $this->assertResourceErrorResponse(405, 'No route found for "DELETE ' . str_replace($this->baseUrl, '', $this->getUrl()->setAbsolute()->toString()) . '": Method Not Allowed (Allow: GET, POST, HEAD)', $response); - + if ($has_canonical_url) { + $this->assertSame(['GET, POST, HEAD'], $response->getHeader('Allow')); + $this->assertResourceErrorResponse(405, 'No route found for "DELETE ' . str_replace($this->baseUrl, '', $this->getUrl()->setAbsolute()->toString()) . '": Method Not Allowed (Allow: GET, POST, HEAD)', $response); + } + else { + $this->assertResourceErrorResponse(404, 'No route found for "DELETE ' . str_replace($this->baseUrl, '', $this->getUrl()->setAbsolute()->toString()) . '"', $response); + } $this->provisionEntityResource(); diff --git a/core/modules/rest/tests/src/Functional/EntityResource/EntityTestLabel/EntityTestLabelJsonAnonTest.php b/core/modules/rest/tests/src/Functional/EntityResource/EntityTestLabel/EntityTestLabelJsonAnonTest.php new file mode 100644 index 0000000000000000000000000000000000000000..10c4ec498bdaf65c68455435caf4a9d8a2fca3a5 --- /dev/null +++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityTestLabel/EntityTestLabelJsonAnonTest.php @@ -0,0 +1,24 @@ +grantPermissionsToTestedRole(['view test entity']); + break; + case 'POST': + $this->grantPermissionsToTestedRole([ + 'administer entity_test content', + 'administer entity_test_with_bundle content', + 'create entity_test entity_test_with_bundle entities', + ]); + break; + case 'PATCH': + case 'DELETE': + $this->grantPermissionsToTestedRole(['administer entity_test content']); + break; + } + } + + /** + * {@inheritdoc} + */ + protected function createEntity() { + $entity_test_label = EntityTestLabel::create([ + 'name' => 'label_llama', + ]); + $entity_test_label->setOwnerId(0); + $entity_test_label->save(); + return $entity_test_label; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedNormalizedEntity() { + $author = User::load(0); + $normalization = [ + 'uuid' => [ + [ + 'value' => $this->entity->uuid(), + ], + ], + 'id' => [ + [ + 'value' => (int) $this->entity->id(), + ], + ], + 'langcode' => [ + [ + 'value' => 'en', + ], + ], + 'type' => [ + [ + 'value' => 'entity_test_label', + ], + ], + 'name' => [ + [ + 'value' => 'label_llama', + ], + ], + 'created' => [ + [ + 'value' => (int) $this->entity->get('created')->value, + ], + ], + 'user_id' => [ + [ + 'target_id' => (int) $author->id(), + 'target_type' => 'user', + 'target_uuid' => $author->uuid(), + 'url' => $author->toUrl()->toString(), + ], + ], + ]; + + return $normalization; + } + + /** + * {@inheritdoc} + */ + protected function getNormalizedPostEntity() { + return [ + 'type' => 'entity_test_label', + 'name' => [ + [ + 'value' => 'label_llama', + ], + ], + ]; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedCacheContexts() { + return ['user.permissions']; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedUnauthorizedAccessMessage($method) { + if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) { + return parent::getExpectedUnauthorizedAccessMessage($method); + } + + switch ($method) { + case 'GET': + return "The 'view test entity' permission is required."; + case 'POST': + return "The following permissions are required: 'administer entity_test content' OR 'administer entity_test_with_bundle content' OR 'create entity_test_label entity_test_with_bundle entities'."; + case 'PATCH': + case 'DELETE': + return "The 'administer entity_test content' permission is required."; + default: + return parent::getExpectedUnauthorizedAccessMessage($method); + } + } + +}