.../EntityResource/EntityResourceTestBase.php | 141 ++++++++++----------- 1 file changed, 69 insertions(+), 72 deletions(-) diff --git a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php index b12c4a1..421d666 100644 --- a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php +++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php @@ -89,52 +89,61 @@ public function setUp() { abstract protected function getExpectedNormalizedEntity(); public function testGet() { + // The URL and Guzzle request options that will be used in this test. The + // request options will be modified/expanded throughout this test: + // - to first test all mistakes a developer might make, and assert that the + // error responses provide a good DX + // - to eventually result in a well-formed request that succeeds. + $url = $this->getUrl(); + $request_options = []; + // @todo test what happens before provisioning. Edge case: node. $this->setUpAuthorization('GET'); - - // Provision REST resource. $this->provisionEntityResource(); - /** @var \Psr\Http\Message\ResponseInterface $response */ $has_canonical_url = $this->entity->hasLinkTemplate('canonical'); - $url = $has_canonical_url ? $this->entity->toUrl() : Url::fromUri('base:entity/' . static::$entityType . '/' . $this->entity->id()); - // Requesting without the appropriate ?_format query argument. - try { - $response = $this->httpClient->get($url->toString(), $this->getAuthenticationRequestOptions()); - } catch (ClientException $e) { - $response = $e->getResponse(); - } - // When the anonymous user accesses a canonical (HTML) route, we won't get a - // 406, but a 200, and that is appropriate when no format is specified. - if ($has_canonical_url && !$this->account) { + // DX: 406 when ?_format is missing, except when requesting a canonical HTML + // route. + $response = $this->request('GET', $url, $request_options); + if ($has_canonical_url && !static::$auth) { $this->assertSame(200, $response->getStatusCode()); } else { $this->assert406Response($response); } + $url->setOption('query', ['_format' => static::$format]); - // Verify that the entity exists: use a HEAD request. - $response = $this->httpClient->head($url->toString(), $this->getAuthenticationRequestOptions()); - $this->assertSame(200, $response->getStatusCode()); + + // DX: forgetting authentication: authentication provider-specific error + // response. + if (static::$auth) { + $response = $this->request('GET', $url, $request_options); + $this->verifyResponseWhenMissingAuthentication($response); + } + + + $request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions()); + + + // 200 for well-formed HEAD request. + $response = $this->request('HEAD', $url, $request_options); + $this->assertResourceResponse(200, '', $response); if (!$this->account) { $this->assertSame(['MISS'], $response->getHeader('X-Drupal-Cache')); } else { $this->assertFalse($response->hasHeader('X-Drupal-Cache')); } - $this->assertSame('', (string)$response->getBody()); $head_headers = $response->getHeaders(); - // Now do a GET request. And because of the preceding HEAD request, this - // should be a Page Cache hit. - $response = $this->httpClient->get($url->toString(), $this->getAuthenticationRequestOptions()); - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame([static::$mimeType], $response->getHeader('Content-Type')); - if (!$this->account) { + // 200 for well-formed GET request. Page Cache hit because of HEAD request. + $response = $this->request('GET', $url, $request_options); + $this->assertResourceResponse(200, FALSE, $response); + if (!static::$auth) { $this->assertSame(['HIT'], $response->getHeader('X-Drupal-Cache')); } else { @@ -160,59 +169,47 @@ public function testGet() { } $this->assertSame($get_headers, $head_headers); - if ($this->account) { - // Try to read the entity without the necessary authentication. - try { - $this->httpClient->get($url->toString()); - $this->fail('No error response for missing authentication!'); - } - catch (ClientException $e) { - $this->verifyResponseWhenMissingAuthentication($e->getResponse()); - } - } - // Try to read the entity in an unsupported format. - try { - $url->setOption('query', ['_format' => 'non_existing_format']); - $this->httpClient->get($url->toString(), $this->getAuthenticationRequestOptions()); - $this->fail('No 406 response received.'); - } - catch (ClientException $e) { - $response = $e->getResponse(); - $this->assert406Response($response); - // @todo this works fine locally, but on testbot it comes back with 'text/plain; charset=UTF-8'. WTF. + $url->setOption('query', ['_format' => 'non_existing_format']); + + + // DX: 406 when requesting unsupported format. + $response = $this->request('GET', $url, $request_options); + $this->assert406Response($response); + // @todo this works fine locally, but on testbot it comes back with 'text/plain; charset=UTF-8'. WTF. // $this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type')); - } - // Repeat the same request, but this time with the format's MIME type in the - // Accept header. This time we should get a response with the expected error - // MIME type. - try { - $options = $this->getAuthenticationRequestOptions(); - $options['headers']['Accept'] = static::$mimeType; - $url->setOption('query', ['_format' => 'non_existing_format']); - $this->httpClient->get($url->toString(), $options); - $this->fail('No 406 response received.'); - } - catch (ClientException $e) { - $response = $e->getResponse(); - $this->assert406Response($response); - $this->assertSame([static::$expectedErrorMimeType], $response->getHeader('Content-Type')); - } - // Try to read an entity that does not exist. - $non_existing_entity_url = Url::fromRoute('rest.entity.' . static::$entityType . '.GET.' . static::$format); - $non_existing_entity_url->setRouteParameter(static::$entityType, 987654321); - $non_existing_entity_url->setOption('query', ['_format' => static::$format]); - try { - $this->httpClient->get($non_existing_entity_url->toString()); - $this->fail('No 404 response received.'); - } - catch (ClientException $e) { - $path = str_replace('987654321', '{' . static::$entityType . '}', $non_existing_entity_url->setAbsolute()->setOptions(['base_url' => '', 'query' => []])->toString()); - $message = 'The "' . static::$entityType . '" parameter was not converted for the path "' . $path . '" (route name: "rest.entity.' . static::$entityType . '.GET.' . static::$format . '")'; - $this->assertResourceErrorResponse(404, $message, $e->getResponse()); - } + $request_options[RequestOptions::HEADERS]['Accept'] = static::$mimeType; + + + // DX: 406 when requesting unsupported format but specifying Accept header. + $response = $this->request('GET', $url, $request_options); + $this->assert406Response($response); + $this->assertSame([static::$expectedErrorMimeType], $response->getHeader('Content-Type')); + + + $url = Url::fromRoute('rest.entity.' . static::$entityType . '.GET.' . static::$format); + $url->setRouteParameter(static::$entityType, 987654321); + $url->setOption('query', ['_format' => static::$format]); + + + // DX: 404 when GETting non-existing entity. + $response = $this->request('GET', $url, $request_options); + $path = str_replace('987654321', '{' . static::$entityType . '}', $url->setAbsolute()->setOptions(['base_url' => '', 'query' => []])->toString()); + $message = 'The "' . static::$entityType . '" parameter was not converted for the path "' . $path . '" (route name: "rest.entity.' . static::$entityType . '.GET.' . static::$format . '")'; + $this->assertResourceErrorResponse(404, $message, $response); + } + + /** + * Gets an entity resource's GET/PATCH/DELETE URL. + * + * @return \Drupal\Core\Url + * The URL to GET/PATCH/DELETE. + */ + protected function getUrl() { + $has_canonical_url = $this->entity->hasLinkTemplate('canonical'); + return $has_canonical_url ? $this->entity->toUrl() : Url::fromUri('base:entity/' . static::$entityType . '/' . $this->entity->id()); } public function testPost() {