Update core 8.3.0
This commit is contained in:
parent
da7a7918f8
commit
cd7a898e66
6144 changed files with 132297 additions and 87747 deletions
|
@ -10,24 +10,6 @@ use Drupal\Core\Session\AccountInterface;
|
|||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
|
||||
/**
|
||||
* Implements hook_rest_type_uri_alter().
|
||||
*/
|
||||
function rest_test_rest_type_uri_alter(&$uri, $context = array()) {
|
||||
if (!empty($context['rest_test'])) {
|
||||
$uri = 'rest_test_type';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_rest_relation_uri_alter().
|
||||
*/
|
||||
function rest_test_rest_relation_uri_alter(&$uri, $context = array()) {
|
||||
if (!empty($context['rest_test'])) {
|
||||
$uri = 'rest_test_relation';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_field_access().
|
||||
*
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
services:
|
||||
rest_test.authentication.test_auth:
|
||||
class: Drupal\rest_test\Authentication\Provider\TestAuth
|
||||
tags:
|
||||
- { name: authentication_provider, provider_id: 'rest_test_auth' }
|
||||
rest_test.authentication.test_auth_global:
|
||||
class: Drupal\rest_test\Authentication\Provider\TestAuthGlobal
|
||||
tags:
|
||||
- { name: authentication_provider, provider_id: 'rest_test_auth_global', global: TRUE }
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\rest_test\Authentication\Provider;
|
||||
|
||||
use Drupal\Core\Authentication\AuthenticationProviderInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Authentication provider for testing purposes.
|
||||
*/
|
||||
class TestAuth implements AuthenticationProviderInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applies(Request $request) {
|
||||
return $request->headers->has('REST-test-auth');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate(Request $request) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\rest_test\Authentication\Provider;
|
||||
|
||||
use Drupal\Core\Authentication\AuthenticationProviderInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Global authentication provider for testing purposes.
|
||||
*/
|
||||
class TestAuthGlobal implements AuthenticationProviderInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applies(Request $request) {
|
||||
return $request->headers->has('REST-test-auth-global');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate(Request $request) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
|
@ -53,10 +53,8 @@ trait CookieResourceTestTrait {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initAuthentication() {
|
||||
// @todo Remove hardcoded use of the 'json' format, and use static::$format
|
||||
// + static::$mimeType instead in https://www.drupal.org/node/2820888.
|
||||
$user_login_url = Url::fromRoute('user.login.http')
|
||||
->setRouteParameter('_format', 'json');
|
||||
->setRouteParameter('_format', static::$format);
|
||||
|
||||
$request_body = [
|
||||
'name' => $this->account->name->value,
|
||||
|
@ -64,7 +62,9 @@ trait CookieResourceTestTrait {
|
|||
];
|
||||
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($request_body, 'json');
|
||||
$request_options[RequestOptions::HEADERS]['Accept'] = 'application/json';
|
||||
$request_options[RequestOptions::HEADERS] = [
|
||||
'Content-Type' => static::$mimeType,
|
||||
];
|
||||
$response = $this->request('POST', $user_login_url, $request_options);
|
||||
|
||||
// Parse and store the session cookie.
|
||||
|
@ -92,7 +92,10 @@ trait CookieResourceTestTrait {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected function assertResponseWhenMissingAuthentication(ResponseInterface $response) {
|
||||
$this->assertResourceErrorResponse(403, '', $response);
|
||||
// Requests needing cookie authentication but missing it results in a 403
|
||||
// response. The cookie authentication mechanism sets no response message.
|
||||
// @todo https://www.drupal.org/node/2847623
|
||||
$this->assertResourceErrorResponse(403, FALSE, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Action;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ActionJsonAnonTest extends ActionResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Action;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ActionJsonBasicAuthTest extends ActionResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Action;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ActionJsonCookieTest extends ActionResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Action;
|
||||
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
use Drupal\system\Entity\Action;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
||||
abstract class ActionResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['user'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'action';
|
||||
|
||||
/**
|
||||
* @var \Drupal\system\ActionConfigEntityInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
$this->grantPermissionsToTestedRole(['administer actions']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
$action = Action::create([
|
||||
'id' => 'user_add_role_action.' . RoleInterface::ANONYMOUS_ID,
|
||||
'type' => 'user',
|
||||
'label' => t('Add the anonymous role to the selected users'),
|
||||
'configuration' => [
|
||||
'rid' => RoleInterface::ANONYMOUS_ID,
|
||||
],
|
||||
'plugin' => 'user_add_role_action',
|
||||
]);
|
||||
$action->save();
|
||||
|
||||
return $action;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'configuration' => [
|
||||
'rid' => 'anonymous',
|
||||
],
|
||||
'dependencies' => [
|
||||
'config' => ['user.role.anonymous'],
|
||||
'module' => ['user'],
|
||||
],
|
||||
'id' => 'user_add_role_action.anonymous',
|
||||
'label' => 'Add the anonymous role to the selected users',
|
||||
'langcode' => 'en',
|
||||
'plugin' => 'user_add_role_action',
|
||||
'status' => TRUE,
|
||||
'type' => 'user',
|
||||
'uuid' => $this->entity->uuid(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
return [
|
||||
'user.permissions',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
}
|
||||
|
||||
}
|
|
@ -21,9 +21,4 @@ class BlockJsonAnonTest extends BlockResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace Drupal\Tests\rest\Functional\EntityResource\Block;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\JsonBasicAuthWorkaroundFor2805281Trait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
|
@ -27,19 +26,9 @@ class BlockJsonBasicAuthTest extends BlockResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use JsonBasicAuthWorkaroundFor2805281Trait {
|
||||
JsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,11 +21,6 @@ class BlockJsonCookieTest extends BlockResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -113,7 +113,7 @@ abstract class BlockResourceTestBase extends EntityResourceTestBase {
|
|||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
// @see ::createEntity()
|
||||
return [];
|
||||
return ['url.site'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -122,9 +122,25 @@ abstract class BlockResourceTestBase extends EntityResourceTestBase {
|
|||
protected function getExpectedCacheTags() {
|
||||
// Because the 'user.permissions' cache context is missing, the cache tag
|
||||
// for the anonymous user role is never added automatically.
|
||||
return array_filter(parent::getExpectedCacheTags(), function ($tag) {
|
||||
return array_values(array_filter(parent::getExpectedCacheTags(), function ($tag) {
|
||||
return $tag !== 'config:user.role.anonymous';
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
return "You are not authorized to view this block entity.";
|
||||
default:
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,11 +21,6 @@ class CommentJsonAnonTest extends CommentResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace Drupal\Tests\rest\Functional\EntityResource\Comment;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\JsonBasicAuthWorkaroundFor2805281Trait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
|
@ -27,19 +26,9 @@ class CommentJsonBasicAuthTest extends CommentResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use JsonBasicAuthWorkaroundFor2805281Trait {
|
||||
JsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,11 +21,6 @@ class CommentJsonCookieTest extends CommentResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -28,6 +28,7 @@ abstract class CommentResourceTestBase extends EntityResourceTestBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $patchProtectedFieldNames = [
|
||||
'status',
|
||||
'pid',
|
||||
'entity_id',
|
||||
'uid',
|
||||
|
@ -35,7 +36,6 @@ abstract class CommentResourceTestBase extends EntityResourceTestBase {
|
|||
'homepage',
|
||||
'created',
|
||||
'changed',
|
||||
'status',
|
||||
'thread',
|
||||
'entity_type',
|
||||
'field_name',
|
||||
|
@ -87,10 +87,10 @@ abstract class CommentResourceTestBase extends EntityResourceTestBase {
|
|||
$this->addDefaultCommentField('entity_test', 'bar', 'comment');
|
||||
|
||||
// Create a "Camelids" test entity that the comment will be assigned to.
|
||||
$commented_entity = EntityTest::create(array(
|
||||
$commented_entity = EntityTest::create([
|
||||
'name' => 'Camelids',
|
||||
'type' => 'bar',
|
||||
));
|
||||
]);
|
||||
$commented_entity->save();
|
||||
|
||||
// Create a "Llama" comment.
|
||||
|
@ -144,17 +144,17 @@ abstract class CommentResourceTestBase extends EntityResourceTestBase {
|
|||
],
|
||||
'status' => [
|
||||
[
|
||||
'value' => 1,
|
||||
'value' => TRUE,
|
||||
],
|
||||
],
|
||||
'created' => [
|
||||
[
|
||||
'value' => '123456789',
|
||||
'value' => 123456789,
|
||||
],
|
||||
],
|
||||
'changed' => [
|
||||
[
|
||||
'value' => '123456789',
|
||||
'value' => $this->entity->getChangedTime(),
|
||||
],
|
||||
],
|
||||
'default_langcode' => [
|
||||
|
@ -164,7 +164,7 @@ abstract class CommentResourceTestBase extends EntityResourceTestBase {
|
|||
],
|
||||
'uid' => [
|
||||
[
|
||||
'target_id' => $author->id(),
|
||||
'target_id' => (int) $author->id(),
|
||||
'target_type' => 'user',
|
||||
'target_uuid' => $author->uuid(),
|
||||
'url' => base_path() . 'user/' . $author->id(),
|
||||
|
@ -178,7 +178,7 @@ abstract class CommentResourceTestBase extends EntityResourceTestBase {
|
|||
],
|
||||
'entity_id' => [
|
||||
[
|
||||
'target_id' => '1',
|
||||
'target_id' => 1,
|
||||
'target_type' => 'entity_test',
|
||||
'target_uuid' => EntityTest::load(1)->uuid(),
|
||||
'url' => base_path() . 'entity_test/1',
|
||||
|
@ -278,8 +278,10 @@ abstract class CommentResourceTestBase extends EntityResourceTestBase {
|
|||
// DX: 422 when missing 'entity_type' field.
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode(array_diff_key($this->getNormalizedPostEntity(), ['entity_type' => TRUE]), static::$format);
|
||||
$response = $this->request('POST', $url, $request_options);
|
||||
// @todo Uncomment, remove next line in https://www.drupal.org/node/2820364.
|
||||
$this->assertResourceErrorResponse(500, 'A fatal error occurred: Internal Server Error', $response);
|
||||
// @todo Uncomment, remove next 3 lines in https://www.drupal.org/node/2820364.
|
||||
$this->assertSame(500, $response->getStatusCode());
|
||||
$this->assertSame(['application/json'], $response->getHeader('Content-Type'));
|
||||
$this->assertSame('{"message":"A fatal error occurred: Internal Server Error"}', (string) $response->getBody());
|
||||
//$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nentity_type: This value should not be null.\n", $response);
|
||||
|
||||
// DX: 422 when missing 'entity_id' field.
|
||||
|
@ -301,9 +303,29 @@ abstract class CommentResourceTestBase extends EntityResourceTestBase {
|
|||
// DX: 422 when missing 'entity_type' field.
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode(array_diff_key($this->getNormalizedPostEntity(), ['field_name' => TRUE]), static::$format);
|
||||
$response = $this->request('POST', $url, $request_options);
|
||||
// @todo Uncomment, remove next line in https://www.drupal.org/node/2820364.
|
||||
$this->assertResourceErrorResponse(500, 'A fatal error occurred: Field is unknown.', $response);
|
||||
// @todo Uncomment, remove next 3 lines in https://www.drupal.org/node/2820364.
|
||||
$this->assertSame(500, $response->getStatusCode());
|
||||
$this->assertSame(['application/json'], $response->getHeader('Content-Type'));
|
||||
$this->assertSame('{"message":"A fatal error occurred: Field is unknown."}', (string) $response->getBody());
|
||||
//$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nfield_name: This value should not be null.\n", $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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 'access comments' permission is required and the comment must be published.";
|
||||
case 'POST';
|
||||
return "The 'post comments' permission is required.";
|
||||
default:
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\CommentType;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class CommentTypeJsonAnonTest extends CommentTypeResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\CommentType;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class CommentTypeJsonBasicAuthTest extends CommentTypeResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\CommentType;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class CommentTypeJsonCookieTest extends CommentTypeResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\CommentType;
|
||||
|
||||
use Drupal\comment\Entity\CommentType;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
|
||||
/**
|
||||
* ResourceTestBase for CommentType entity.
|
||||
*/
|
||||
abstract class CommentTypeResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['node', 'comment'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'comment_type';
|
||||
|
||||
/**
|
||||
* The CommentType entity.
|
||||
*
|
||||
* @var \Drupal\comment\CommentTypeInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
$this->grantPermissionsToTestedRole(['administer comment types']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
// Create a "Camelids" comment type.
|
||||
$camelids = CommentType::create([
|
||||
'id' => 'camelids',
|
||||
'label' => 'Camelids',
|
||||
'description' => 'Camelids are large, strictly herbivorous animals with slender necks and long legs.',
|
||||
'target_entity_type_id' => 'node',
|
||||
]);
|
||||
|
||||
$camelids->save();
|
||||
|
||||
return $camelids;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'dependencies' => [],
|
||||
'description' => 'Camelids are large, strictly herbivorous animals with slender necks and long legs.',
|
||||
'id' => 'camelids',
|
||||
'label' => 'Camelids',
|
||||
'langcode' => 'en',
|
||||
'status' => TRUE,
|
||||
'target_entity_type_id' => 'node',
|
||||
'uuid' => $this->entity->uuid(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
}
|
||||
|
||||
}
|
|
@ -21,9 +21,4 @@ class ConfigTestJsonAnonTest extends ConfigTestResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace Drupal\Tests\rest\Functional\EntityResource\ConfigTest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\JsonBasicAuthWorkaroundFor2805281Trait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
|
@ -27,19 +26,9 @@ class ConfigTestJsonBasicAuthTest extends ConfigTestResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use JsonBasicAuthWorkaroundFor2805281Trait {
|
||||
JsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,11 +21,6 @@ class ConfigTestJsonCookieTest extends ConfigTestResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ConfigurableLanguage;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ConfigurableLanguageJsonAnonTest extends ConfigurableLanguageResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ConfigurableLanguage;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ConfigurableLanguageJsonBasicAuthTest extends ConfigurableLanguageResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ConfigurableLanguage;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ConfigurableLanguageJsonCookieTest extends ConfigurableLanguageResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ConfigurableLanguage;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
abstract class ConfigurableLanguageResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'configurable_language';
|
||||
|
||||
/**
|
||||
* @var \Drupal\language\ConfigurableLanguageInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
$this->grantPermissionsToTestedRole(['administer languages']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
$configurable_language = ConfigurableLanguage::create([
|
||||
'id' => 'll',
|
||||
'label' => 'Llama Language',
|
||||
]);
|
||||
$configurable_language->save();
|
||||
|
||||
return $configurable_language;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'dependencies' => [],
|
||||
'direction' => 'ltr',
|
||||
'id' => 'll',
|
||||
'label' => 'Llama Language',
|
||||
'langcode' => 'en',
|
||||
'locked' => FALSE,
|
||||
'status' => TRUE,
|
||||
'uuid' => $this->entity->uuid(),
|
||||
'weight' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
return Cache::mergeContexts(parent::getExpectedCacheContexts(), ['languages:language_interface']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
}
|
||||
|
||||
}
|
|
@ -5,7 +5,6 @@ namespace Drupal\Tests\rest\Functional\EntityResource;
|
|||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
use Drupal\Core\Entity\EntityChangedInterface;
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
|
@ -43,10 +42,9 @@ use Psr\Http\Message\ResponseInterface;
|
|||
* (permissions or perhaps custom access control handling, such as node
|
||||
* grants), plus
|
||||
* 2. a concrete subclass extending the abstract entity type-specific subclass
|
||||
* that specifies the exact @code $format @endcode, @code $mimeType @endcode,
|
||||
* @code $expectedErrorMimeType @endcode and @code $auth @endcode for this
|
||||
* concrete test. Usually that's all that's necessary: most concrete
|
||||
* subclasses will be very thin.
|
||||
* that specifies the exact @code $format @endcode, @code $mimeType @endcode
|
||||
* and @code $auth @endcode for this concrete test. Usually that's all that's
|
||||
* necessary: most concrete subclasses will be very thin.
|
||||
*
|
||||
* For every of these concrete subclasses, a comprehensive test scenario will
|
||||
* run per HTTP method:
|
||||
|
@ -111,11 +109,6 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
*/
|
||||
protected static $secondCreatedEntityId = 3;
|
||||
|
||||
/**
|
||||
* @var \GuzzleHttp\ClientInterface
|
||||
*/
|
||||
protected $httpClient;
|
||||
|
||||
/**
|
||||
* The main entity used for testing.
|
||||
*
|
||||
|
@ -138,13 +131,13 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
public static $modules = ['rest_test', 'text'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Provides an entity resource.
|
||||
*/
|
||||
protected function provisionEntityResource() {
|
||||
// It's possible to not have any authentication providers enabled, when
|
||||
// testing public (anonymous) usage of a REST resource.
|
||||
$auth = isset(static::$auth) ? [static::$auth] : [];
|
||||
$this->provisionResource('entity.' . static::$entityTypeId, [static::$format], $auth);
|
||||
$this->provisionResource([static::$format], $auth);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -153,14 +146,13 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Calculate REST Resource config entity ID.
|
||||
static::$resourceConfigId = 'entity.' . static::$entityTypeId;
|
||||
|
||||
$this->serializer = $this->container->get('serializer');
|
||||
$this->entityStorage = $this->container->get('entity_type.manager')
|
||||
->getStorage(static::$entityTypeId);
|
||||
|
||||
// Set up a HTTP client that accepts relative URLs.
|
||||
$this->httpClient = $this->container->get('http_client_factory')
|
||||
->fromOptions(['base_uri' => $this->baseUrl]);
|
||||
|
||||
// Create an entity.
|
||||
$this->entity = $this->createEntity();
|
||||
|
||||
|
@ -187,18 +179,8 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
|
||||
// Set a default value on the field.
|
||||
$this->entity->set('field_rest_test', ['value' => 'All the faith he had had had had no effect on the outcome of his life.']);
|
||||
// @todo Remove in this if-test in https://www.drupal.org/node/2808335.
|
||||
if ($this->entity instanceof EntityChangedInterface) {
|
||||
$changed = $this->entity->getChangedTime();
|
||||
$this->entity->setChangedTime(42);
|
||||
$this->entity->save();
|
||||
$this->entity->setChangedTime($changed);
|
||||
}
|
||||
$this->entity->save();
|
||||
}
|
||||
|
||||
// @todo Remove this in https://www.drupal.org/node/2815845.
|
||||
drupal_flush_all_caches();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -241,6 +223,43 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
return $this->getNormalizedPostEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
|
||||
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
|
||||
return $this->getExpectedBCUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
$permission = $this->entity->getEntityType()->getAdminPermission();
|
||||
if ($permission !== FALSE) {
|
||||
return "The '{$permission}' permission is required.";
|
||||
}
|
||||
|
||||
$http_method_to_entity_operation = [
|
||||
'GET' => 'view',
|
||||
'POST' => 'create',
|
||||
'PATCH' => 'update',
|
||||
'DELETE' => 'delete',
|
||||
];
|
||||
$operation = $http_method_to_entity_operation[$method];
|
||||
$message = sprintf('You are not authorized to %s this %s entity', $operation, $this->entity->getEntityTypeId());
|
||||
|
||||
if ($this->entity->bundle() !== $this->entity->getEntityTypeId()) {
|
||||
$message .= ' of bundle ' . $this->entity->bundle();
|
||||
}
|
||||
|
||||
return "$message.";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedBcUnauthorizedAccessMessage($method) {
|
||||
return "The 'restful " . strtolower($method) . " entity:" . $this->entity->getEntityTypeId() . "' permission is required.";
|
||||
}
|
||||
|
||||
/**
|
||||
* The expected cache tags for the GET/HEAD response of the test entity.
|
||||
*
|
||||
|
@ -255,6 +274,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
if (!static::$auth) {
|
||||
$expected_cache_tags[] = 'config:user.role.anonymous';
|
||||
}
|
||||
$expected_cache_tags[] = 'http_response';
|
||||
return Cache::mergeTags($expected_cache_tags, $this->entity->getCacheTags());
|
||||
}
|
||||
|
||||
|
@ -267,6 +287,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
return [
|
||||
'url.site',
|
||||
'user.permissions',
|
||||
];
|
||||
}
|
||||
|
@ -301,7 +322,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
// response because ?_format query string is present.
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
if ($has_canonical_url) {
|
||||
$this->assertResourceErrorResponse(403, '', $response);
|
||||
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('GET'), $response);
|
||||
}
|
||||
else {
|
||||
$this->assertResourceErrorResponse(404, 'No route found for "GET ' . str_replace($this->baseUrl, '', $this->getUrl()->setAbsolute()->toString()) . '"', $response);
|
||||
|
@ -335,13 +356,28 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
$this->assertResponseWhenMissingAuthentication($response);
|
||||
}
|
||||
|
||||
$request_options[RequestOptions::HEADERS]['REST-test-auth'] = '1';
|
||||
|
||||
// DX: 403 when attempting to use unallowed authentication provider.
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(403, 'The used authentication method is not allowed on this route.', $response);
|
||||
|
||||
unset($request_options[RequestOptions::HEADERS]['REST-test-auth']);
|
||||
$request_options[RequestOptions::HEADERS]['REST-test-auth-global'] = '1';
|
||||
|
||||
// DX: 403 when attempting to use unallowed global authentication provider.
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(403, 'The used authentication method is not allowed on this route.', $response);
|
||||
|
||||
unset($request_options[RequestOptions::HEADERS]['REST-test-auth-global']);
|
||||
$request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions('GET'));
|
||||
|
||||
|
||||
// DX: 403 when unauthorized.
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
// @todo Update the message in https://www.drupal.org/node/2808233.
|
||||
$this->assertResourceErrorResponse(403, '', $response);
|
||||
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('GET'), $response);
|
||||
$this->assertArrayNotHasKey('Link', $response->getHeaders());
|
||||
|
||||
|
||||
|
||||
$this->setUpAuthorization('GET');
|
||||
|
@ -371,15 +407,38 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
$this->assertEquals($this->getExpectedCacheTags(), empty($cache_tags_header_value) ? [] : explode(' ', $cache_tags_header_value));
|
||||
$cache_contexts_header_value = $response->getHeader('X-Drupal-Cache-Contexts')[0];
|
||||
$this->assertEquals($this->getExpectedCacheContexts(), empty($cache_contexts_header_value) ? [] : explode(' ', $cache_contexts_header_value));
|
||||
// Comparing the exact serialization is pointless, because the order of
|
||||
// fields does not matter (at least not yet). That's why we only compare the
|
||||
// normalized entity with the decoded response: it's comparing PHP arrays
|
||||
// instead of strings.
|
||||
$this->assertEquals($this->getExpectedNormalizedEntity(), $this->serializer->decode((string) $response->getBody(), static::$format));
|
||||
// Sort the serialization data first so we can do an identical comparison
|
||||
// for the keys with the array order the same (it needs to match with
|
||||
// identical comparison).
|
||||
$expected = $this->getExpectedNormalizedEntity();
|
||||
ksort($expected);
|
||||
$actual = $this->serializer->decode((string) $response->getBody(), static::$format);
|
||||
ksort($actual);
|
||||
$this->assertSame($expected, $actual);
|
||||
|
||||
// Not only assert the normalization, also assert deserialization of the
|
||||
// response results in the expected object.
|
||||
$unserialized = $this->serializer->deserialize((string) $response->getBody(), get_class($this->entity), static::$format);
|
||||
$this->assertSame($unserialized->uuid(), $this->entity->uuid());
|
||||
// Finally, assert that the expected 'Link' headers are present.
|
||||
if ($this->entity->getEntityType()->getLinkTemplates()) {
|
||||
$this->assertArrayHasKey('Link', $response->getHeaders());
|
||||
$link_relation_type_manager = $this->container->get('plugin.manager.link_relation_type');
|
||||
$expected_link_relation_headers = array_map(function ($rel) use ($link_relation_type_manager) {
|
||||
$definition = $link_relation_type_manager->getDefinition($rel, FALSE);
|
||||
return (!empty($definition['uri']))
|
||||
? $definition['uri']
|
||||
: $rel;
|
||||
}, array_keys($this->entity->getEntityType()->getLinkTemplates()));
|
||||
$parse_rel_from_link_header = function ($value) use ($link_relation_type_manager) {
|
||||
$matches = [];
|
||||
if (preg_match('/rel="([^"]+)"/', $value, $matches) === 1) {
|
||||
return $matches[1];
|
||||
}
|
||||
return FALSE;
|
||||
};
|
||||
$this->assertSame($expected_link_relation_headers, array_map($parse_rel_from_link_header, $response->getHeader('Link')));
|
||||
}
|
||||
$get_headers = $response->getHeaders();
|
||||
|
||||
// Verify that the GET and HEAD responses are the same. The only difference
|
||||
|
@ -394,16 +453,42 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
}
|
||||
$this->assertSame($get_headers, $head_headers);
|
||||
|
||||
// Only run this for fieldable entities. It doesn't make sense for config
|
||||
// entities as config values are already casted. They also run through the
|
||||
// ConfigEntityNormalizer, which doesn't deal with fields individually.
|
||||
if ($this->entity instanceof FieldableEntityInterface) {
|
||||
$this->config('serialization.settings')->set('bc_primitives_as_strings', TRUE)->save(TRUE);
|
||||
// Rebuild the container so new config is reflected in the removal of the
|
||||
// PrimitiveDataNormalizer.
|
||||
$this->rebuildAll();
|
||||
|
||||
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
|
||||
|
||||
// Again do an identical comparison, but this time transform the expected
|
||||
// normalized entity's values to strings. This ensures the BC layer for
|
||||
// bc_primitives_as_strings works as expected.
|
||||
$expected = $this->getExpectedNormalizedEntity();
|
||||
// Config entities are not affected.
|
||||
// @see \Drupal\serialization\Normalizer\ConfigEntityNormalizer::normalize()
|
||||
$expected = static::castToString($expected);
|
||||
ksort($expected);
|
||||
$actual = $this->serializer->decode((string) $response->getBody(), static::$format);
|
||||
ksort($actual);
|
||||
$this->assertSame($expected, $actual);
|
||||
}
|
||||
|
||||
|
||||
// BC: rest_update_8203().
|
||||
$this->config('rest.settings')->set('bc_entity_resource_permissions', TRUE)->save(TRUE);
|
||||
// @todo Remove this in https://www.drupal.org/node/2815845.
|
||||
drupal_flush_all_caches();
|
||||
$this->refreshTestStateAfterRestConfigChange();
|
||||
|
||||
|
||||
// DX: 403 when unauthorized.
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
// @todo Update the message in https://www.drupal.org/node/2808233.
|
||||
$this->assertResourceErrorResponse(403, '', $response);
|
||||
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('GET'), $response);
|
||||
|
||||
|
||||
$this->grantPermissionsToTestedRole(['restful get entity:' . static::$entityTypeId]);
|
||||
|
@ -414,13 +499,39 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
|
||||
|
||||
$this->resourceConfigStorage->load(static::$resourceConfigId)->disable()->save();
|
||||
$this->refreshTestStateAfterRestConfigChange();
|
||||
|
||||
|
||||
// DX: upon disabling a resource, it's immediately no longer available.
|
||||
$this->assertResourceNotAvailable($url, $request_options);
|
||||
|
||||
|
||||
$this->resourceConfigStorage->load(static::$resourceConfigId)->enable()->save();
|
||||
$this->refreshTestStateAfterRestConfigChange();
|
||||
|
||||
|
||||
// DX: upon re-enabling a resource, immediate 200.
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
|
||||
|
||||
$this->resourceConfigStorage->load(static::$resourceConfigId)->delete();
|
||||
$this->refreshTestStateAfterRestConfigChange();
|
||||
|
||||
|
||||
// DX: upon deleting a resource, it's immediately no longer available.
|
||||
$this->assertResourceNotAvailable($url, $request_options);
|
||||
|
||||
|
||||
$this->provisionEntityResource();
|
||||
$url->setOption('query', ['_format' => 'non_existing_format']);
|
||||
|
||||
|
||||
// DX: 406 when requesting unsupported format.
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$this->assert406Response($response);
|
||||
$this->assertNotSame([static::$expectedErrorMimeType], $response->getHeader('Content-Type'));
|
||||
$this->assertNotSame([static::$mimeType], $response->getHeader('Content-Type'));
|
||||
|
||||
|
||||
$request_options[RequestOptions::HEADERS]['Accept'] = static::$mimeType;
|
||||
|
@ -430,7 +541,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
// @todo Update in https://www.drupal.org/node/2825347.
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$this->assert406Response($response);
|
||||
$this->assertSame([static::$expectedErrorMimeType], $response->getHeader('Content-Type'));
|
||||
$this->assertSame(['application/json'], $response->getHeader('Content-Type'));
|
||||
|
||||
|
||||
$url = Url::fromRoute('rest.entity.' . static::$entityTypeId . '.GET.' . static::$format);
|
||||
|
@ -445,6 +556,30 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
$this->assertResourceErrorResponse(404, $message, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a normalization: casts all non-string types to strings.
|
||||
*
|
||||
* @param array $normalization
|
||||
* A normalization to transform.
|
||||
*
|
||||
* @return array
|
||||
* The transformed normalization.
|
||||
*/
|
||||
protected static function castToString(array $normalization) {
|
||||
foreach ($normalization as $key => $value) {
|
||||
if (is_bool($value)) {
|
||||
$normalization[$key] = (string) (int) $value;
|
||||
}
|
||||
elseif (is_int($value) || is_float($value)) {
|
||||
$normalization[$key] = (string) $value;
|
||||
}
|
||||
elseif (is_array($value)) {
|
||||
$normalization[$key] = static::castToString($value);
|
||||
}
|
||||
}
|
||||
return $normalization;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a POST request for an entity, plus edge cases to ensure good DX.
|
||||
*/
|
||||
|
@ -463,8 +598,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
$parseable_valid_request_body = $this->serializer->encode($this->getNormalizedPostEntity(), static::$format);
|
||||
$parseable_valid_request_body_2 = $this->serializer->encode($this->getNormalizedPostEntity(), static::$format);
|
||||
$parseable_invalid_request_body = $this->serializer->encode($this->makeNormalizationInvalid($this->getNormalizedPostEntity()), static::$format);
|
||||
// @todo Change to ['uuid' => UUID] in https://www.drupal.org/node/2820743.
|
||||
$parseable_invalid_request_body_2 = $this->serializer->encode($this->getNormalizedPostEntity() + ['uuid' => [['value' => $this->randomMachineName(129)]]], static::$format);
|
||||
$parseable_invalid_request_body_2 = $this->serializer->encode($this->getNormalizedPostEntity() + ['uuid' => [$this->randomMachineName(129)]], static::$format);
|
||||
$parseable_invalid_request_body_3 = $this->serializer->encode($this->getNormalizedPostEntity() + ['field_rest_test' => [['value' => $this->randomString()]]], static::$format);
|
||||
|
||||
// The URL and Guzzle request options that will be used in this test. The
|
||||
|
@ -476,15 +610,11 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
$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]);
|
||||
|
@ -500,16 +630,12 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
$url->setOption('query', []);
|
||||
|
||||
|
||||
// DX: 415 when no Content-Type request header, but HTML if canonical route.
|
||||
// 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/html; 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/html; 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]);
|
||||
|
@ -533,12 +659,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
|
||||
// DX: 400 when unparseable request body.
|
||||
$response = $this->request('POST', $url, $request_options);
|
||||
// @todo Uncomment, remove next 3 in https://www.drupal.org/node/2813853.
|
||||
// $this->assertResourceErrorResponse(400, 'Syntax error', $response);
|
||||
$this->assertSame(400, $response->getStatusCode());
|
||||
$this->assertSame([static::$mimeType], $response->getHeader('Content-Type'));
|
||||
$this->assertSame($this->serializer->encode(['error' => 'Syntax error'], static::$format), (string) $response->getBody());
|
||||
|
||||
$this->assertResourceErrorResponse(400, 'Syntax error', $response);
|
||||
|
||||
|
||||
$request_options[RequestOptions::BODY] = $parseable_invalid_request_body;
|
||||
|
@ -557,8 +678,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
|
||||
// DX: 403 when unauthorized.
|
||||
$response = $this->request('POST', $url, $request_options);
|
||||
// @todo Update the message in https://www.drupal.org/node/2808233.
|
||||
$this->assertResourceErrorResponse(403, '', $response);
|
||||
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('POST'), $response);
|
||||
|
||||
|
||||
$this->setUpAuthorization('POST');
|
||||
|
@ -567,24 +687,19 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
// DX: 422 when invalid entity: multiple values sent for single-value field.
|
||||
$response = $this->request('POST', $url, $request_options);
|
||||
$label_field = $this->entity->getEntityType()->hasKey('label') ? $this->entity->getEntityType()->getKey('label') : static::$labelFieldName;
|
||||
$label_field_capitalized = ucfirst($label_field);
|
||||
// @todo Uncomment, remove next 3 in https://www.drupal.org/node/2813755.
|
||||
// $this->assertErrorResponse(422, "Unprocessable Entity: validation failed.\ntitle: <em class=\"placeholder\">Title</em>: this field cannot hold more than 1 values.\n", $response);
|
||||
$this->assertSame(422, $response->getStatusCode());
|
||||
$this->assertSame([static::$mimeType], $response->getHeader('Content-Type'));
|
||||
$this->assertSame($this->serializer->encode(['message' => "Unprocessable Entity: validation failed.\n$label_field: <em class=\"placeholder\">$label_field_capitalized</em>: this field cannot hold more than 1 values.\n"], static::$format), (string) $response->getBody());
|
||||
$label_field_capitalized = $this->entity->getFieldDefinition($label_field)->getLabel();
|
||||
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\n$label_field: $label_field_capitalized: this field cannot hold more than 1 values.\n", $response);
|
||||
|
||||
|
||||
$request_options[RequestOptions::BODY] = $parseable_invalid_request_body_2;
|
||||
|
||||
|
||||
// DX: 422 when invalid entity: UUID field too long.
|
||||
$response = $this->request('POST', $url, $request_options);
|
||||
// @todo Uncomment, remove next 3 in https://www.drupal.org/node/2813755.
|
||||
// $this->assertErrorResponse(422, "Unprocessable Entity: validation failed.\nuuid.0.value: <em class=\"placeholder\">UUID</em>: may not be longer than 128 characters.\n", $response);
|
||||
$this->assertSame(422, $response->getStatusCode());
|
||||
$this->assertSame([static::$mimeType], $response->getHeader('Content-Type'));
|
||||
$this->assertSame($this->serializer->encode(['message' => "Unprocessable Entity: validation failed.\nuuid.0.value: <em class=\"placeholder\">UUID</em>: may not be longer than 128 characters.\n"], static::$format), (string) $response->getBody());
|
||||
// @todo Fix this in https://www.drupal.org/node/2149851.
|
||||
if ($this->entity->getEntityType()->hasKey('uuid')) {
|
||||
$response = $this->request('POST', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nuuid.0.value: UUID: may not be longer than 128 characters.\n", $response);
|
||||
}
|
||||
|
||||
|
||||
$request_options[RequestOptions::BODY] = $parseable_invalid_request_body_3;
|
||||
|
@ -592,8 +707,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
|
||||
// DX: 403 when entity contains field without 'edit' access.
|
||||
$response = $this->request('POST', $url, $request_options);
|
||||
// @todo Add trailing period in https://www.drupal.org/node/2821013.
|
||||
$this->assertResourceErrorResponse(403, "Access denied on creating field 'field_rest_test'", $response);
|
||||
$this->assertResourceErrorResponse(403, "Access denied on creating field 'field_rest_test'.", $response);
|
||||
|
||||
|
||||
$request_options[RequestOptions::BODY] = $parseable_valid_request_body;
|
||||
|
@ -622,20 +736,24 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
// 201 for well-formed request.
|
||||
$response = $this->request('POST', $url, $request_options);
|
||||
$this->assertResourceResponse(201, FALSE, $response);
|
||||
$this->assertSame([str_replace($this->entity->id(), static::$firstCreatedEntityId, $this->entity->toUrl('canonical')->setAbsolute(TRUE)->toString())], $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'));
|
||||
|
||||
|
||||
$this->config('rest.settings')->set('bc_entity_resource_permissions', TRUE)->save(TRUE);
|
||||
$this->refreshTestStateAfterRestConfigChange();
|
||||
$request_options[RequestOptions::BODY] = $parseable_valid_request_body_2;
|
||||
// @todo Remove this in https://www.drupal.org/node/2815845.
|
||||
drupal_flush_all_caches();
|
||||
|
||||
|
||||
// DX: 403 when unauthorized.
|
||||
$response = $this->request('POST', $url, $request_options);
|
||||
// @todo Update the message in https://www.drupal.org/node/2808233.
|
||||
$this->assertResourceErrorResponse(403, '', $response);
|
||||
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('POST'), $response);
|
||||
|
||||
|
||||
$this->grantPermissionsToTestedRole(['restful post entity:' . static::$entityTypeId]);
|
||||
|
@ -644,7 +762,13 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
// 201 for well-formed request.
|
||||
$response = $this->request('POST', $url, $request_options);
|
||||
$this->assertResourceResponse(201, FALSE, $response);
|
||||
$this->assertSame([str_replace($this->entity->id(), static::$secondCreatedEntityId, $this->entity->toUrl('canonical')->setAbsolute(TRUE)->toString())], $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'));
|
||||
}
|
||||
|
||||
|
@ -677,23 +801,31 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
$request_options = [];
|
||||
|
||||
|
||||
// DX: 405 when resource not provisioned, but HTML 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());
|
||||
$this->assertSame(['GET, POST, HEAD'], $response->getHeader('Allow'));
|
||||
$this->assertSame(['text/html; 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->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();
|
||||
|
@ -701,16 +833,11 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
$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/html; 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/html; 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]);
|
||||
|
@ -734,11 +861,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
|
||||
// DX: 400 when unparseable request body.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
// @todo Uncomment, remove next 3 in https://www.drupal.org/node/2813853.
|
||||
// $this->assertResourceErrorResponse(400, 'Syntax error', $response);
|
||||
$this->assertSame(400, $response->getStatusCode());
|
||||
$this->assertSame([static::$mimeType], $response->getHeader('Content-Type'));
|
||||
$this->assertSame($this->serializer->encode(['error' => 'Syntax error'], static::$format), (string) $response->getBody());
|
||||
$this->assertResourceErrorResponse(400, 'Syntax error', $response);
|
||||
|
||||
|
||||
|
||||
|
@ -758,8 +881,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
|
||||
// DX: 403 when unauthorized.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
// @todo Update the message in https://www.drupal.org/node/2808233.
|
||||
$this->assertResourceErrorResponse(403, '', $response);
|
||||
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('PATCH'), $response);
|
||||
|
||||
|
||||
$this->setUpAuthorization('PATCH');
|
||||
|
@ -768,12 +890,8 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
// DX: 422 when invalid entity: multiple values sent for single-value field.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$label_field = $this->entity->getEntityType()->hasKey('label') ? $this->entity->getEntityType()->getKey('label') : static::$labelFieldName;
|
||||
$label_field_capitalized = ucfirst($label_field);
|
||||
// @todo Uncomment, remove next 3 in https://www.drupal.org/node/2813755.
|
||||
// $this->assertErrorResponse(422, "Unprocessable Entity: validation failed.\ntitle: <em class=\"placeholder\">Title</em>: this field cannot hold more than 1 values.\n", $response);
|
||||
// $this->assertSame(422, $response->getStatusCode());
|
||||
// $this->assertSame([static::$mimeType], $response->getHeader('Content-Type'));
|
||||
$this->assertSame($this->serializer->encode(['message' => "Unprocessable Entity: validation failed.\n$label_field: <em class=\"placeholder\">$label_field_capitalized</em>: this field cannot hold more than 1 values.\n"], static::$format), (string) $response->getBody());
|
||||
$label_field_capitalized = $this->entity->getFieldDefinition($label_field)->getLabel();
|
||||
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\n$label_field: $label_field_capitalized: this field cannot hold more than 1 values.\n", $response);
|
||||
|
||||
|
||||
$request_options[RequestOptions::BODY] = $parseable_invalid_request_body_2;
|
||||
|
@ -838,15 +956,13 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
|
||||
|
||||
$this->config('rest.settings')->set('bc_entity_resource_permissions', TRUE)->save(TRUE);
|
||||
$this->refreshTestStateAfterRestConfigChange();
|
||||
$request_options[RequestOptions::BODY] = $parseable_valid_request_body_2;
|
||||
// @todo Remove this in https://www.drupal.org/node/2815845.
|
||||
drupal_flush_all_caches();
|
||||
|
||||
|
||||
// DX: 403 when unauthorized.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
// @todo Update the message in https://www.drupal.org/node/2808233.
|
||||
$this->assertResourceErrorResponse(403, '', $response);
|
||||
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('PATCH'), $response);
|
||||
|
||||
|
||||
$this->grantPermissionsToTestedRole(['restful patch entity:' . static::$entityTypeId]);
|
||||
|
@ -880,24 +996,32 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
$request_options = [];
|
||||
|
||||
|
||||
// DX: 405 when resource not provisioned, but HTML if canonical route.
|
||||
// DX: 405 when resource not provisioned, but HTML 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());
|
||||
$this->assertSame(['GET, POST, HEAD'], $response->getHeader('Allow'));
|
||||
$this->assertSame(['text/html; 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->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();
|
||||
|
||||
|
@ -915,8 +1039,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
|
||||
// DX: 403 when unauthorized.
|
||||
$response = $this->request('DELETE', $url, $request_options);
|
||||
// @todo Update the message in https://www.drupal.org/node/2808233.
|
||||
$this->assertResourceErrorResponse(403, '', $response);
|
||||
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('DELETE'), $response);
|
||||
|
||||
|
||||
$this->setUpAuthorization('DELETE');
|
||||
|
@ -930,23 +1053,24 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
// 204 for well-formed request.
|
||||
$response = $this->request('DELETE', $url, $request_options);
|
||||
$this->assertSame(204, $response->getStatusCode());
|
||||
// @todo Uncomment the following line when https://www.drupal.org/node/2821711 is fixed.
|
||||
// DELETE responses should not include a Content-Type header. But Apache
|
||||
// sets it to 'text/html' by default. We also cannot detect the presence of
|
||||
// Apache either here in the CLI. For now having this documented here is all
|
||||
// we can do.
|
||||
// $this->assertSame(FALSE, $response->hasHeader('Content-Type'));
|
||||
$this->assertSame('', (string) $response->getBody());
|
||||
$this->assertFalse($response->hasHeader('X-Drupal-Cache'));
|
||||
|
||||
|
||||
$this->config('rest.settings')->set('bc_entity_resource_permissions', TRUE)->save(TRUE);
|
||||
// @todo Remove this in https://www.drupal.org/node/2815845.
|
||||
drupal_flush_all_caches();
|
||||
$this->refreshTestStateAfterRestConfigChange();
|
||||
$this->entity = $this->createEntity();
|
||||
$url = $this->getUrl()->setOption('query', $url->getOption('query'));
|
||||
|
||||
|
||||
// DX: 403 when unauthorized.
|
||||
$response = $this->request('DELETE', $url, $request_options);
|
||||
// @todo Update the message in https://www.drupal.org/node/2808233.
|
||||
$this->assertResourceErrorResponse(403, '', $response);
|
||||
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('DELETE'), $response);
|
||||
|
||||
|
||||
$this->grantPermissionsToTestedRole(['restful delete entity:' . static::$entityTypeId]);
|
||||
|
@ -982,11 +1106,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
// DX: 400 when incorrect entity type bundle is specified.
|
||||
// @todo Change to 422 in https://www.drupal.org/node/2827084.
|
||||
$response = $this->request($method, $url, $request_options);
|
||||
// @todo use this commented line instead of the 3 lines thereafter once https://www.drupal.org/node/2813853 lands.
|
||||
// $this->assertResourceErrorResponse(400, '"bad_bundle_name" is not a valid bundle type for denormalization.', $response);
|
||||
$this->assertSame(400, $response->getStatusCode());
|
||||
$this->assertSame([static::$mimeType], $response->getHeader('Content-Type'));
|
||||
$this->assertSame($this->serializer->encode(['error' => '"bad_bundle_name" is not a valid bundle type for denormalization.'], static::$format), (string) $response->getBody());
|
||||
$this->assertResourceErrorResponse(400, '"bad_bundle_name" is not a valid bundle type for denormalization.', $response);
|
||||
}
|
||||
|
||||
|
||||
|
@ -997,11 +1117,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
// DX: 400 when no entity type bundle is specified.
|
||||
// @todo Change to 422 in https://www.drupal.org/node/2827084.
|
||||
$response = $this->request($method, $url, $request_options);
|
||||
// @todo use this commented line instead of the 3 lines thereafter once https://www.drupal.org/node/2813853 lands.
|
||||
// $this->assertResourceErrorResponse(400, 'A string must be provided as a bundle value.', $response);
|
||||
$this->assertSame(400, $response->getStatusCode());
|
||||
$this->assertSame([static::$mimeType], $response->getHeader('Content-Type'));
|
||||
$this->assertSame($this->serializer->encode(['error' => 'A string must be provided as a bundle value.'], static::$format), (string) $response->getBody());
|
||||
$this->assertResourceErrorResponse(400, sprintf('Could not determine entity type bundle: "%s" field is missing.', $bundle_field_name), $response);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1090,4 +1206,23 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a resource is unavailable: 404, 406 if it has canonical route.
|
||||
*
|
||||
* @param \Drupal\Core\Url $url
|
||||
* URL to request.
|
||||
* @param array $request_options
|
||||
* Request options to apply.
|
||||
*/
|
||||
protected function assertResourceNotAvailable(Url $url, array $request_options) {
|
||||
$has_canonical_url = $this->entity->hasLinkTemplate('canonical');
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
if (!$has_canonical_url) {
|
||||
$this->assertSame(404, $response->getStatusCode());
|
||||
}
|
||||
else {
|
||||
$this->assert406Response($response);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,9 +21,4 @@ class EntityTestJsonAnonTest extends EntityTestResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\JsonBasicAuthWorkaroundFor2805281Trait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
|
@ -27,19 +26,9 @@ class EntityTestJsonBasicAuthTest extends EntityTestResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use JsonBasicAuthWorkaroundFor2805281Trait {
|
||||
JsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,11 +21,6 @@ class EntityTestJsonCookieTest extends EntityTestResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -73,7 +73,7 @@ abstract class EntityTestResourceTestBase extends EntityResourceTestBase {
|
|||
],
|
||||
'id' => [
|
||||
[
|
||||
'value' => '1',
|
||||
'value' => 1,
|
||||
],
|
||||
],
|
||||
'langcode' => [
|
||||
|
@ -93,12 +93,12 @@ abstract class EntityTestResourceTestBase extends EntityResourceTestBase {
|
|||
],
|
||||
'created' => [
|
||||
[
|
||||
'value' => $this->entity->get('created')->value,
|
||||
'value' => (int) $this->entity->get('created')->value,
|
||||
]
|
||||
],
|
||||
'user_id' => [
|
||||
[
|
||||
'target_id' => $author->id(),
|
||||
'target_id' => (int) $author->id(),
|
||||
'target_type' => 'user',
|
||||
'target_uuid' => $author->uuid(),
|
||||
'url' => $author->toUrl()->toString(),
|
||||
|
@ -124,4 +124,22 @@ abstract class EntityTestResourceTestBase extends EntityResourceTestBase {
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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 entity_test_with_bundle entities'.";
|
||||
default:
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTestLabel;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityTestLabelJsonAnonTest extends EntityTestLabelResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTestLabel;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityTestLabelJsonBasicAuthTest extends EntityTestLabelResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTestLabel;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityTestLabelJsonCookieTest extends EntityTestLabelResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTestLabel;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTestLabel;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
abstract class EntityTestLabelResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['entity_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'entity_test_label';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $patchProtectedFieldNames = [];
|
||||
|
||||
/**
|
||||
* @var \Drupal\entity_test\Entity\EntityTestLabel
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
$this->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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\FilterFormat;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class FilterFormatJsonAnonTest extends FilterFormatResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\FilterFormat;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class FilterFormatJsonBasicAuthTest extends FilterFormatResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\FilterFormat;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class FilterFormatJsonCookieTest extends FilterFormatResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\FilterFormat;
|
||||
|
||||
use Drupal\filter\Entity\FilterFormat;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
|
||||
abstract class FilterFormatResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'filter_format';
|
||||
|
||||
/**
|
||||
* @var \Drupal\filter\FilterFormatInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
$this->grantPermissionsToTestedRole(['administer filters']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
$pablo_format = FilterFormat::create([
|
||||
'name' => 'Pablo Piccasso',
|
||||
'format' => 'pablo',
|
||||
'langcode' => 'es',
|
||||
'filters' => [
|
||||
'filter_html' => [
|
||||
'status' => TRUE,
|
||||
'settings' => [
|
||||
'allowed_html' => '<p> <a> <b> <lo>',
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
$pablo_format->save();
|
||||
return $pablo_format;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'dependencies' => [],
|
||||
'filters' => [
|
||||
'filter_html' => [
|
||||
'id' => 'filter_html',
|
||||
'provider' => 'filter',
|
||||
'status' => TRUE,
|
||||
'weight' => -10,
|
||||
'settings' => [
|
||||
'allowed_html' => '<p> <a> <b> <lo>',
|
||||
'filter_html_help' => TRUE,
|
||||
'filter_html_nofollow' => FALSE,
|
||||
],
|
||||
],
|
||||
],
|
||||
'format' => 'pablo',
|
||||
'langcode' => 'es',
|
||||
'name' => 'Pablo Piccasso',
|
||||
'status' => TRUE,
|
||||
'uuid' => $this->entity->uuid(),
|
||||
'weight' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ImageStyle;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ImageStyleJsonAnonTest extends ImageStyleResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ImageStyle;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ImageStyleJsonBasicAuthTest extends ImageStyleResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ImageStyle;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ImageStyleJsonCookieTest extends ImageStyleResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ImageStyle;
|
||||
|
||||
use Drupal\image\Entity\ImageStyle;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
|
||||
/**
|
||||
* ResourceTestBase for ImageStyle entity.
|
||||
*/
|
||||
abstract class ImageStyleResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['image'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'image_style';
|
||||
|
||||
/**
|
||||
* The ImageStyle entity.
|
||||
*
|
||||
* @var \Drupal\image\ImageStyleInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* The effect UUID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $effectUuid;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
$this->grantPermissionsToTestedRole(['administer image styles']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
// Create a "Camelids" image style.
|
||||
$camelids = ImageStyle::create([
|
||||
'name' => 'camelids',
|
||||
'label' => 'Camelids',
|
||||
]);
|
||||
|
||||
// Add an image effect.
|
||||
$effect = [
|
||||
'id' => 'image_scale_and_crop',
|
||||
'data' => [
|
||||
'width' => 120,
|
||||
'height' => 121,
|
||||
],
|
||||
'weight' => 0,
|
||||
];
|
||||
$this->effectUuid = $camelids->addImageEffect($effect);
|
||||
|
||||
$camelids->save();
|
||||
|
||||
return $camelids;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'dependencies' => [],
|
||||
'effects' => [
|
||||
$this->effectUuid => [
|
||||
'uuid' => $this->effectUuid,
|
||||
'id' => 'image_scale_and_crop',
|
||||
'weight' => 0,
|
||||
'data' => [
|
||||
'width' => 120,
|
||||
'height' => 121,
|
||||
],
|
||||
],
|
||||
],
|
||||
'label' => 'Camelids',
|
||||
'langcode' => 'en',
|
||||
'name' => 'camelids',
|
||||
'status' => TRUE,
|
||||
'uuid' => $this->entity->uuid(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
return "The 'administer image styles' permission is required.";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Item;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ItemJsonAnonTest extends ItemResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Item;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ItemJsonBasicAuthTest extends ItemResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Item;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ItemJsonCookieTest extends ItemResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Item;
|
||||
|
||||
use Drupal\aggregator\Entity\Feed;
|
||||
use Drupal\aggregator\Entity\Item;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
|
||||
/**
|
||||
* ResourceTestBase for Item entity.
|
||||
*/
|
||||
abstract class ItemResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['aggregator'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'aggregator_item';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $patchProtectedFieldNames = [];
|
||||
|
||||
/**
|
||||
* The Item entity.
|
||||
*
|
||||
* @var \Drupal\aggregator\ItemInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
$this->grantPermissionsToTestedRole(['access news feeds']);
|
||||
break;
|
||||
|
||||
case 'POST':
|
||||
case 'PATCH':
|
||||
case 'DELETE':
|
||||
$this->grantPermissionsToTestedRole(['administer news feeds']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
// Create a "Camelids" feed.
|
||||
$feed = Feed::create([
|
||||
'title' => 'Camelids',
|
||||
'url' => 'https://groups.drupal.org/not_used/167169',
|
||||
'refresh' => 900,
|
||||
'checked' => 1389919932,
|
||||
'description' => 'Drupal Core Group feed',
|
||||
]);
|
||||
$feed->save();
|
||||
|
||||
// Create a "Llama" item.
|
||||
$item = Item::create();
|
||||
$item->setTitle('Llama')
|
||||
->setFeedId($feed->id())
|
||||
->setLink('https://www.drupal.org/')
|
||||
->setPostedTime(123456789)
|
||||
->save();
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
$feed = Feed::load($this->entity->getFeedId());
|
||||
|
||||
return [
|
||||
'iid' => [
|
||||
[
|
||||
'value' => 1,
|
||||
],
|
||||
],
|
||||
'langcode' => [
|
||||
[
|
||||
'value' => 'en',
|
||||
],
|
||||
],
|
||||
'fid' => [
|
||||
[
|
||||
'target_id' => 1,
|
||||
'target_type' => 'aggregator_feed',
|
||||
'target_uuid' => $feed->uuid(),
|
||||
'url' => base_path() . 'aggregator/sources/1',
|
||||
],
|
||||
],
|
||||
'title' => [
|
||||
[
|
||||
'value' => 'Llama',
|
||||
],
|
||||
],
|
||||
'link' => [
|
||||
[
|
||||
'value' => 'https://www.drupal.org/',
|
||||
],
|
||||
],
|
||||
'author' => [],
|
||||
'description' => [],
|
||||
'timestamp' => [
|
||||
[
|
||||
'value' => 123456789,
|
||||
],
|
||||
],
|
||||
'guid' => [],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return [
|
||||
'fid' => [
|
||||
[
|
||||
'target_id' => 1,
|
||||
],
|
||||
],
|
||||
'title' => [
|
||||
[
|
||||
'value' => 'Llama',
|
||||
],
|
||||
],
|
||||
'link' => [
|
||||
[
|
||||
'value' => 'https://www.drupal.org/',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
// @see ::createEntity()
|
||||
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 'access news feeds' permission is required.";
|
||||
|
||||
case 'POST':
|
||||
case 'PATCH':
|
||||
case 'DELETE':
|
||||
return "The 'administer news feeds' permission is required.";
|
||||
|
||||
default:
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\MenuLinkContent;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class MenuLinkContentJsonAnonTest extends MenuLinkContentResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\MenuLinkContent;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class MenuLinkContentJsonBasicAuthTest extends MenuLinkContentResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\MenuLinkContent;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class MenuLinkContentJsonCookieTest extends MenuLinkContentResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\MenuLinkContent;
|
||||
|
||||
use Drupal\menu_link_content\Entity\MenuLinkContent;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
|
||||
/**
|
||||
* ResourceTestBase for MenuLinkContent entity.
|
||||
*/
|
||||
abstract class MenuLinkContentResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['menu_link_content'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'menu_link_content';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $patchProtectedFieldNames = [
|
||||
'changed',
|
||||
];
|
||||
|
||||
/**
|
||||
* The MenuLinkContent entity.
|
||||
*
|
||||
* @var \Drupal\menu_link_content\MenuLinkContentInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
case 'POST':
|
||||
case 'PATCH':
|
||||
case 'DELETE':
|
||||
$this->grantPermissionsToTestedRole(['administer menu']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
$menu_link = MenuLinkContent::create([
|
||||
'id' => 'llama',
|
||||
'title' => 'Llama Gabilondo',
|
||||
'description' => 'Llama Gabilondo',
|
||||
'link' => 'https://nl.wikipedia.org/wiki/Llama',
|
||||
'weight' => 0,
|
||||
'menu_name' => 'main',
|
||||
]);
|
||||
$menu_link->save();
|
||||
|
||||
return $menu_link;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return [
|
||||
'title' => [
|
||||
[
|
||||
'value' => 'Dramallama',
|
||||
],
|
||||
],
|
||||
'link' => [
|
||||
[
|
||||
'uri' => 'http://www.urbandictionary.com/define.php?term=drama%20llama',
|
||||
],
|
||||
],
|
||||
'bundle' => [
|
||||
[
|
||||
'value' => 'menu_link_content',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'uuid' => [
|
||||
[
|
||||
'value' => $this->entity->uuid(),
|
||||
],
|
||||
],
|
||||
'id' => [
|
||||
[
|
||||
'value' => 1,
|
||||
],
|
||||
],
|
||||
'title' => [
|
||||
[
|
||||
'value' => 'Llama Gabilondo',
|
||||
],
|
||||
],
|
||||
'link' => [
|
||||
[
|
||||
'uri' => 'https://nl.wikipedia.org/wiki/Llama',
|
||||
'title' => NULL,
|
||||
'options' => [],
|
||||
],
|
||||
],
|
||||
'weight' => [
|
||||
[
|
||||
'value' => 0,
|
||||
],
|
||||
],
|
||||
'menu_name' => [
|
||||
[
|
||||
'value' => 'main',
|
||||
],
|
||||
],
|
||||
'langcode' => [
|
||||
[
|
||||
'value' => 'en',
|
||||
],
|
||||
],
|
||||
'bundle' => [
|
||||
[
|
||||
'value' => 'menu_link_content',
|
||||
],
|
||||
],
|
||||
'description' => [
|
||||
[
|
||||
'value' => 'Llama Gabilondo',
|
||||
],
|
||||
],
|
||||
'external' => [
|
||||
[
|
||||
'value' => FALSE,
|
||||
],
|
||||
],
|
||||
'rediscover' => [
|
||||
[
|
||||
'value' => FALSE,
|
||||
],
|
||||
],
|
||||
'expanded' => [
|
||||
[
|
||||
'value' => FALSE,
|
||||
],
|
||||
],
|
||||
'enabled' => [
|
||||
[
|
||||
'value' => TRUE,
|
||||
],
|
||||
],
|
||||
'changed' => [
|
||||
[
|
||||
'value' => $this->entity->getChangedTime(),
|
||||
],
|
||||
],
|
||||
'default_langcode' => [
|
||||
[
|
||||
'value' => TRUE,
|
||||
],
|
||||
],
|
||||
'parent' => [],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
switch ($method) {
|
||||
case 'DELETE':
|
||||
return "You are not authorized to delete this menu_link_content entity.";
|
||||
default:
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -21,9 +21,4 @@ class NodeJsonAnonTest extends NodeResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace Drupal\Tests\rest\Functional\EntityResource\Node;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\JsonBasicAuthWorkaroundFor2805281Trait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
|
@ -27,19 +26,9 @@ class NodeJsonBasicAuthTest extends NodeResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use JsonBasicAuthWorkaroundFor2805281Trait {
|
||||
JsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,11 +21,6 @@ class NodeJsonCookieTest extends NodeResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -116,32 +116,32 @@ abstract class NodeResourceTestBase extends EntityResourceTestBase {
|
|||
],
|
||||
'status' => [
|
||||
[
|
||||
'value' => 1,
|
||||
'value' => TRUE,
|
||||
],
|
||||
],
|
||||
'created' => [
|
||||
[
|
||||
'value' => '123456789',
|
||||
'value' => 123456789,
|
||||
],
|
||||
],
|
||||
'changed' => [
|
||||
[
|
||||
'value' => '123456789',
|
||||
'value' => $this->entity->getChangedTime(),
|
||||
],
|
||||
],
|
||||
'promote' => [
|
||||
[
|
||||
'value' => 1,
|
||||
'value' => TRUE,
|
||||
],
|
||||
],
|
||||
'sticky' => [
|
||||
[
|
||||
'value' => '0',
|
||||
'value' => FALSE,
|
||||
],
|
||||
],
|
||||
'revision_timestamp' => [
|
||||
[
|
||||
'value' => '123456789',
|
||||
'value' => 123456789,
|
||||
],
|
||||
],
|
||||
'revision_translation_affected' => [
|
||||
|
@ -156,7 +156,7 @@ abstract class NodeResourceTestBase extends EntityResourceTestBase {
|
|||
],
|
||||
'uid' => [
|
||||
[
|
||||
'target_id' => $author->id(),
|
||||
'target_id' => (int) $author->id(),
|
||||
'target_type' => 'user',
|
||||
'target_uuid' => $author->uuid(),
|
||||
'url' => base_path() . 'user/' . $author->id(),
|
||||
|
@ -164,14 +164,13 @@ abstract class NodeResourceTestBase extends EntityResourceTestBase {
|
|||
],
|
||||
'revision_uid' => [
|
||||
[
|
||||
'target_id' => $author->id(),
|
||||
'target_id' => (int) $author->id(),
|
||||
'target_type' => 'user',
|
||||
'target_uuid' => $author->uuid(),
|
||||
'url' => base_path() . 'user/' . $author->id(),
|
||||
],
|
||||
],
|
||||
'revision_log' => [
|
||||
],
|
||||
'revision_log' => [],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -193,4 +192,18 @@ abstract class NodeResourceTestBase extends EntityResourceTestBase {
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
if ($method === 'GET' || $method == 'PATCH' || $method == 'DELETE') {
|
||||
return "The 'access content' permission is required.";
|
||||
}
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\NodeType;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class NodeTypeJsonAnonTest extends NodeTypeResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\NodeType;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class NodeTypeJsonBasicAuthTest extends NodeTypeResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\NodeType;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class NodeTypeJsonCookieTest extends NodeTypeResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\NodeType;
|
||||
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
|
||||
/**
|
||||
* ResourceTestBase for NodeType entity.
|
||||
*/
|
||||
abstract class NodeTypeResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['node'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'node_type';
|
||||
|
||||
/**
|
||||
* The NodeType entity.
|
||||
*
|
||||
* @var \Drupal\node\NodeTypeInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
$this->grantPermissionsToTestedRole(['administer content types', 'access content']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
// Create a "Camelids" node type.
|
||||
$camelids = NodeType::create([
|
||||
'name' => 'Camelids',
|
||||
'type' => 'camelids',
|
||||
'description' => 'Camelids are large, strictly herbivorous animals with slender necks and long legs.',
|
||||
]);
|
||||
|
||||
$camelids->save();
|
||||
|
||||
return $camelids;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'dependencies' => [],
|
||||
'description' => 'Camelids are large, strictly herbivorous animals with slender necks and long legs.',
|
||||
'display_submitted' => TRUE,
|
||||
'help' => NULL,
|
||||
'langcode' => 'en',
|
||||
'name' => 'Camelids',
|
||||
'new_revision' => TRUE,
|
||||
'preview_mode' => 1,
|
||||
'status' => TRUE,
|
||||
'type' => 'camelids',
|
||||
'uuid' => $this->entity->uuid(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
return "The 'access content' permission is required.";
|
||||
}
|
||||
|
||||
}
|
|
@ -21,9 +21,4 @@ class RoleJsonAnonTest extends RoleResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace Drupal\Tests\rest\Functional\EntityResource\Role;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
|
@ -27,22 +26,9 @@ class RoleJsonBasicAuthTest extends RoleResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function assertResponseWhenMissingAuthentication(ResponseInterface $response) {
|
||||
$this->assertSame(401, $response->getStatusCode());
|
||||
$this->assertSame('{"message":"A fatal error occurred: No authentication credentials provided."}', (string) $response->getBody());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,11 +21,6 @@ class RoleJsonCookieTest extends RoleResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\SearchPage;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class SearchPageJsonAnonTest extends SearchPageResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\SearchPage;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class SearchPageJsonBasicAuthTest extends SearchPageResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\SearchPage;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class SearchPageJsonCookieTest extends SearchPageResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\SearchPage;
|
||||
|
||||
use Drupal\search\Entity\SearchPage;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
|
||||
abstract class SearchPageResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['node', 'search'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'search_page';
|
||||
|
||||
/**
|
||||
* @var \Drupal\search\SearchPageInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
$this->grantPermissionsToTestedRole(['access content']);
|
||||
break;
|
||||
|
||||
case 'POST':
|
||||
case 'PATCH':
|
||||
case 'DELETE':
|
||||
$this->grantPermissionsToTestedRole(['administer search']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
$search_page = SearchPage::create([
|
||||
'id' => 'hinode_search',
|
||||
'plugin' => 'node_search',
|
||||
'label' => 'Search of magnetic activity of the Sun',
|
||||
'path' => 'sun',
|
||||
]);
|
||||
$search_page->save();
|
||||
return $search_page;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'configuration' => [
|
||||
'rankings' => [],
|
||||
],
|
||||
'dependencies' => [
|
||||
'module' => ['node'],
|
||||
],
|
||||
'id' => 'hinode_search',
|
||||
'label' => 'Search of magnetic activity of the Sun',
|
||||
'langcode' => 'en',
|
||||
'path' => 'sun',
|
||||
'plugin' => 'node_search',
|
||||
'status' => TRUE,
|
||||
'uuid' => $this->entity->uuid(),
|
||||
'weight' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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 'access content' permission is required.";
|
||||
|
||||
default:
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Shortcut;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ShortcutJsonAnonTest extends ShortcutResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Shortcut;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ShortcutJsonBasicAuthTest extends ShortcutResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Shortcut;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ShortcutJsonCookieTest extends ShortcutResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Shortcut;
|
||||
|
||||
use Drupal\shortcut\Entity\Shortcut;
|
||||
use Drupal\shortcut\Entity\ShortcutSet;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
|
||||
/**
|
||||
* ResourceTestBase for Shortcut entity.
|
||||
*/
|
||||
abstract class ShortcutResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['comment', 'shortcut'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'shortcut';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $patchProtectedFieldNames = [];
|
||||
|
||||
/**
|
||||
* The Shortcut entity.
|
||||
*
|
||||
* @var \Drupal\shortcut\ShortcutInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
case 'POST':
|
||||
case 'PATCH':
|
||||
case 'DELETE':
|
||||
$this->grantPermissionsToTestedRole(['access shortcuts', 'customize shortcut links']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
// Create shortcut.
|
||||
$shortcut = Shortcut::create([
|
||||
'shortcut_set' => 'default',
|
||||
'title' => t('Comments'),
|
||||
'weight' => -20,
|
||||
'link' => [
|
||||
'uri' => 'internal:/admin/content/comment',
|
||||
],
|
||||
]);
|
||||
$shortcut->save();
|
||||
|
||||
return $shortcut;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'uuid' => [
|
||||
[
|
||||
'value' => $this->entity->uuid(),
|
||||
],
|
||||
],
|
||||
'id' => [
|
||||
[
|
||||
'value' => (int) $this->entity->id(),
|
||||
],
|
||||
],
|
||||
'title' => [
|
||||
[
|
||||
'value' => 'Comments',
|
||||
],
|
||||
],
|
||||
'shortcut_set' => [
|
||||
[
|
||||
'target_id' => 'default',
|
||||
'target_type' => 'shortcut_set',
|
||||
'target_uuid' => ShortcutSet::load('default')->uuid(),
|
||||
],
|
||||
],
|
||||
'link' => [
|
||||
[
|
||||
'uri' => 'internal:/admin/content/comment',
|
||||
'title' => NULL,
|
||||
'options' => [],
|
||||
],
|
||||
],
|
||||
'weight' => [
|
||||
[
|
||||
'value' => -20,
|
||||
],
|
||||
],
|
||||
'langcode' => [
|
||||
[
|
||||
'value' => 'en',
|
||||
],
|
||||
],
|
||||
'default_langcode' => [
|
||||
[
|
||||
'value' => TRUE,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return [
|
||||
'title' => [
|
||||
[
|
||||
'value' => 'Comments',
|
||||
],
|
||||
],
|
||||
'link' => [
|
||||
[
|
||||
'uri' => 'internal:/',
|
||||
],
|
||||
],
|
||||
'shortcut_set' => 'default',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
case 'POST':
|
||||
case 'PATCH':
|
||||
case 'DELETE':
|
||||
return "The shortcut set must be the currently displayed set for the user and the user must have 'access shortcuts' AND 'customize shortcut links' permissions.";
|
||||
|
||||
default:
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -21,9 +21,4 @@ class TermJsonAnonTest extends TermResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace Drupal\Tests\rest\Functional\EntityResource\Term;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\JsonBasicAuthWorkaroundFor2805281Trait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
|
@ -27,19 +26,9 @@ class TermJsonBasicAuthTest extends TermResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use JsonBasicAuthWorkaroundFor2805281Trait {
|
||||
JsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,11 +21,6 @@ class TermJsonCookieTest extends TermResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -108,7 +108,7 @@ abstract class TermResourceTestBase extends EntityResourceTestBase {
|
|||
],
|
||||
'changed' => [
|
||||
[
|
||||
'value' => '123456789',
|
||||
'value' => $this->entity->getChangedTime(),
|
||||
],
|
||||
],
|
||||
'default_langcode' => [
|
||||
|
@ -137,4 +137,26 @@ abstract class TermResourceTestBase extends EntityResourceTestBase {
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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 'access content' permission is required.";
|
||||
case 'POST':
|
||||
return "The 'administer taxonomy' permission is required.";
|
||||
case 'PATCH':
|
||||
return "The following permissions are required: 'edit terms in camelids' OR 'administer taxonomy'.";
|
||||
case 'DELETE':
|
||||
return "The following permissions are required: 'delete terms in camelids' OR 'administer taxonomy'.";
|
||||
default:
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,9 +21,4 @@ class UserJsonAnonTest extends UserResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace Drupal\Tests\rest\Functional\EntityResource\User;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\JsonBasicAuthWorkaroundFor2805281Trait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
|
@ -27,19 +26,9 @@ class UserJsonBasicAuthTest extends UserResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use JsonBasicAuthWorkaroundFor2805281Trait {
|
||||
JsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,11 +21,6 @@ class UserJsonCookieTest extends UserResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -82,7 +82,7 @@ abstract class UserResourceTestBase extends EntityResourceTestBase {
|
|||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'uid' => [
|
||||
['value' => '3'],
|
||||
['value' => 3],
|
||||
],
|
||||
'uuid' => [
|
||||
['value' => $this->entity->uuid()],
|
||||
|
@ -99,12 +99,12 @@ abstract class UserResourceTestBase extends EntityResourceTestBase {
|
|||
],
|
||||
'created' => [
|
||||
[
|
||||
'value' => '123456789',
|
||||
'value' => 123456789,
|
||||
],
|
||||
],
|
||||
'changed' => [
|
||||
[
|
||||
'value' => '123456789',
|
||||
'value' => $this->entity->getChangedTime(),
|
||||
],
|
||||
],
|
||||
'default_langcode' => [
|
||||
|
@ -163,11 +163,7 @@ abstract class UserResourceTestBase extends EntityResourceTestBase {
|
|||
|
||||
// DX: 422 when changing email without providing the password.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
// @todo use this commented line instead of the 3 lines thereafter once https://www.drupal.org/node/2813755 lands.
|
||||
// $this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the <em class=\"placeholder\">Email</em>.\n", $response);
|
||||
$this->assertSame(422, $response->getStatusCode());
|
||||
$this->assertSame([static::$mimeType], $response->getHeader('Content-Type'));
|
||||
$this->assertSame($this->serializer->encode(['message' => "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the <em class=\"placeholder\">Email</em>.\n"], static::$format), (string) $response->getBody());
|
||||
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the Email.\n", $response);
|
||||
|
||||
|
||||
$normalization['pass'] = [['existing' => 'wrong']];
|
||||
|
@ -175,11 +171,7 @@ abstract class UserResourceTestBase extends EntityResourceTestBase {
|
|||
|
||||
// DX: 422 when changing email while providing a wrong password.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
// @todo use this commented line instead of the 3 lines thereafter once https://www.drupal.org/node/2813755 lands.
|
||||
// $this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the <em class=\"placeholder\">Email</em>.\n", $response);
|
||||
$this->assertSame(422, $response->getStatusCode());
|
||||
$this->assertSame([static::$mimeType], $response->getHeader('Content-Type'));
|
||||
$this->assertSame($this->serializer->encode(['message' => "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the <em class=\"placeholder\">Email</em>.\n"], static::$format), (string) $response->getBody());
|
||||
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the Email.\n", $response);
|
||||
|
||||
|
||||
$normalization['pass'] = [['existing' => $this->account->passRaw]];
|
||||
|
@ -200,11 +192,7 @@ abstract class UserResourceTestBase extends EntityResourceTestBase {
|
|||
|
||||
// DX: 422 when changing password without providing the current password.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
// @todo use this commented line instead of the 3 lines thereafter once https://www.drupal.org/node/2813755 lands.
|
||||
// $this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\npass: Your current password is missing or incorrect; it's required to change the <em class=\"placeholder\">Password</em>.\n", $response);
|
||||
$this->assertSame(422, $response->getStatusCode());
|
||||
$this->assertSame([static::$mimeType], $response->getHeader('Content-Type'));
|
||||
$this->assertSame($this->serializer->encode(['message' => "Unprocessable Entity: validation failed.\npass: Your current password is missing or incorrect; it's required to change the <em class=\"placeholder\">Password</em>.\n"], static::$format), (string) $response->getBody());
|
||||
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\npass: Your current password is missing or incorrect; it's required to change the Password.\n", $response);
|
||||
|
||||
|
||||
$normalization['pass'][0]['existing'] = $this->account->pass_raw;
|
||||
|
@ -229,4 +217,24 @@ abstract class UserResourceTestBase extends EntityResourceTestBase {
|
|||
$this->assertSame(200, $response->getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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 'access user profiles' permission is required and the user must be active.";
|
||||
case 'PATCH':
|
||||
return "You are not authorized to update this user entity.";
|
||||
case 'DELETE':
|
||||
return 'You are not authorized to delete this user entity.';
|
||||
default:
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,11 +21,6 @@ class VocabularyJsonAnonTest extends VocabularyResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* Disable the GET test coverage due to bug in taxonomy module.
|
||||
* @todo Fix in https://www.drupal.org/node/2805281: remove this override.
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace Drupal\Tests\rest\Functional\EntityResource\Vocabulary;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\JsonBasicAuthWorkaroundFor2805281Trait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
|
@ -27,19 +26,9 @@ class VocabularyJsonBasicAuthTest extends VocabularyResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
// @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
|
||||
use JsonBasicAuthWorkaroundFor2805281Trait {
|
||||
JsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,11 +21,6 @@ class VocabularyJsonCookieTest extends VocabularyResourceTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
trait JsonBasicAuthWorkaroundFor2805281Trait {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Note that strange 'A fatal error occurred: ' prefix, that should not exist.
|
||||
*
|
||||
* @todo Fix in https://www.drupal.org/node/2805281: remove this trait.
|
||||
*/
|
||||
protected function assertResponseWhenMissingAuthentication(ResponseInterface $response) {
|
||||
$this->assertSame(401, $response->getStatusCode());
|
||||
$this->assertSame([static::$expectedErrorMimeType], $response->getHeader('Content-Type'));
|
||||
// Note that strange 'A fatal error occurred: ' prefix, that should not
|
||||
// exist.
|
||||
// @todo Fix in https://www.drupal.org/node/2805281.
|
||||
$this->assertSame('{"message":"A fatal error occurred: No authentication credentials provided."}', (string) $response->getBody());
|
||||
}
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\Tests\rest\Functional;
|
||||
|
||||
use Behat\Mink\Driver\BrowserKitDriver;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\rest\RestResourceConfigInterface;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
@ -46,17 +47,6 @@ abstract class ResourceTestBase extends BrowserTestBase {
|
|||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* The expected MIME type in case of 4xx error responses.
|
||||
*
|
||||
* (Can be different, when $mimeType for example encodes a particular
|
||||
* normalization, such as 'application/hal+json': its error response MIME
|
||||
* type is 'application/json'.)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $expectedErrorMimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* The authentication mechanism to use in this test.
|
||||
*
|
||||
|
@ -66,6 +56,15 @@ abstract class ResourceTestBase extends BrowserTestBase {
|
|||
*/
|
||||
protected static $auth = FALSE;
|
||||
|
||||
/**
|
||||
* The REST Resource Config entity ID under test (i.e. a resource type).
|
||||
*
|
||||
* The REST Resource plugin ID can be calculated from this.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $resourceConfigId = NULL;
|
||||
|
||||
/**
|
||||
* The account to use for authentication, if any.
|
||||
*
|
||||
|
@ -94,6 +93,11 @@ abstract class ResourceTestBase extends BrowserTestBase {
|
|||
*/
|
||||
public static $modules = ['rest'];
|
||||
|
||||
/**
|
||||
* @var \GuzzleHttp\ClientInterface
|
||||
*/
|
||||
protected $httpClient;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -130,30 +134,51 @@ abstract class ResourceTestBase extends BrowserTestBase {
|
|||
|
||||
// Ensure there's a clean slate: delete all REST resource config entities.
|
||||
$this->resourceConfigStorage->delete($this->resourceConfigStorage->loadMultiple());
|
||||
$this->refreshTestStateAfterRestConfigChange();
|
||||
|
||||
// Set up a HTTP client that accepts relative URLs.
|
||||
$this->httpClient = $this->container->get('http_client_factory')
|
||||
->fromOptions(['base_uri' => $this->baseUrl]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provisions a REST resource.
|
||||
* Provisions the REST resource under test.
|
||||
*
|
||||
* @param string $resource_type
|
||||
* The resource type (REST resource plugin ID).
|
||||
* @param string[] $formats
|
||||
* The allowed formats for this resource.
|
||||
* @param string[] $authentication
|
||||
* The allowed authentication providers for this resource.
|
||||
*/
|
||||
protected function provisionResource($resource_type, $formats = [], $authentication = []) {
|
||||
protected function provisionResource($formats = [], $authentication = []) {
|
||||
$this->resourceConfigStorage->create([
|
||||
'id' => $resource_type,
|
||||
'id' => static::$resourceConfigId,
|
||||
'granularity' => RestResourceConfigInterface::RESOURCE_GRANULARITY,
|
||||
'configuration' => [
|
||||
'methods' => ['GET', 'POST', 'PATCH', 'DELETE'],
|
||||
'formats' => $formats,
|
||||
'authentication' => $authentication,
|
||||
]
|
||||
],
|
||||
'status' => TRUE,
|
||||
])->save();
|
||||
// @todo Remove this in https://www.drupal.org/node/2815845.
|
||||
drupal_flush_all_caches();
|
||||
$this->refreshTestStateAfterRestConfigChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the state of the tester to be in sync with the testee.
|
||||
*
|
||||
* Should be called after every change made to:
|
||||
* - RestResourceConfig entities
|
||||
* - the 'rest.settings' simple configuration
|
||||
*/
|
||||
protected function refreshTestStateAfterRestConfigChange() {
|
||||
// Ensure that the cache tags invalidator has its internal values reset.
|
||||
// Otherwise the http_response cache tag invalidation won't work.
|
||||
$this->refreshVariables();
|
||||
|
||||
// Tests using this base class may trigger route rebuilds due to changes to
|
||||
// RestResourceConfig entities or 'rest.settings'. Ensure the test generates
|
||||
// routes using an up-to-date router.
|
||||
\Drupal::service('router.builder')->rebuildIfNeeded();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,6 +239,29 @@ abstract class ResourceTestBase extends BrowserTestBase {
|
|||
*/
|
||||
abstract protected function assertAuthenticationEdgeCases($method, Url $url, array $request_options);
|
||||
|
||||
/**
|
||||
* Return the expected error message.
|
||||
*
|
||||
* @param string $method
|
||||
* The HTTP method (GET, POST, PATCH, DELETE).
|
||||
*
|
||||
* @return string
|
||||
* The error string.
|
||||
*/
|
||||
abstract protected function getExpectedUnauthorizedAccessMessage($method);
|
||||
|
||||
/**
|
||||
* Return the default expected error message if the
|
||||
* bc_entity_resource_permissions is true.
|
||||
*
|
||||
* @param string $method
|
||||
* The HTTP method (GET, POST, PATCH, DELETE).
|
||||
*
|
||||
* @return string
|
||||
* The error string.
|
||||
*/
|
||||
abstract protected function getExpectedBcUnauthorizedAccessMessage($method);
|
||||
|
||||
/**
|
||||
* Initializes authentication.
|
||||
*
|
||||
|
@ -295,16 +343,13 @@ abstract class ResourceTestBase extends BrowserTestBase {
|
|||
*/
|
||||
protected function request($method, Url $url, array $request_options) {
|
||||
$request_options[RequestOptions::HTTP_ERRORS] = FALSE;
|
||||
$request_options = $this->decorateWithXdebugCookie($request_options);
|
||||
return $this->httpClient->request($method, $url->toString(), $request_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a resource response has the given status code and body.
|
||||
*
|
||||
* (Also asserts that the expected error MIME type is present, but this is
|
||||
* defined globally for the test via static::$expectedErrorMimeType, because
|
||||
* all error responses should use the same MIME type.)
|
||||
*
|
||||
* @param int $expected_status_code
|
||||
* The expected response status.
|
||||
* @param string|false $expected_body
|
||||
|
@ -318,7 +363,7 @@ abstract class ResourceTestBase extends BrowserTestBase {
|
|||
$this->assertSame([static::$mimeType], $response->getHeader('Content-Type'));
|
||||
}
|
||||
else {
|
||||
$this->assertSame([static::$expectedErrorMimeType], $response->getHeader('Content-Type'));
|
||||
$this->assertSame([static::$mimeType], $response->getHeader('Content-Type'));
|
||||
}
|
||||
if ($expected_body !== FALSE) {
|
||||
$this->assertSame($expected_body, (string) $response->getBody());
|
||||
|
@ -328,10 +373,6 @@ abstract class ResourceTestBase extends BrowserTestBase {
|
|||
/**
|
||||
* Asserts that a resource error response has the given message.
|
||||
*
|
||||
* (Also asserts that the expected error MIME type is present, but this is
|
||||
* defined globally for the test via static::$expectedErrorMimeType, because
|
||||
* all error responses should use the same MIME type.)
|
||||
*
|
||||
* @param int $expected_status_code
|
||||
* The expected response status.
|
||||
* @param string $expected_message
|
||||
|
@ -340,10 +381,34 @@ abstract class ResourceTestBase extends BrowserTestBase {
|
|||
* The error response to assert.
|
||||
*/
|
||||
protected function assertResourceErrorResponse($expected_status_code, $expected_message, ResponseInterface $response) {
|
||||
// @todo Fix this in https://www.drupal.org/node/2813755.
|
||||
$encode_options = ['json_encode_options' => JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT];
|
||||
$expected_body = $this->serializer->encode(['message' => $expected_message], static::$format, $encode_options);
|
||||
$expected_body = ($expected_message !== FALSE) ? $this->serializer->encode(['message' => $expected_message], static::$format) : FALSE;
|
||||
$this->assertResourceResponse($expected_status_code, $expected_body, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the Xdebug cookie to the request options.
|
||||
*
|
||||
* @param array $request_options
|
||||
* The request options.
|
||||
*
|
||||
* @return array
|
||||
* Request options updated with the Xdebug cookie if present.
|
||||
*/
|
||||
protected function decorateWithXdebugCookie(array $request_options) {
|
||||
$session = $this->getSession();
|
||||
$driver = $session->getDriver();
|
||||
if ($driver instanceof BrowserKitDriver) {
|
||||
$client = $driver->getClient();
|
||||
foreach ($client->getCookieJar()->all() as $cookie) {
|
||||
if (isset($request_options[RequestOptions::HEADERS]['Cookie'])) {
|
||||
$request_options[RequestOptions::HEADERS]['Cookie'] .= '; ' . $cookie->getName() . '=' . $cookie->getValue();
|
||||
}
|
||||
else {
|
||||
$request_options[RequestOptions::HEADERS]['Cookie'] = $cookie->getName() . '=' . $cookie->getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return $request_options;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Drupal\Tests\rest\Kernel;
|
||||
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Routing\RouteMatch;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
@ -10,8 +9,6 @@ use Drupal\rest\Plugin\ResourceBase;
|
|||
use Drupal\rest\RequestHandler;
|
||||
use Drupal\rest\ResourceResponse;
|
||||
use Drupal\rest\RestResourceConfigInterface;
|
||||
use Prophecy\Argument;
|
||||
use Prophecy\Prophecy\MethodProphecy;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
|
@ -48,11 +45,9 @@ class RequestHandlerTest extends KernelTestBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Assert some basic handler method logic.
|
||||
*
|
||||
* @covers ::handle
|
||||
*/
|
||||
public function testBaseHandler() {
|
||||
public function testHandle() {
|
||||
$request = new Request();
|
||||
$route_match = new RouteMatch('test', new Route('/rest/test', ['_rest_resource_config' => 'restplugin'], ['_format' => 'json']));
|
||||
|
||||
|
@ -91,249 +86,6 @@ class RequestHandlerTest extends KernelTestBase {
|
|||
$this->assertEquals($response, $handler_response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that given structured data, the request handler will serialize it.
|
||||
*
|
||||
* @dataProvider providerTestSerialization
|
||||
* @covers ::handle
|
||||
*/
|
||||
public function testSerialization($data, $expected_response = FALSE) {
|
||||
$request = new Request();
|
||||
$route_match = new RouteMatch('test', new Route('/rest/test', ['_rest_resource_config' => 'restplugin'], ['_format' => 'json']));
|
||||
|
||||
$resource = $this->prophesize(StubRequestHandlerResourcePlugin::class);
|
||||
|
||||
// Mock the configuration.
|
||||
$config = $this->prophesize(RestResourceConfigInterface::class);
|
||||
$config->getResourcePlugin()->willReturn($resource->reveal());
|
||||
$config->getCacheContexts()->willReturn([]);
|
||||
$config->getCacheTags()->willReturn([]);
|
||||
$config->getCacheMaxAge()->willReturn(12);
|
||||
$this->entityStorage->load('restplugin')->willReturn($config->reveal());
|
||||
|
||||
$response = new ResourceResponse($data);
|
||||
$resource->get(NULL, $request)
|
||||
->willReturn($response);
|
||||
$handler_response = $this->requestHandler->handle($route_match, $request);
|
||||
// Content is a serialized version of the data we provided.
|
||||
$this->assertEquals($expected_response !== FALSE ? $expected_response : json_encode($data), $handler_response->getContent());
|
||||
}
|
||||
|
||||
public function providerTestSerialization() {
|
||||
return [
|
||||
// The default data for \Drupal\rest\ResourceResponse.
|
||||
[NULL, ''],
|
||||
[''],
|
||||
['string'],
|
||||
['Complex \ string $%^&@ with unicode ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΣὨ'],
|
||||
[[]],
|
||||
[['test']],
|
||||
[['test' => 'foobar']],
|
||||
[TRUE],
|
||||
[FALSE],
|
||||
// @todo Not supported. https://www.drupal.org/node/2427811
|
||||
// [new \stdClass()],
|
||||
// [(object) ['test' => 'foobar']],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getResponseFormat
|
||||
*
|
||||
* Note this does *not* need to test formats being requested that are not
|
||||
* accepted by the server, because the routing system would have already
|
||||
* prevented those from reaching RequestHandler.
|
||||
*
|
||||
* @param string[] $methods
|
||||
* The HTTP methods to test.
|
||||
* @param string[] $supported_formats
|
||||
* The supported formats for the REST route to be tested.
|
||||
* @param string|false $request_format
|
||||
* The value for the ?_format URL query argument, if any.
|
||||
* @param string[] $request_headers
|
||||
* The request headers to send, if any.
|
||||
* @param string|null $request_body
|
||||
* The request body to send, if any.
|
||||
* @param string|null $expected_response_content_type
|
||||
* The expected MIME type of the response, if any.
|
||||
* @param string $expected_response_content
|
||||
* The expected content of the response.
|
||||
*
|
||||
* @dataProvider providerTestResponseFormat
|
||||
*/
|
||||
public function testResponseFormat($methods, array $supported_formats, $request_format, array $request_headers, $request_body, $expected_response_content_type, $expected_response_content) {
|
||||
$rest_config_name = $this->randomMachineName();
|
||||
|
||||
$parameters = [];
|
||||
if ($request_format !== FALSE) {
|
||||
$parameters['_format'] = $request_format;
|
||||
}
|
||||
|
||||
foreach ($request_headers as $key => $value) {
|
||||
unset($request_headers[$key]);
|
||||
$key = strtoupper(str_replace('-', '_', $key));
|
||||
$request_headers[$key] = $value;
|
||||
}
|
||||
|
||||
foreach ($methods as $method) {
|
||||
$request = Request::create('/rest/test', $method, $parameters, [], [], $request_headers, $request_body);
|
||||
$route_requirement_key_format = $request->isMethodSafe() ? '_format' : '_content_type_format';
|
||||
$route_match = new RouteMatch('test', new Route('/rest/test', ['_rest_resource_config' => $rest_config_name], [$route_requirement_key_format => implode('|', $supported_formats)]));
|
||||
|
||||
$resource = $this->prophesize(StubRequestHandlerResourcePlugin::class);
|
||||
|
||||
// Mock the configuration.
|
||||
$config = $this->prophesize(RestResourceConfigInterface::class);
|
||||
$config->getFormats($method)->willReturn($supported_formats);
|
||||
$config->getResourcePlugin()->willReturn($resource->reveal());
|
||||
$config->getCacheContexts()->willReturn([]);
|
||||
$config->getCacheTags()->willReturn([]);
|
||||
$config->getCacheMaxAge()->willReturn(12);
|
||||
$this->entityStorage->load($rest_config_name)->willReturn($config->reveal());
|
||||
|
||||
// Mock the resource plugin.
|
||||
$response = new ResourceResponse($method !== 'DELETE' ? ['REST' => 'Drupal'] : NULL);
|
||||
$resource->getPluginDefinition()->willReturn([]);
|
||||
$method_prophecy = new MethodProphecy($resource, strtolower($method), [Argument::any(), $request]);
|
||||
$method_prophecy->willReturn($response);
|
||||
$resource->addMethodProphecy($method_prophecy);
|
||||
|
||||
// Test the request handler.
|
||||
$handler_response = $this->requestHandler->handle($route_match, $request);
|
||||
$this->assertSame($expected_response_content_type, $handler_response->headers->get('Content-Type'));
|
||||
$this->assertEquals($expected_response_content, $handler_response->getContent());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* 0. methods to test
|
||||
* 1. supported formats for route requirements
|
||||
* 2. request format
|
||||
* 3. request headers
|
||||
* 4. request body
|
||||
* 5. expected response content type
|
||||
* 6. expected response body
|
||||
*/
|
||||
public function providerTestResponseFormat() {
|
||||
$json_encoded = Json::encode(['REST' => 'Drupal']);
|
||||
$xml_encoded = "<?xml version=\"1.0\"?>\n<response><REST>Drupal</REST></response>\n";
|
||||
|
||||
$safe_method_test_cases = [
|
||||
'safe methods: client requested format (JSON)' => [
|
||||
// @todo add 'HEAD' in https://www.drupal.org/node/2752325
|
||||
['GET'],
|
||||
['xml', 'json'],
|
||||
'json',
|
||||
[],
|
||||
NULL,
|
||||
'application/json',
|
||||
$json_encoded,
|
||||
],
|
||||
'safe methods: client requested format (XML)' => [
|
||||
// @todo add 'HEAD' in https://www.drupal.org/node/2752325
|
||||
['GET'],
|
||||
['xml', 'json'],
|
||||
'xml',
|
||||
[],
|
||||
NULL,
|
||||
'text/xml',
|
||||
$xml_encoded,
|
||||
],
|
||||
'safe methods: client requested no format: response should use the first configured format (JSON)' => [
|
||||
// @todo add 'HEAD' in https://www.drupal.org/node/2752325
|
||||
['GET'],
|
||||
['json', 'xml'],
|
||||
FALSE,
|
||||
[],
|
||||
NULL,
|
||||
'application/json',
|
||||
$json_encoded,
|
||||
],
|
||||
'safe methods: client requested no format: response should use the first configured format (XML)' => [
|
||||
// @todo add 'HEAD' in https://www.drupal.org/node/2752325
|
||||
['GET'],
|
||||
['xml', 'json'],
|
||||
FALSE,
|
||||
[],
|
||||
NULL,
|
||||
'text/xml',
|
||||
$xml_encoded,
|
||||
],
|
||||
];
|
||||
|
||||
$unsafe_method_bodied_test_cases = [
|
||||
'unsafe methods with response (POST, PATCH): client requested no format, response should use request body format (JSON)' => [
|
||||
['POST', 'PATCH'],
|
||||
['xml', 'json'],
|
||||
FALSE,
|
||||
['Content-Type' => 'application/json'],
|
||||
$json_encoded,
|
||||
'application/json',
|
||||
$json_encoded,
|
||||
],
|
||||
'unsafe methods with response (POST, PATCH): client requested no format, response should use request body format (XML)' => [
|
||||
['POST', 'PATCH'],
|
||||
['xml', 'json'],
|
||||
FALSE,
|
||||
['Content-Type' => 'text/xml'],
|
||||
$xml_encoded,
|
||||
'text/xml',
|
||||
$xml_encoded,
|
||||
],
|
||||
'unsafe methods with response (POST, PATCH): client requested format other than request body format (JSON): response format should use requested format (XML)' => [
|
||||
['POST', 'PATCH'],
|
||||
['xml', 'json'],
|
||||
'xml',
|
||||
['Content-Type' => 'application/json'],
|
||||
$json_encoded,
|
||||
'text/xml',
|
||||
$xml_encoded,
|
||||
],
|
||||
'unsafe methods with response (POST, PATCH): client requested format other than request body format (XML), but is allowed for the request body (JSON)' => [
|
||||
['POST', 'PATCH'],
|
||||
['xml', 'json'],
|
||||
'json',
|
||||
['Content-Type' => 'text/xml'],
|
||||
$xml_encoded,
|
||||
'application/json',
|
||||
$json_encoded,
|
||||
],
|
||||
];
|
||||
|
||||
$unsafe_method_bodyless_test_cases = [
|
||||
'unsafe methods with response bodies (DELETE): client requested no format, response should have no format' => [
|
||||
['DELETE'],
|
||||
['xml', 'json'],
|
||||
FALSE,
|
||||
['Content-Type' => 'application/json'],
|
||||
$json_encoded,
|
||||
NULL,
|
||||
'',
|
||||
],
|
||||
'unsafe methods with response bodies (DELETE): client requested format (XML), response should have no format' => [
|
||||
['DELETE'],
|
||||
['xml', 'json'],
|
||||
'xml',
|
||||
['Content-Type' => 'application/json'],
|
||||
$json_encoded,
|
||||
NULL,
|
||||
'',
|
||||
],
|
||||
'unsafe methods with response bodies (DELETE): client requested format (JSON), response should have no format' => [
|
||||
['DELETE'],
|
||||
['xml', 'json'],
|
||||
'json',
|
||||
['Content-Type' => 'application/json'],
|
||||
$json_encoded,
|
||||
NULL,
|
||||
'',
|
||||
],
|
||||
];
|
||||
|
||||
return $safe_method_test_cases + $unsafe_method_bodied_test_cases + $unsafe_method_bodyless_test_cases;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -341,9 +93,9 @@ class RequestHandlerTest extends KernelTestBase {
|
|||
*/
|
||||
class StubRequestHandlerResourcePlugin extends ResourceBase {
|
||||
|
||||
function get() {}
|
||||
function post() {}
|
||||
function patch() {}
|
||||
function delete() {}
|
||||
public function get() {}
|
||||
public function post() {}
|
||||
public function patch() {}
|
||||
public function delete() {}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Kernel;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests that REST type and relation link managers work as expected
|
||||
* @group rest
|
||||
*/
|
||||
class RestLinkManagerTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['serialization', 'rest', 'rest_test', 'system'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that type hooks work as expected.
|
||||
*/
|
||||
public function testRestLinkManagers() {
|
||||
\Drupal::moduleHandler()->invoke('rest', 'install');
|
||||
/* @var \Drupal\rest\LinkManager\TypeLinkManagerInterface $type_manager */
|
||||
$type_manager = \Drupal::service('rest.link_manager.type');
|
||||
$base = Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString();
|
||||
$link = $type_manager->getTypeUri('node', 'page');
|
||||
$this->assertEqual($link, $base . 'rest/type/node/page');
|
||||
// Now with optional context.
|
||||
$link = $type_manager->getTypeUri('node', 'page', ['rest_test' => TRUE]);
|
||||
$this->assertEqual($link, 'rest_test_type');
|
||||
|
||||
/* @var \Drupal\rest\LinkManager\RelationLinkManagerInterface $relation_manager */
|
||||
$relation_manager = \Drupal::service('rest.link_manager.relation');
|
||||
$link = $relation_manager->getRelationUri('node', 'page', 'field_ref');
|
||||
$this->assertEqual($link, $base . 'rest/relation/node/page/field_ref');
|
||||
// Now with optional context.
|
||||
$link = $relation_manager->getRelationUri('node', 'page', 'foobar', ['rest_test' => TRUE]);
|
||||
$this->assertEqual($link, 'rest_test_relation');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that type hooks work as expected even without install hook.
|
||||
*/
|
||||
public function testRestLinkManagersNoInstallHook() {
|
||||
/* @var \Drupal\rest\LinkManager\TypeLinkManagerInterface $type_manager */
|
||||
$type_manager = \Drupal::service('rest.link_manager.type');
|
||||
$base = Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString();
|
||||
$link = $type_manager->getTypeUri('node', 'page');
|
||||
$this->assertEqual($link, $base . 'rest/type/node/page');
|
||||
// Now with optional context.
|
||||
$link = $type_manager->getTypeUri('node', 'page', ['rest_test' => TRUE]);
|
||||
$this->assertEqual($link, 'rest_test_type');
|
||||
|
||||
/* @var \Drupal\rest\LinkManager\RelationLinkManagerInterface $relation_manager */
|
||||
$relation_manager = \Drupal::service('rest.link_manager.relation');
|
||||
$link = $relation_manager->getRelationUri('node', 'page', 'field_ref');
|
||||
$this->assertEqual($link, $base . 'rest/relation/node/page/field_ref');
|
||||
// Now with optional context.
|
||||
$link = $relation_manager->getRelationUri('node', 'page', 'foobar', ['rest_test' => TRUE]);
|
||||
$this->assertEqual($link, 'rest_test_relation');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests \Drupal\rest\LinkManager\LinkManager::setLinkDomain().
|
||||
*/
|
||||
public function testRestLinkManagersSetLinkDomain() {
|
||||
/* @var \Drupal\rest\LinkManager\LinkManager $link_manager */
|
||||
$link_manager = \Drupal::service('rest.link_manager');
|
||||
$link_manager->setLinkDomain('http://example.com/');
|
||||
$link = $link_manager->getTypeUri('node', 'page');
|
||||
$this->assertEqual($link, 'http://example.com/rest/type/node/page');
|
||||
$link = $link_manager->getRelationUri('node', 'page', 'field_ref');
|
||||
$this->assertEqual($link, 'http://example.com/rest/relation/node/page/field_ref');
|
||||
}
|
||||
|
||||
}
|
|
@ -39,18 +39,18 @@ class CollectRoutesTest extends UnitTestCase {
|
|||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->view = $this->getMock('\Drupal\views\Entity\View', array('initHandlers'), array(
|
||||
array('id' => 'test_view'),
|
||||
$this->view = $this->getMock('\Drupal\views\Entity\View', ['initHandlers'], [
|
||||
['id' => 'test_view'],
|
||||
'view',
|
||||
));
|
||||
]);
|
||||
|
||||
$view_executable = $this->getMock('\Drupal\views\ViewExecutable', array('initHandlers', 'getTitle'), array(), '', FALSE);
|
||||
$view_executable = $this->getMock('\Drupal\views\ViewExecutable', ['initHandlers', 'getTitle'], [], '', FALSE);
|
||||
$view_executable->expects($this->any())
|
||||
->method('getTitle')
|
||||
->willReturn('View title');
|
||||
|
||||
$view_executable->storage = $this->view;
|
||||
$view_executable->argument = array();
|
||||
$view_executable->argument = [];
|
||||
|
||||
$display_manager = $this->getMockBuilder('\Drupal\views\Plugin\ViewsPluginManager')
|
||||
->disableOriginalConstructor()
|
||||
|
@ -86,21 +86,21 @@ class CollectRoutesTest extends UnitTestCase {
|
|||
|
||||
\Drupal::setContainer($container);
|
||||
|
||||
$this->restExport = RestExport::create($container, array(), "test_routes", array());
|
||||
$this->restExport = RestExport::create($container, [], "test_routes", []);
|
||||
$this->restExport->view = $view_executable;
|
||||
|
||||
// Initialize a display.
|
||||
$this->restExport->display = array('id' => 'page_1');
|
||||
$this->restExport->display = ['id' => 'page_1'];
|
||||
|
||||
// Set the style option.
|
||||
$this->restExport->setOption('style', array('type' => 'serializer'));
|
||||
$this->restExport->setOption('style', ['type' => 'serializer']);
|
||||
|
||||
// Set the auth option.
|
||||
$this->restExport->setOption('auth', ['basic_auth']);
|
||||
|
||||
$display_manager->expects($this->once())
|
||||
->method('getDefinition')
|
||||
->will($this->returnValue(array('id' => 'test', 'provider' => 'test')));
|
||||
->will($this->returnValue(['id' => 'test', 'provider' => 'test']));
|
||||
|
||||
$none = $this->getMockBuilder('\Drupal\views\Plugin\views\access\None')
|
||||
->disableOriginalConstructor()
|
||||
|
@ -110,11 +110,11 @@ class CollectRoutesTest extends UnitTestCase {
|
|||
->method('createInstance')
|
||||
->will($this->returnValue($none));
|
||||
|
||||
$style_plugin = $this->getMock('\Drupal\rest\Plugin\views\style\Serializer', array('getFormats', 'init'), array(), '', FALSE);
|
||||
$style_plugin = $this->getMock('\Drupal\rest\Plugin\views\style\Serializer', ['getFormats', 'init'], [], '', FALSE);
|
||||
|
||||
$style_plugin->expects($this->once())
|
||||
->method('getFormats')
|
||||
->will($this->returnValue(array('json')));
|
||||
->will($this->returnValue(['json']));
|
||||
|
||||
$style_plugin->expects($this->once())
|
||||
->method('init')
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Unit;
|
||||
|
||||
use Drupal\Core\Entity\EntityConstraintViolationList;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\user\Entity\User;
|
||||
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
||||
use Symfony\Component\Validator\ConstraintViolationInterface;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
* @coversDefaultClass \Drupal\rest\Plugin\rest\resource\EntityResourceValidationTrait
|
||||
*/
|
||||
class EntityResourceValidationTraitTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @covers ::validate
|
||||
*/
|
||||
public function testValidate() {
|
||||
$trait = $this->getMockForTrait('Drupal\rest\Plugin\rest\resource\EntityResourceValidationTrait');
|
||||
|
||||
$method = new \ReflectionMethod($trait, 'validate');
|
||||
$method->setAccessible(TRUE);
|
||||
|
||||
$violations = $this->prophesize(EntityConstraintViolationList::class);
|
||||
$violations->filterByFieldAccess()->shouldBeCalled()->willReturn([]);
|
||||
$violations->count()->shouldBeCalled()->willReturn(0);
|
||||
|
||||
$entity = $this->prophesize(Node::class);
|
||||
$entity->validate()->shouldBeCalled()->willReturn($violations->reveal());
|
||||
|
||||
$method->invoke($trait, $entity->reveal());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::validate
|
||||
*/
|
||||
public function testFailedValidate() {
|
||||
$violation1 = $this->prophesize(ConstraintViolationInterface::class);
|
||||
$violation1->getPropertyPath()->willReturn('property_path');
|
||||
$violation1->getMessage()->willReturn('message');
|
||||
|
||||
$violation2 = $this->prophesize(ConstraintViolationInterface::class);
|
||||
$violation2->getPropertyPath()->willReturn('property_path');
|
||||
$violation2->getMessage()->willReturn('message');
|
||||
|
||||
$entity = $this->prophesize(User::class);
|
||||
|
||||
$violations = $this->getMockBuilder(EntityConstraintViolationList::class)
|
||||
->setConstructorArgs([$entity->reveal(), [$violation1->reveal(), $violation2->reveal()]])
|
||||
->setMethods(['filterByFieldAccess'])
|
||||
->getMock();
|
||||
|
||||
$violations->expects($this->once())
|
||||
->method('filterByFieldAccess')
|
||||
->will($this->returnValue([]));
|
||||
|
||||
$entity->validate()->willReturn($violations);
|
||||
|
||||
$trait = $this->getMockForTrait('Drupal\rest\Plugin\rest\resource\EntityResourceValidationTrait');
|
||||
|
||||
$method = new \ReflectionMethod($trait, 'validate');
|
||||
$method->setAccessible(TRUE);
|
||||
|
||||
$this->setExpectedException(UnprocessableEntityHttpException::class);
|
||||
|
||||
$method->invoke($trait, $entity->reveal());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,371 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Unit\EventSubscriber;
|
||||
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Core\Cache\CacheableResponseInterface;
|
||||
use Drupal\Core\Render\RenderContext;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Routing\RouteMatch;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\rest\EventSubscriber\ResourceResponseSubscriber;
|
||||
use Drupal\rest\ModifiedResourceResponse;
|
||||
use Drupal\rest\ResourceResponse;
|
||||
use Drupal\rest\ResourceResponseInterface;
|
||||
use Drupal\serialization\Encoder\JsonEncoder;
|
||||
use Drupal\serialization\Encoder\XmlEncoder;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Prophecy\Argument;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\rest\EventSubscriber\ResourceResponseSubscriber
|
||||
* @group rest
|
||||
*/
|
||||
class ResourceResponseSubscriberTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @covers ::onResponse
|
||||
* @dataProvider providerTestSerialization
|
||||
*/
|
||||
public function testSerialization($data, $expected_response = FALSE) {
|
||||
$request = new Request();
|
||||
$route_match = new RouteMatch('test', new Route('/rest/test', ['_rest_resource_config' => 'restplugin'], ['_format' => 'json']));
|
||||
|
||||
$handler_response = new ResourceResponse($data);
|
||||
$resource_response_subscriber = $this->getFunctioningResourceResponseSubscriber($route_match);
|
||||
$event = new FilterResponseEvent(
|
||||
$this->prophesize(HttpKernelInterface::class)->reveal(),
|
||||
$request,
|
||||
HttpKernelInterface::MASTER_REQUEST,
|
||||
$handler_response
|
||||
);
|
||||
$resource_response_subscriber->onResponse($event);
|
||||
|
||||
// Content is a serialized version of the data we provided.
|
||||
$this->assertEquals($expected_response !== FALSE ? $expected_response : Json::encode($data), $event->getResponse()->getContent());
|
||||
}
|
||||
|
||||
public function providerTestSerialization() {
|
||||
return [
|
||||
// The default data for \Drupal\rest\ResourceResponse.
|
||||
'default' => [NULL, ''],
|
||||
'empty string' => [''],
|
||||
'simple string' => ['string'],
|
||||
'complex string' => ['Complex \ string $%^&@ with unicode ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΣὨ'],
|
||||
'empty array' => [[]],
|
||||
'numeric array' => [['test']],
|
||||
'associative array' => [['test' => 'foobar']],
|
||||
'boolean true' => [TRUE],
|
||||
'boolean false' => [FALSE],
|
||||
// @todo Not supported. https://www.drupal.org/node/2427811
|
||||
// [new \stdClass()],
|
||||
// [(object) ['test' => 'foobar']],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getResponseFormat
|
||||
*
|
||||
* Note this does *not* need to test formats being requested that are not
|
||||
* accepted by the server, because the routing system would have already
|
||||
* prevented those from reaching the controller.
|
||||
*
|
||||
* @dataProvider providerTestResponseFormat
|
||||
*/
|
||||
public function testResponseFormat($methods, array $supported_formats, $request_format, array $request_headers, $request_body, $expected_response_format, $expected_response_content_type, $expected_response_content) {
|
||||
$parameters = [];
|
||||
if ($request_format !== FALSE) {
|
||||
$parameters['_format'] = $request_format;
|
||||
}
|
||||
|
||||
foreach ($request_headers as $key => $value) {
|
||||
unset($request_headers[$key]);
|
||||
$key = strtoupper(str_replace('-', '_', $key));
|
||||
$request_headers[$key] = $value;
|
||||
}
|
||||
|
||||
foreach ($methods as $method) {
|
||||
$request = Request::create('/rest/test', $method, $parameters, [], [], $request_headers, $request_body);
|
||||
$route_requirement_key_format = $request->isMethodSafe() ? '_format' : '_content_type_format';
|
||||
$route_match = new RouteMatch('test', new Route('/rest/test', ['_rest_resource_config' => $this->randomMachineName()], [$route_requirement_key_format => implode('|', $supported_formats)]));
|
||||
|
||||
$resource_response_subscriber = new ResourceResponseSubscriber(
|
||||
$this->prophesize(SerializerInterface::class)->reveal(),
|
||||
$this->prophesize(RendererInterface::class)->reveal(),
|
||||
$route_match
|
||||
);
|
||||
|
||||
$this->assertSame($expected_response_format, $resource_response_subscriber->getResponseFormat($route_match, $request));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::onResponse
|
||||
* @covers ::getResponseFormat
|
||||
* @covers ::renderResponseBody
|
||||
* @covers ::flattenResponse
|
||||
*
|
||||
* @dataProvider providerTestResponseFormat
|
||||
*/
|
||||
public function testOnResponseWithCacheableResponse($methods, array $supported_formats, $request_format, array $request_headers, $request_body, $expected_response_format, $expected_response_content_type, $expected_response_content) {
|
||||
$rest_config_name = $this->randomMachineName();
|
||||
|
||||
$parameters = [];
|
||||
if ($request_format !== FALSE) {
|
||||
$parameters['_format'] = $request_format;
|
||||
}
|
||||
|
||||
foreach ($request_headers as $key => $value) {
|
||||
unset($request_headers[$key]);
|
||||
$key = strtoupper(str_replace('-', '_', $key));
|
||||
$request_headers[$key] = $value;
|
||||
}
|
||||
|
||||
foreach ($methods as $method) {
|
||||
$request = Request::create('/rest/test', $method, $parameters, [], [], $request_headers, $request_body);
|
||||
$route_requirement_key_format = $request->isMethodSafe() ? '_format' : '_content_type_format';
|
||||
$route_match = new RouteMatch('test', new Route('/rest/test', ['_rest_resource_config' => $rest_config_name], [$route_requirement_key_format => implode('|', $supported_formats)]));
|
||||
|
||||
// The RequestHandler must return a ResourceResponseInterface object.
|
||||
$handler_response = new ResourceResponse($method !== 'DELETE' ? ['REST' => 'Drupal'] : NULL);
|
||||
$this->assertInstanceOf(ResourceResponseInterface::class, $handler_response);
|
||||
$this->assertInstanceOf(CacheableResponseInterface::class, $handler_response);
|
||||
|
||||
// The ResourceResponseSubscriber must then generate a response body and
|
||||
// transform it to a plain CacheableResponse object.
|
||||
$resource_response_subscriber = $this->getFunctioningResourceResponseSubscriber($route_match);
|
||||
$event = new FilterResponseEvent(
|
||||
$this->prophesize(HttpKernelInterface::class)->reveal(),
|
||||
$request,
|
||||
HttpKernelInterface::MASTER_REQUEST,
|
||||
$handler_response
|
||||
);
|
||||
$resource_response_subscriber->onResponse($event);
|
||||
$final_response = $event->getResponse();
|
||||
$this->assertNotInstanceOf(ResourceResponseInterface::class, $final_response);
|
||||
$this->assertInstanceOf(CacheableResponseInterface::class, $final_response);
|
||||
$this->assertSame($expected_response_content_type, $final_response->headers->get('Content-Type'));
|
||||
$this->assertEquals($expected_response_content, $final_response->getContent());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::onResponse
|
||||
* @covers ::getResponseFormat
|
||||
* @covers ::renderResponseBody
|
||||
* @covers ::flattenResponse
|
||||
*
|
||||
* @dataProvider providerTestResponseFormat
|
||||
*/
|
||||
public function testOnResponseWithUncacheableResponse($methods, array $supported_formats, $request_format, array $request_headers, $request_body, $expected_response_format, $expected_response_content_type, $expected_response_content) {
|
||||
$rest_config_name = $this->randomMachineName();
|
||||
|
||||
$parameters = [];
|
||||
if ($request_format !== FALSE) {
|
||||
$parameters['_format'] = $request_format;
|
||||
}
|
||||
|
||||
foreach ($request_headers as $key => $value) {
|
||||
unset($request_headers[$key]);
|
||||
$key = strtoupper(str_replace('-', '_', $key));
|
||||
$request_headers[$key] = $value;
|
||||
}
|
||||
|
||||
foreach ($methods as $method) {
|
||||
$request = Request::create('/rest/test', $method, $parameters, [], [], $request_headers, $request_body);
|
||||
$route_requirement_key_format = $request->isMethodSafe() ? '_format' : '_content_type_format';
|
||||
$route_match = new RouteMatch('test', new Route('/rest/test', ['_rest_resource_config' => $rest_config_name], [$route_requirement_key_format => implode('|', $supported_formats)]));
|
||||
|
||||
// The RequestHandler must return a ResourceResponseInterface object.
|
||||
$handler_response = new ModifiedResourceResponse($method !== 'DELETE' ? ['REST' => 'Drupal'] : NULL);
|
||||
$this->assertInstanceOf(ResourceResponseInterface::class, $handler_response);
|
||||
$this->assertNotInstanceOf(CacheableResponseInterface::class, $handler_response);
|
||||
|
||||
// The ResourceResponseSubscriber must then generate a response body and
|
||||
// transform it to a plain Response object.
|
||||
$resource_response_subscriber = $this->getFunctioningResourceResponseSubscriber($route_match);
|
||||
$event = new FilterResponseEvent(
|
||||
$this->prophesize(HttpKernelInterface::class)->reveal(),
|
||||
$request,
|
||||
HttpKernelInterface::MASTER_REQUEST,
|
||||
$handler_response
|
||||
);
|
||||
$resource_response_subscriber->onResponse($event);
|
||||
$final_response = $event->getResponse();
|
||||
$this->assertNotInstanceOf(ResourceResponseInterface::class, $final_response);
|
||||
$this->assertNotInstanceOf(CacheableResponseInterface::class, $final_response);
|
||||
$this->assertSame($expected_response_content_type, $final_response->headers->get('Content-Type'));
|
||||
$this->assertEquals($expected_response_content, $final_response->getContent());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* 0. methods to test
|
||||
* 1. supported formats for route requirements
|
||||
* 2. request format
|
||||
* 3. request headers
|
||||
* 4. request body
|
||||
* 5. expected response format
|
||||
* 6. expected response content type
|
||||
* 7. expected response body
|
||||
*/
|
||||
public function providerTestResponseFormat() {
|
||||
$json_encoded = Json::encode(['REST' => 'Drupal']);
|
||||
$xml_encoded = "<?xml version=\"1.0\"?>\n<response><REST>Drupal</REST></response>\n";
|
||||
|
||||
$safe_method_test_cases = [
|
||||
'safe methods: client requested format (JSON)' => [
|
||||
// @todo add 'HEAD' in https://www.drupal.org/node/2752325
|
||||
['GET'],
|
||||
['xml', 'json'],
|
||||
'json',
|
||||
[],
|
||||
NULL,
|
||||
'json',
|
||||
'application/json',
|
||||
$json_encoded,
|
||||
],
|
||||
'safe methods: client requested format (XML)' => [
|
||||
// @todo add 'HEAD' in https://www.drupal.org/node/2752325
|
||||
['GET'],
|
||||
['xml', 'json'],
|
||||
'xml',
|
||||
[],
|
||||
NULL,
|
||||
'xml',
|
||||
'text/xml',
|
||||
$xml_encoded,
|
||||
],
|
||||
'safe methods: client requested no format: response should use the first configured format (JSON)' => [
|
||||
// @todo add 'HEAD' in https://www.drupal.org/node/2752325
|
||||
['GET'],
|
||||
['json', 'xml'],
|
||||
FALSE,
|
||||
[],
|
||||
NULL,
|
||||
'json',
|
||||
'application/json',
|
||||
$json_encoded,
|
||||
],
|
||||
'safe methods: client requested no format: response should use the first configured format (XML)' => [
|
||||
// @todo add 'HEAD' in https://www.drupal.org/node/2752325
|
||||
['GET'],
|
||||
['xml', 'json'],
|
||||
FALSE,
|
||||
[],
|
||||
NULL,
|
||||
'xml',
|
||||
'text/xml',
|
||||
$xml_encoded,
|
||||
],
|
||||
];
|
||||
|
||||
$unsafe_method_bodied_test_cases = [
|
||||
'unsafe methods with response (POST, PATCH): client requested no format, response should use request body format (JSON)' => [
|
||||
['POST', 'PATCH'],
|
||||
['xml', 'json'],
|
||||
FALSE,
|
||||
['Content-Type' => 'application/json'],
|
||||
$json_encoded,
|
||||
'json',
|
||||
'application/json',
|
||||
$json_encoded,
|
||||
],
|
||||
'unsafe methods with response (POST, PATCH): client requested no format, response should use request body format (XML)' => [
|
||||
['POST', 'PATCH'],
|
||||
['xml', 'json'],
|
||||
FALSE,
|
||||
['Content-Type' => 'text/xml'],
|
||||
$xml_encoded,
|
||||
'xml',
|
||||
'text/xml',
|
||||
$xml_encoded,
|
||||
],
|
||||
'unsafe methods with response (POST, PATCH): client requested format other than request body format (JSON): response format should use requested format (XML)' => [
|
||||
['POST', 'PATCH'],
|
||||
['xml', 'json'],
|
||||
'xml',
|
||||
['Content-Type' => 'application/json'],
|
||||
$json_encoded,
|
||||
'xml',
|
||||
'text/xml',
|
||||
$xml_encoded,
|
||||
],
|
||||
'unsafe methods with response (POST, PATCH): client requested format other than request body format (XML), but is allowed for the request body (JSON)' => [
|
||||
['POST', 'PATCH'],
|
||||
['xml', 'json'],
|
||||
'json',
|
||||
['Content-Type' => 'text/xml'],
|
||||
$xml_encoded,
|
||||
'json',
|
||||
'application/json',
|
||||
$json_encoded,
|
||||
],
|
||||
];
|
||||
|
||||
$unsafe_method_bodyless_test_cases = [
|
||||
'unsafe methods with response bodies (DELETE): client requested no format, response should have no format' => [
|
||||
['DELETE'],
|
||||
['xml', 'json'],
|
||||
FALSE,
|
||||
['Content-Type' => 'application/json'],
|
||||
NULL,
|
||||
'xml',
|
||||
NULL,
|
||||
'',
|
||||
],
|
||||
'unsafe methods with response bodies (DELETE): client requested format (XML), response should have no format' => [
|
||||
['DELETE'],
|
||||
['xml', 'json'],
|
||||
'xml',
|
||||
['Content-Type' => 'application/json'],
|
||||
NULL,
|
||||
'xml',
|
||||
NULL,
|
||||
'',
|
||||
],
|
||||
'unsafe methods with response bodies (DELETE): client requested format (JSON), response should have no format' => [
|
||||
['DELETE'],
|
||||
['xml', 'json'],
|
||||
'json',
|
||||
['Content-Type' => 'application/json'],
|
||||
NULL,
|
||||
'json',
|
||||
NULL,
|
||||
'',
|
||||
],
|
||||
];
|
||||
|
||||
return $safe_method_test_cases + $unsafe_method_bodied_test_cases + $unsafe_method_bodyless_test_cases;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Drupal\rest\EventSubscriber\ResourceResponseSubscriber
|
||||
*/
|
||||
protected function getFunctioningResourceResponseSubscriber(RouteMatchInterface $route_match) {
|
||||
// Create a dummy of the renderer service.
|
||||
$renderer = $this->prophesize(RendererInterface::class);
|
||||
$renderer->executeInRenderContext(Argument::type(RenderContext::class), Argument::type('callable'))
|
||||
->will(function ($args) {
|
||||
$callable = $args[1];
|
||||
return $callable();
|
||||
});
|
||||
|
||||
// Instantiate the ResourceResponseSubscriber we will test.
|
||||
$resource_response_subscriber = new ResourceResponseSubscriber(
|
||||
new Serializer([], [new JsonEncoder(), new XmlEncoder()]),
|
||||
$renderer->reveal(),
|
||||
$route_match
|
||||
);
|
||||
|
||||
return $resource_response_subscriber;
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue