Move all files to 2017/

This commit is contained in:
Oliver Davies 2025-09-29 22:25:17 +01:00
parent ac7370f67f
commit 2875863330
15717 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,59 @@
<?php
/**
* @file
* Contains database additions to drupal-8.bare.standard.php.gz for testing the
* upgrade path of rest_update_8201().
*/
use Drupal\Core\Database\Database;
$connection = Database::getConnection();
// Set the schema version.
$connection->insert('key_value')
->fields([
'collection' => 'system.schema',
'name' => 'rest',
'value' => 'i:8000;',
])
->execute();
// Update core.extension.
$extensions = $connection->select('config')
->fields('config', ['data'])
->condition('collection', '')
->condition('name', 'core.extension')
->execute()
->fetchField();
$extensions = unserialize($extensions);
$extensions['module']['basic_auth'] = 0;
$extensions['module']['rest'] = 0;
$extensions['module']['serialization'] = 0;
$connection->update('config')
->fields([
'data' => serialize($extensions),
])
->condition('collection', '')
->condition('name', 'core.extension')
->execute();
// Install the rest configuration.
$config = [
'resources' => [
'entity:node' => [
'GET' => [
'supported_formats' => ['json'],
'supported_auth' => ['basic_auth'],
],
],
],
'link_domain' => NULL,
];
$data = $connection->insert('config')
->fields([
'name' => 'rest.settings',
'data' => serialize($config),
'collection' => '',
])
->execute();

View file

@ -0,0 +1,58 @@
<?php
/**
* @file
* Contains database additions to drupal-8.bare.standard.php.gz for testing the
* upgrade path of rest_update_8203().
*/
use Drupal\Core\Database\Database;
$connection = Database::getConnection();
// Set the schema version.
$connection->insert('key_value')
->fields([
'collection' => 'system.schema',
'name' => 'rest',
'value' => 'i:8000;',
])
->execute();
// Update core.extension.
$extensions = $connection->select('config')
->fields('config', ['data'])
->condition('collection', '')
->condition('name', 'core.extension')
->execute()
->fetchField();
$extensions = unserialize($extensions);
$extensions['module']['rest'] = 0;
$extensions['module']['serialization'] = 0;
$connection->update('config')
->fields([
'data' => serialize($extensions),
])
->condition('collection', '')
->condition('name', 'core.extension')
->execute();
// Install the rest configuration.
$config = [
'resources' => [
'entity:node' => [
'GET' => [
'supported_formats' => ['json'],
'supported_auth' => ['basic_auth'],
],
],
],
'link_domain' => NULL,
];
$data = $connection->insert('config')
->fields([
'name' => 'rest.settings',
'data' => serialize($config),
'collection' => '',
])
->execute();

View file

@ -0,0 +1,63 @@
<?php
/**
* @file
* Test fixture for \Drupal\Tests\rest\Functional\Update\RestExportAuthCorrectionUpdateTest.
*/
use Drupal\Core\Database\Database;
use Drupal\Core\Serialization\Yaml;
$connection = Database::getConnection();
// Set the schema version.
$connection->insert('key_value')
->fields([
'collection' => 'system.schema',
'name' => 'rest',
'value' => 'i:8000;',
])
->execute();
// Update core.extension.
$extensions = $connection->select('config')
->fields('config', ['data'])
->condition('collection', '')
->condition('name', 'core.extension')
->execute()
->fetchField();
$extensions = unserialize($extensions);
$extensions['module']['rest'] = 0;
$extensions['module']['serialization'] = 0;
$extensions['module']['basic_auth'] = 0;
$connection->update('config')
->fields([
'data' => serialize($extensions),
])
->condition('collection', '')
->condition('name', 'core.extension')
->execute();
$connection->insert('config')
->fields([
'name' => 'rest.settings',
'data' => serialize([
'link_domain' => '~',
]),
'collection' => '',
])
->execute();
$connection->insert('config')
->fields([
'name' => 'views.view.rest_export_with_authorization_correction',
])
->execute();
$connection->merge('config')
->condition('name', 'views.view.rest_export_with_authorization_correction')
->condition('collection', '')
->fields([
'data' => serialize(Yaml::decode(file_get_contents('core/modules/views/tests/modules/views_test_config/test_views/views.view.rest_export_with_authorization_correction.yml'))),
])
->execute();

View file

@ -0,0 +1,65 @@
<?php
/**
* @file
* Test fixture for \Drupal\rest\Tests\Update\RestExportAuthUpdateTest.
*/
use Drupal\Core\Database\Database;
use Drupal\Core\Serialization\Yaml;
$connection = Database::getConnection();
$config = $connection;
// Set the schema version.
$connection->insert('key_value')
->fields([
'collection' => 'system.schema',
'name' => 'rest',
'value' => 'i:8000;',
])
->execute();
// Update core.extension.
$extensions = $connection->select('config')
->fields('config', ['data'])
->condition('collection', '')
->condition('name', 'core.extension')
->execute()
->fetchField();
$extensions = unserialize($extensions);
$extensions['module']['rest'] = 0;
$extensions['module']['serialization'] = 0;
$extensions['module']['basic_auth'] = 0;
$connection->update('config')
->fields([
'data' => serialize($extensions),
])
->condition('collection', '')
->condition('name', 'core.extension')
->execute();
$config = [
'link_domain' => '~',
];
$data = $connection->insert('config')
->fields([
'name' => 'rest.settings',
'data' => serialize($config),
'collection' => '',
])
->execute();
$connection->insert('config')
->fields([
'name' => 'views.view.rest_export_with_authorization',
])
->execute();
$connection->merge('config')
->condition('name', 'views.view.rest_export_with_authorization')
->condition('collection', '')
->fields([
'data' => serialize(Yaml::decode(file_get_contents('core/modules/views/tests/modules/views_test_config/test_views/views.view.rest_export_with_authorization.yml'))),
])
->execute();

View file

@ -0,0 +1,32 @@
id: entity.comment
plugin_id: 'entity:comment'
granularity: method
configuration:
GET:
supported_formats:
- hal_json
# This resource has a method-specific format.
# @see \Drupal\rest\Tests\Update\ResourceGranularityUpdateTest
- xml
supported_auth:
- basic_auth
POST:
supported_formats:
- hal_json
supported_auth:
- basic_auth
PATCH:
supported_formats:
- hal_json
supported_auth:
- basic_auth
DELETE:
supported_formats:
- hal_json
supported_auth:
- basic_auth
dependencies:
module:
- node
- basic_auth
- hal

View file

@ -0,0 +1,29 @@
id: entity.node
plugin_id: 'entity:node'
granularity: method
configuration:
GET:
supported_formats:
- hal_json
supported_auth:
- basic_auth
POST:
supported_formats:
- hal_json
supported_auth:
- basic_auth
PATCH:
supported_formats:
- hal_json
supported_auth:
- basic_auth
DELETE:
supported_formats:
- hal_json
supported_auth:
- basic_auth
dependencies:
module:
- node
- basic_auth
- hal

View file

@ -0,0 +1,32 @@
id: entity.user
plugin_id: 'entity:user'
granularity: method
configuration:
GET:
supported_formats:
- hal_json
supported_auth:
- basic_auth
# This resource has a method-specific authentication.
# @see \Drupal\rest\Tests\Update\ResourceGranularityUpdateTest
- oauth
POST:
supported_formats:
- hal_json
supported_auth:
- basic_auth
PATCH:
supported_formats:
- hal_json
supported_auth:
- basic_auth
DELETE:
supported_formats:
- hal_json
supported_auth:
- basic_auth
dependencies:
module:
- node
- basic_auth
- hal

View file

@ -0,0 +1,7 @@
name: 'Configuration test REST'
type: module
package: Testing
version: VERSION
core: 8.x
dependencies:
- drupal:config_test

View file

@ -0,0 +1,30 @@
<?php
/**
* @file
* Contains hook implementations for testing REST module.
*/
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Session\AccountInterface;
/**
* Implements hook_entity_type_alter().
*/
function config_test_rest_entity_type_alter(array &$entity_types) {
// Undo part of what config_test_entity_type_alter() did: remove this
// config_test_no_status entity type, because it uses the same entity class as
// the config_test entity type, which makes REST deserialization impossible.
unset($entity_types['config_test_no_status']);
}
/**
* Implements hook_ENTITY_TYPE_access().
*/
function config_test_rest_config_test_access(EntityInterface $entity, $operation, AccountInterface $account) {
// Add permission, so that EntityResourceTestBase's scenarios can test access
// being denied. By default, all access is always allowed for the config_test
// config entity.
return AccessResult::forbiddenIf(!$account->hasPermission('view config_test'))->cachePerPermissions();
}

View file

@ -0,0 +1,2 @@
view config_test:
title: 'View ConfigTest entities'

View file

@ -0,0 +1,6 @@
name: 'REST test'
type: module
description: 'Provides test hooks and resources for REST module.'
package: Testing
version: VERSION
core: 8.x

View file

@ -0,0 +1,71 @@
<?php
/**
* @file
* Contains hook implementations for testing REST module.
*/
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Access\AccessResult;
/**
* Implements hook_entity_field_access().
*
* @see \Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase::setUp()
*/
function rest_test_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
// @see \Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase::testPost()
// @see \Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase::testPatch()
if ($field_definition->getName() === 'field_rest_test') {
switch ($operation) {
case 'view':
// Never ever allow this field to be viewed: this lets
// EntityResourceTestBase::testGet() test in a "vanilla" way.
return AccessResult::forbidden();
case 'edit':
return AccessResult::forbidden();
}
}
// @see \Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase::testGet()
// @see \Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase::testPatch()
if ($field_definition->getName() === 'field_rest_test_multivalue') {
switch ($operation) {
case 'view':
// Never ever allow this field to be viewed: this lets
// EntityResourceTestBase::testGet() test in a "vanilla" way.
return AccessResult::forbidden();
}
}
// @see \Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase::testGet()
// @see \Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase::testPatch()
if ($field_definition->getName() === 'rest_test_validation') {
switch ($operation) {
case 'view':
// Never ever allow this field to be viewed: this lets
// EntityResourceTestBase::testGet() test in a "vanilla" way.
return AccessResult::forbidden();
}
}
// No opinion.
return AccessResult::neutral();
}
/**
* Implements hook_entity_base_field_info().
*/
function rest_test_entity_base_field_info(EntityTypeInterface $entity_type) {
$fields = [];
$fields['rest_test_validation'] = BaseFieldDefinition::create('string')
->setLabel(t('REST test validation field'))
->setDescription(t('A text field with some special validations attached used for testing purposes'))
->addConstraint('rest_test_validation');
return $fields;
}

View file

@ -0,0 +1,18 @@
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 }
rest_test.page_cache_request_policy.deny_test_auth_requests:
class: Drupal\rest_test\PageCache\RequestPolicy\DenyTestAuthRequests
public: false
tags:
- { name: page_cache_request_policy }
rest_test.encoder.foobar:
class: Drupal\serialization\Encoder\JsonEncoder
tags:
- { name: encoder, format: foobar }

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace Drupal\rest_test\PageCache\RequestPolicy;
use Drupal\Core\PageCache\RequestPolicyInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Cache policy for pages requested with REST Test Auth.
*
* This policy disallows caching of requests that use the REST Test Auth
* authentication provider for security reasons (just like basic_auth).
* Otherwise responses for authenticated requests can get into the page cache
* and could be delivered to unprivileged users.
*
* @see \Drupal\rest_test\Authentication\Provider\TestAuth
* @see \Drupal\rest_test\Authentication\Provider\TestAuthGlobal
* @see \Drupal\basic_auth\PageCache\DisallowBasicAuthRequests
*/
class DenyTestAuthRequests implements RequestPolicyInterface {
/**
* {@inheritdoc}
*/
public function check(Request $request) {
if ($request->headers->has('REST-test-auth') || $request->headers->has('REST-test-auth-global')) {
return self::DENY;
}
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace Drupal\rest_test\Plugin\Validation\Constraint;
use Symfony\Component\Validator\Constraint;
/**
* Adds some validations for a REST test field.
*
* @Constraint(
* id = "rest_test_validation",
* label = @Translation("REST test validation", context = "Validation")
* )
*
* @see \Drupal\Core\TypedData\OptionsProviderInterface
*/
class RestTestConstraint extends Constraint {
public $message = 'REST test validation failed';
}

View file

@ -0,0 +1,26 @@
<?php
namespace Drupal\rest_test\Plugin\Validation\Constraint;
use Drupal\Core\Field\FieldItemListInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
/**
* Validator for \Drupal\rest_test\Plugin\Validation\Constraint\RestTestConstraint.
*/
class RestTestConstraintValidator extends ConstraintValidator {
/**
* {@inheritdoc}
*/
public function validate($value, Constraint $constraint) {
if ($value instanceof FieldItemListInterface) {
$value = $value->getValue();
if (!empty($value[0]['value']) && $value[0]['value'] === 'ALWAYS_FAIL') {
$this->context->addViolation($constraint->message);
}
}
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace Drupal\rest_test\Plugin\rest\resource;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
/**
* Class used to test that serialization_class is optional.
*
* @RestResource(
* id = "serialization_test",
* label = @Translation("Optional serialization_class"),
* serialization_class = "",
* uri_paths = {}
* )
*/
class NoSerializationClassTestResource extends ResourceBase {
/**
* Responds to a POST request.
*
* @param array $data
* An array with the payload.
*
* @return \Drupal\rest\ResourceResponse
*/
public function post(array $data) {
return new ResourceResponse($data);
}
}

View file

@ -0,0 +1,9 @@
name: 'REST test views'
type: module
description: 'Provides default views for views REST tests.'
package: Testing
version: VERSION
core: 8.x
dependencies:
- drupal:rest
- drupal:views

View file

@ -0,0 +1,21 @@
<?php
/**
* @file
* Test hook implementations for the REST views test module.
*/
use Drupal\views\ViewExecutable;
/**
* Implements hook_views_post_execute().
*/
function rest_test_views_views_post_execute(ViewExecutable $view) {
// Attach a custom header to the test_data_export view.
if ($view->id() === 'test_serializer_display_entity') {
if ($value = \Drupal::state()->get('rest_test_views_set_header', FALSE)) {
$view->getResponse()->headers->set('Custom-Header', $value);
}
}
}

View file

@ -0,0 +1,277 @@
langcode: en
status: true
dependencies:
config:
- node.type.article
module:
- node
- rest
- user
id: test_excluded_field_token_display
label: 'Test Excluded Field Token Display'
module: views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: 0
display_options:
access:
type: perm
options:
perm: 'access content'
cache:
type: tag
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: mini
options:
items_per_page: 10
offset: 0
id: 0
total_pages: null
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
tags:
previous:
next:
style:
type: serializer
row:
type: fields
options:
inline: { }
separator: ''
hide_empty: false
default_field_elements: true
fields:
title:
id: title
table: node_field_data
field: title
relationship: none
group_type: group
admin_label: ''
label: ''
exclude: true
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: false
ellipsis: false
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: false
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
click_sort_column: value
type: string
settings:
link_to_entity: false
group_column: value
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
entity_type: node
entity_field: title
plugin_id: field
nothing:
id: nothing
table: views
field: nothing
relationship: none
group_type: group
admin_label: ''
label: ''
exclude: false
alter:
alter_text: true
text: '{{ title }}'
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: false
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: false
plugin_id: custom
filters:
status:
value: '1'
table: node_field_data
field: status
plugin_id: boolean
entity_type: node
entity_field: status
id: status
expose:
operator: ''
group: 1
type:
id: type
table: node_field_data
field: type
value:
article: article
entity_type: node
entity_field: type
plugin_id: bundle
sorts:
nid:
id: nid
table: node_field_data
field: nid
order: DESC
entity_type: node
entity_field: nid
plugin_id: standard
relationship: none
group_type: group
admin_label: ''
exposed: false
expose:
label: ''
header: { }
footer: { }
empty: { }
relationships: { }
arguments: { }
display_extenders: { }
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- request_format
- url.query_args
- 'user.node_grants:view'
- user.permissions
tags: { }
rest_export_1:
display_plugin: rest_export
id: rest_export_1
display_title: 'REST export'
position: 1
display_options:
display_extenders: { }
path: rest/test/excluded-field-token
pager:
type: some
options:
items_per_page: 10
offset: 0
style:
type: serializer
options:
formats:
json: json
row:
type: data_field
options:
field_options:
title:
alias: ''
raw_output: false
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- request_format
- 'user.node_grants:view'
- user.permissions
tags: { }

View file

@ -0,0 +1,55 @@
langcode: en
status: true
dependencies:
module:
- rest
- user
id: test_serializer_display_entity
label: 'Test serialize display entity rows'
module: rest
description: ''
tag: ''
base_table: entity_test
base_field: id
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: null
display_options:
access:
type: perm
options:
perm: 'access content'
cache:
type: tag
query:
type: views_query
exposed_form:
type: basic
style:
type: serializer
row:
type: data_entity
sorts:
id:
id: standard
table: entity_test
field: id
order: DESC
plugin_id: date
entity_type: entity_test
entity_field: id
title: 'Test serialize'
arguments: { }
rest_export_1:
display_plugin: rest_export
id: rest_export_1
display_title: serializer
position: null
display_options:
defaults:
access: false
path: test/serialize/entity

View file

@ -0,0 +1,47 @@
langcode: en
status: true
dependencies:
module:
- entity_test
- rest
id: test_serializer_display_entity_translated
label: 'Test serialize translated entity rows'
module: rest
description: ''
tag: ''
base_table: entity_test_mul_property_data
base_field: id
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: null
display_options:
access:
type: perm
options:
perm: 'access content'
cache:
type: tag
query:
type: views_query
exposed_form:
type: basic
style:
type: serializer
row:
type: data_entity
title: 'Test serialize translated entity rows'
rendering_language: '***LANGUAGE_entity_translation***'
arguments: { }
rest_export_1:
display_plugin: rest_export
id: rest_export_1
display_title: serializer
position: null
display_options:
defaults:
access: false
path: test/serialize/translated_entity

View file

@ -0,0 +1,110 @@
langcode: en
status: true
dependencies:
module:
- rest
- user
id: test_serializer_display_field
label: 'Test serializer display field rows'
module: rest
description: ''
tag: ''
base_table: views_test_data
base_field: id
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: null
display_options:
access:
type: perm
options:
perm: 'access content'
cache:
type: tag
query:
type: views_query
exposed_form:
type: basic
style:
type: serializer
row:
type: data_field
fields:
name:
id: name
table: views_test_data
field: name
label: ''
plugin_id: string
nothing:
id: nothing
table: views
field: nothing
relationship: none
group_type: group
admin_label: ''
label: 'Custom text'
exclude: false
alter:
alter_text: true
text: TEST
plugin_id: custom
created:
id: created
table: views_test_data
field: created
type: timestamp
settings:
date_format: medium
custom_date_format: ''
timezone: ''
plugin_id: field
sorts:
created:
id: created
table: views_test_data
field: created
order: DESC
plugin_id: date
title: 'Test serialize'
arguments: { }
rest_export_1:
display_plugin: rest_export
id: rest_export_1
display_title: serializer
position: null
display_options:
defaults:
access: false
style: false
row: false
path: test/serialize/field
access:
type: none
style:
type: serializer
row:
type: data_field
rest_export_2:
display_plugin: rest_export
id: rest_export_2
display_title: 'serialize - access denied'
position: null
display_options:
defaults:
access: false
style: false
row: false
path: test/serialize/denied
access:
type: perm
options:
perm: 'administer views'
style:
type: serializer
row:
type: data_field

View file

@ -0,0 +1,172 @@
langcode: en
status: true
dependencies:
config:
- field.storage.node.body
module:
- field
- node
- rest
- rest_test_views
- user
id: test_serializer_node_display_field
label: 'Test serializer display field rows for entity fields'
module: rest_test_views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: null
display_options:
access:
type: perm
options:
perm: 'administer views'
cache:
type: tag
query:
type: views_query
exposed_form:
type: basic
style:
type: serializer
row:
type: data_field
fields:
nid:
id: nid
table: node_field_data
field: nid
plugin_id: field
entity_type: node
entity_field: nid
title:
id: title
table: node_field_data
field: title
label: Title
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
entity_type: node
entity_field: title
type: string
settings:
link_to_entity: true
plugin_id: field
body:
id: body
table: node__body
field: body
relationship: none
group_type: group
admin_label: ''
label: Body
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
click_sort_column: value
type: text_default
settings: { }
group_column: value
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
plugin_id: field
entity_type: node
entity_field: body
title: 'Test serialize'
arguments: { }
rest_export_1:
display_plugin: rest_export
id: rest_export_1
display_title: serializer
position: null
display_options:
defaults:
access: false
style: false
row: false
path: test/serialize/node-field
access:
type: none
style:
type: serializer
row:
type: data_field
rest_export_2:
display_plugin: rest_export
id: rest_export_2
display_title: 'REST export 2'
position: 2
display_options:
display_extenders: { }
auth:
basic_auth: basic_auth
path: test/serialize/auth_with_perm
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- request_format
- 'user.node_grants:view'
- user.permissions
tags:
- 'config:field.storage.node.body'

View file

@ -0,0 +1,172 @@
langcode: en
status: true
dependencies:
config:
- field.storage.node.body
module:
- field
- node
- rest
- rest_test_views
- user
id: test_serializer_node_exposed_filter
label: 'Test serializer display for exposed filters'
module: rest_test_views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: null
display_options:
access:
type: perm
options:
perm: 'access content'
cache:
type: tag
query:
type: views_query
exposed_form:
type: basic
style:
type: serializer
row:
type: data_field
fields:
nid:
id: nid
table: node_field_data
field: nid
plugin_id: field
entity_type: node
entity_field: nid
body:
id: body
table: node__body
field: body
relationship: none
group_type: group
admin_label: ''
label: Body
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
click_sort_column: value
type: text_default
settings: { }
group_column: value
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
plugin_id: field
entity_type: node
entity_field: body
filters:
title:
id: title
table: node_field_data
field: title
relationship: none
group_type: group
admin_label: ''
operator: starts
value: ''
group: 1
exposed: true
expose:
operator_id: title_op
label: Title
description: ''
use_operator: false
operator: title_op
identifier: title
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
entity_type: node
entity_field: title
plugin_id: string
title: 'Test serialize'
arguments: { }
rest_export_1:
display_plugin: rest_export
id: rest_export_1
display_title: serializer
position: null
display_options:
defaults:
access: false
style: false
row: false
path: test/serialize/node-exposed-filter
access:
type: none
style:
type: serializer
row:
type: data_field

View file

@ -0,0 +1,70 @@
langcode: en
status: true
dependencies:
module:
- rest
- user
id: test_serializer_shared_path
label: 'Test serializer shared path'
module: rest
description: ''
tag: ''
base_table: entity_test
base_field: id
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: null
display_options:
access:
type: perm
options:
perm: 'access content'
cache:
type: tag
query:
type: views_query
exposed_form:
type: basic
style:
type: serializer
row:
type: data_entity
sorts:
id:
id: standard
table: entity_test
field: id
order: DESC
plugin_id: date
entity_type: entity_test
entity_field: id
title: 'Test serialize'
arguments: { }
rest_export_1:
display_plugin: rest_export
id: rest_export_1
display_title: serializer
position: null
display_options:
defaults:
access: false
path: test/serialize/shared
page_1:
display_plugin: page
id: page_1
display_title: page
position: null
display_options:
defaults:
access: false
style: false
row: false
style:
type: default
row:
type: entity:entity_test
path: test/serialize/shared

View file

@ -0,0 +1,37 @@
<?php
namespace Drupal\Tests\rest\Functional;
use Drupal\Core\Url;
use Psr\Http\Message\ResponseInterface;
/**
* Trait for ResourceTestBase subclasses testing $auth=NULL, i.e. authless/anon.
*
* Characteristics:
* - When no authentication provider is being used, there also cannot be any
* particular error response for missing authentication, since by definition
* there is not any authentication.
* - For the same reason, there are no authentication edge cases to test.
* - Because no authentication is required, this is vulnerable to CSRF attacks
* by design. Hence a REST resource should probably only allow for anonymous
* for safe (GET/HEAD) HTTP methods, and only with extreme care should unsafe
* (POST/PATCH/DELETE) HTTP methods be allowed for a REST resource that allows
* anonymous access.
*/
trait AnonResourceTestTrait {
/**
* {@inheritdoc}
*/
protected function assertResponseWhenMissingAuthentication($method, ResponseInterface $response) {
throw new \LogicException('When testing for anonymous users, authentication cannot be missing.');
}
/**
* {@inheritdoc}
*/
protected function assertAuthenticationEdgeCases($method, Url $url, array $request_options) {
}
}

View file

@ -0,0 +1,49 @@
<?php
namespace Drupal\Tests\rest\Functional;
use Drupal\Core\Url;
use Psr\Http\Message\ResponseInterface;
/**
* Trait for ResourceTestBase subclasses testing $auth=basic_auth.
*
* Characteristics:
* - Every request must send an Authorization header.
* - When accessing a URI that requires authentication without being
* authenticated, a 401 response must be sent.
* - Because every request must send an authorization, there is no danger of
* CSRF attacks.
*
* @see \Drupal\Tests\rest\Functional\BasicAuthResourceWithInterfaceTranslationTestTrait
*/
trait BasicAuthResourceTestTrait {
/**
* {@inheritdoc}
*/
protected function getAuthenticationRequestOptions($method) {
return [
'headers' => [
'Authorization' => 'Basic ' . base64_encode($this->account->name->value . ':' . $this->account->passRaw),
],
];
}
/**
* {@inheritdoc}
*/
protected function assertResponseWhenMissingAuthentication($method, ResponseInterface $response) {
$expected_page_cache_header_value = $method === 'GET' ? 'MISS' : FALSE;
// @see \Drupal\basic_auth\Authentication\Provider\BasicAuth::challengeException()
$expected_dynamic_page_cache_header_value = $expected_page_cache_header_value;
$this->assertResourceErrorResponse(401, 'No authentication credentials provided.', $response, ['4xx-response', 'config:system.site', 'config:user.role.anonymous', 'http_response'], ['user.roles:anonymous'], $expected_page_cache_header_value, $expected_dynamic_page_cache_header_value);
}
/**
* {@inheritdoc}
*/
protected function assertAuthenticationEdgeCases($method, Url $url, array $request_options) {
}
}

View file

@ -0,0 +1,28 @@
<?php
namespace Drupal\Tests\rest\Functional;
use Psr\Http\Message\ResponseInterface;
/**
* Trait for ResourceTestBase subclasses testing $auth=basic_auth + 'language'.
*
* @see \Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait
*/
trait BasicAuthResourceWithInterfaceTranslationTestTrait {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
protected function assertResponseWhenMissingAuthentication($method, ResponseInterface $response) {
// Because BasicAuth::challengeException() relies on the 'system.site'
// configuration, and this test installs the 'language' module, all config
// may be translated and therefore gets the 'languages:language_interface'
// cache context.
$expected_page_cache_header_value = $method === 'GET' ? 'MISS' : FALSE;
$this->assertResourceErrorResponse(401, 'No authentication credentials provided.', $response, ['4xx-response', 'config:system.site', 'config:user.role.anonymous', 'http_response'], ['languages:language_interface', 'user.roles:anonymous'], $expected_page_cache_header_value, $expected_page_cache_header_value);
}
}

View file

@ -0,0 +1,43 @@
<?php
namespace Drupal\Tests\rest\Functional;
/**
* Trait for ResourceTestBase subclasses formatting expected timestamp data.
*/
trait BcTimestampNormalizerUnixTestTrait {
/**
* Formats a UNIX timestamp.
*
* Depending on the 'bc_timestamp_normalizer_unix' setting. The return will be
* an RFC3339 date string or the same timestamp that was passed in.
*
* @param int $timestamp
* The timestamp value to format.
*
* @return string|int
* The formatted RFC3339 date string or UNIX timestamp.
*
* @see \Drupal\serialization\Normalizer\TimestampItemNormalizer
*/
protected function formatExpectedTimestampItemValues($timestamp) {
// If the setting is enabled, just return the timestamp as-is now.
if ($this->config('serialization.settings')->get('bc_timestamp_normalizer_unix')) {
return ['value' => $timestamp];
}
// Otherwise, format the date string to the same that
// \Drupal\serialization\Normalizer\TimestampItemNormalizer will produce.
$date = new \DateTime();
$date->setTimestamp($timestamp);
$date->setTimezone(new \DateTimeZone('UTC'));
// Format is also added to the expected return values.
return [
'value' => $date->format(\DateTime::RFC3339),
'format' => \DateTime::RFC3339,
];
}
}

View file

@ -0,0 +1,147 @@
<?php
namespace Drupal\Tests\rest\Functional;
use Drupal\Core\Url;
use GuzzleHttp\RequestOptions;
use Psr\Http\Message\ResponseInterface;
/**
* Trait for ResourceTestBase subclasses testing $auth=cookie.
*
* Characteristics:
* - After performing a valid "log in" request, the server responds with a 2xx
* status code and a 'Set-Cookie' response header. This cookie is what
* continues to identify the user in subsequent requests.
* - When accessing a URI that requires authentication without being
* authenticated, a standard 403 response must be sent.
* - Because of the reliance on cookies, and the fact that user agents send
* cookies with every request, this is vulnerable to CSRF attacks. To mitigate
* this, the response for the "log in" request contains a CSRF token that must
* be sent with every unsafe (POST/PATCH/DELETE) HTTP request.
*/
trait CookieResourceTestTrait {
/**
* The session cookie.
*
* @see ::initAuthentication
*
* @var string
*/
protected $sessionCookie;
/**
* The CSRF token.
*
* @see ::initAuthentication
*
* @var string
*/
protected $csrfToken;
/**
* The logout token.
*
* @see ::initAuthentication
*
* @var string
*/
protected $logoutToken;
/**
* {@inheritdoc}
*/
protected function initAuthentication() {
$user_login_url = Url::fromRoute('user.login.http')
->setRouteParameter('_format', static::$format);
$request_body = [
'name' => $this->account->name->value,
'pass' => $this->account->passRaw,
];
$request_options[RequestOptions::BODY] = $this->serializer->encode($request_body, static::$format);
$request_options[RequestOptions::HEADERS] = [
'Content-Type' => static::$mimeType,
];
$response = $this->request('POST', $user_login_url, $request_options);
// Parse and store the session cookie.
$this->sessionCookie = explode(';', $response->getHeader('Set-Cookie')[0], 2)[0];
// Parse and store the CSRF token and logout token.
$data = $this->serializer->decode((string) $response->getBody(), static::$format);
$this->csrfToken = $data['csrf_token'];
$this->logoutToken = $data['logout_token'];
}
/**
* {@inheritdoc}
*/
protected function getAuthenticationRequestOptions($method) {
$request_options[RequestOptions::HEADERS]['Cookie'] = $this->sessionCookie;
// @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
if (!in_array($method, ['HEAD', 'GET', 'OPTIONS', 'TRACE'])) {
$request_options[RequestOptions::HEADERS]['X-CSRF-Token'] = $this->csrfToken;
}
return $request_options;
}
/**
* {@inheritdoc}
*/
protected function assertResponseWhenMissingAuthentication($method, ResponseInterface $response) {
// Requests needing cookie authentication but missing it results in a 403
// response. The cookie authentication mechanism sets no response message.
// Hence, effectively, this is just the 403 response that one gets as the
// anonymous user trying to access a certain REST resource.
// @see \Drupal\user\Authentication\Provider\Cookie
// @todo https://www.drupal.org/node/2847623
if ($method === 'GET') {
$expected_cookie_403_cacheability = $this->getExpectedUnauthorizedAccessCacheability();
// - \Drupal\Core\EventSubscriber\AnonymousUserResponseSubscriber applies
// to cacheable anonymous responses: it updates their cacheability.
// - A 403 response to a GET request is cacheable.
// Therefore we must update our cacheability expectations accordingly.
if (in_array('user.permissions', $expected_cookie_403_cacheability->getCacheContexts(), TRUE)) {
$expected_cookie_403_cacheability->addCacheTags(['config:user.role.anonymous']);
}
// @todo Fix \Drupal\block\BlockAccessControlHandler::mergeCacheabilityFromConditions() in https://www.drupal.org/node/2867881
if (static::$entityTypeId === 'block') {
$expected_cookie_403_cacheability->setCacheTags(str_replace('user:2', 'user:0', $expected_cookie_403_cacheability->getCacheTags()));
}
$this->assertResourceErrorResponse(403, FALSE, $response, $expected_cookie_403_cacheability->getCacheTags(), $expected_cookie_403_cacheability->getCacheContexts(), 'MISS', 'MISS');
}
else {
$this->assertResourceErrorResponse(403, FALSE, $response);
}
}
/**
* {@inheritdoc}
*/
protected function assertAuthenticationEdgeCases($method, Url $url, array $request_options) {
// X-CSRF-Token request header is unnecessary for safe and side effect-free
// HTTP methods. No need for additional assertions.
// @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
if (in_array($method, ['HEAD', 'GET', 'OPTIONS', 'TRACE'])) {
return;
}
unset($request_options[RequestOptions::HEADERS]['X-CSRF-Token']);
// DX: 403 when missing X-CSRF-Token request header.
$response = $this->request($method, $url, $request_options);
$this->assertResourceErrorResponse(403, 'X-CSRF-Token request header is missing', $response);
$request_options[RequestOptions::HEADERS]['X-CSRF-Token'] = 'this-is-not-the-token-you-are-looking-for';
// DX: 403 when invalid X-CSRF-Token request header.
$response = $this->request($method, $url, $request_options);
$this->assertResourceErrorResponse(403, 'X-CSRF-Token request header is invalid', $response);
$request_options[RequestOptions::HEADERS]['X-CSRF-Token'] = $this->csrfToken;
}
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Action;
@trigger_error('The ' . __NAMESPACE__ . '\ActionResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\system\Functional\Rest\ActionResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\system\Functional\Rest\ActionResourceTestBase as ActionResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\system\Functional\Rest\ActionResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class ActionResourceTestBase extends ActionResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\BaseFieldOverride;
@trigger_error('The ' . __NAMESPACE__ . '\BaseFieldOverrideResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\FunctionalTests\Rest\BaseFieldOverrideResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\FunctionalTests\Rest\BaseFieldOverrideResourceTestBase as BaseFieldOverrideResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\FunctionalTests\Rest\BaseFieldOverrideResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class BaseFieldOverrideResourceTestBase extends BaseFieldOverrideResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Block;
@trigger_error('The ' . __NAMESPACE__ . '\BlockResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\block\Functional\Rest\BlockResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\block\Functional\Rest\BlockResourceTestBase as BlockResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\block\Functional\Rest\BlockResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class BlockResourceTestBase extends BlockResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\BlockContent;
@trigger_error('The ' . __NAMESPACE__ . '\BlockContentResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\block_content\Functional\Rest\BlockContentResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\block_content\Functional\Rest\BlockContentResourceTestBase as BlockContentResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\block_content\Functional\Rest\BlockContentResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class BlockContentResourceTestBase extends BlockContentResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\BlockContentType;
@trigger_error('The ' . __NAMESPACE__ . '\BlockContentTypeResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\block_content\Functional\Rest\BlockContentTypeResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\block_content\Functional\Rest\BlockContentTypeResourceTestBase as BlockContentTypeResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\block_content\Functional\Rest\BlockContentTypeResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class BlockContentTypeResourceTestBase extends BlockContentTypeResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Comment;
@trigger_error('The ' . __NAMESPACE__ . '\CommentResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\comment\Functional\Rest\CommentResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\comment\Functional\Rest\CommentResourceTestBase as CommentResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\comment\Functional\Rest\CommentResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class CommentResourceTestBase extends CommentResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\CommentType;
@trigger_error('The ' . __NAMESPACE__ . '\CommentTypeResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\comment\Functional\Rest\CommentTypeResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\comment\Functional\Rest\CommentTypeResourceTestBase as CommentTypeResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\comment\Functional\Rest\CommentTypeResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class CommentTypeResourceTestBase extends CommentTypeResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\ConfigTest;
@trigger_error('The ' . __NAMESPACE__ . '\ConfigTestResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\config_test\Functional\Rest\ConfigTestResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\config_test\Functional\Rest\ConfigTestResourceTestBase as ConfigTestResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\config_test\Functional\Rest\ConfigTestResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class ConfigTestResourceTestBase extends ConfigTestResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\ConfigurableLanguage;
@trigger_error('The ' . __NAMESPACE__ . '\ConfigurableLanguageResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\language\Functional\Rest\ConfigurableLanguageResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\language\Functional\Rest\ConfigurableLanguageResourceTestBase as ConfigurableLanguageResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\language\Functional\Rest\ConfigurableLanguageResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class ConfigurableLanguageResourceTestBase extends ConfigurableLanguageResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\ContactForm;
@trigger_error('The ' . __NAMESPACE__ . '\ContactFormResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\contact\Functional\Rest\ContactFormResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\contact\Functional\Rest\ContactFormResourceTestBase as ContactFormResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\contact\Functional\Rest\ContactFormResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class ContactFormResourceTestBase extends ContactFormResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\ContentLanguageSettings;
@trigger_error('The ' . __NAMESPACE__ . '\ContentLanguageSettingsResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\language\Functional\Rest\ContentLanguageSettingsResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\language\Functional\Rest\ContentLanguageSettingsResourceTestBase as ContentLanguageSettingsResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\language\Functional\Rest\ContentLanguageSettingsResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class ContentLanguageSettingsResourceTestBase extends ContentLanguageSettingsResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\DateFormat;
@trigger_error('The ' . __NAMESPACE__ . '\DateFormatResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\FunctionalTests\Rest\DateFormatResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\FunctionalTests\Rest\DateFormatResourceTestBase as DateFormatResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\FunctionalTests\Rest\DateFormatResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class DateFormatResourceTestBase extends DateFormatResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Editor;
@trigger_error('The ' . __NAMESPACE__ . '\EditorResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\editor\Functional\Rest\EditorResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\editor\Functional\Rest\EditorResourceTestBase as EditorResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\editor\Functional\Rest\EditorResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class EditorResourceTestBase extends EditorResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\EntityFormDisplay;
@trigger_error('The ' . __NAMESPACE__ . '\EntityFormDisplayResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\FunctionalTests\Rest\EntityFormDisplayResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\FunctionalTests\Rest\EntityFormDisplayResourceTestBase as EntityFormDisplayResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\FunctionalTests\Rest\EntityFormDisplayResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class EntityFormDisplayResourceTestBase extends EntityFormDisplayResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\EntityFormMode;
@trigger_error('The ' . __NAMESPACE__ . '\EntityFormModeResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\FunctionalTests\Rest\EntityFormModeResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\FunctionalTests\Rest\EntityFormModeResourceTestBase as EntityFormModeResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\FunctionalTests\Rest\EntityFormModeResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class EntityFormModeResourceTestBase extends EntityFormModeResourceTestBaseReal {
}

View file

@ -0,0 +1,147 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Tests\BrowserTestBase;
/**
* Checks that all core content/config entity types have REST test coverage.
*
* Every entity type must have test coverage for:
* - every format in core (json + xml + hal_json)
* - every authentication provider in core (anon, cookie, basic_auth)
*
* @group rest
*/
class EntityResourceRestTestCoverageTest extends BrowserTestBase {
/**
* Entity definitions array.
*
* @var array
*/
protected $definitions;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$all_modules = system_rebuild_module_data();
$stable_core_modules = array_filter($all_modules, function ($module) {
// Filter out contrib, hidden, testing, and experimental modules. We also
// don't need to enable modules that are already enabled.
return
$module->origin === 'core' &&
empty($module->info['hidden']) &&
$module->status == FALSE &&
$module->info['package'] !== 'Testing' &&
$module->info['package'] !== 'Core (Experimental)';
});
$this->container->get('module_installer')->install(array_keys($stable_core_modules));
$this->rebuildContainer();
$this->definitions = $this->container->get('entity_type.manager')->getDefinitions();
// Entity types marked as "internal" are not exposed by the entity REST
// resource plugin and hence also don't need test coverage.
$this->definitions = array_filter($this->definitions, function (EntityTypeInterface $entity_type) {
return !$entity_type->isInternal();
});
}
/**
* Tests that all core content/config entity types have REST test coverage.
*/
public function testEntityTypeRestTestCoverage() {
$tests = [
// Test coverage for formats provided by the 'serialization' module.
'serialization' => [
'path' => '\Drupal\Tests\PROVIDER\Functional\Rest\CLASS',
'class suffix' => [
'JsonAnonTest',
'JsonBasicAuthTest',
'JsonCookieTest',
'XmlAnonTest',
'XmlBasicAuthTest',
'XmlCookieTest',
],
],
// Test coverage for formats provided by the 'hal' module.
'hal' => [
'path' => '\Drupal\Tests\PROVIDER\Functional\Hal\CLASS',
'class suffix' => [
'HalJsonAnonTest',
'HalJsonBasicAuthTest',
'HalJsonCookieTest',
],
],
];
$problems = [];
foreach ($this->definitions as $entity_type_id => $info) {
$class_name_full = $info->getClass();
$parts = explode('\\', $class_name_full);
$class_name = end($parts);
$module_name = $parts[1];
foreach ($tests as $module => $info) {
$path = $info['path'];
$missing_tests = [];
foreach ($info['class suffix'] as $postfix) {
$class = str_replace(['PROVIDER', 'CLASS'], [$module_name, $class_name], $path . $postfix);
$class_alternative = str_replace("\\Drupal\\Tests\\$module_name\\Functional", '\Drupal\FunctionalTests', $class);
if (class_exists($class) || class_exists($class_alternative)) {
continue;
}
$missing_tests[] = $postfix;
}
if (!empty($missing_tests)) {
$missing_tests_list = implode(', ', array_map(function ($missing_test) use ($class_name) {
return $class_name . $missing_test;
}, $missing_tests));
$which_normalization = $module === 'serialization' ? 'default' : $module;
$problems[] = "$entity_type_id: $class_name ($class_name_full), $which_normalization normalization (expected tests: $missing_tests_list)";
}
}
}
$all = count($this->definitions);
$good = $all - count($problems);
$this->assertSame([], $problems, $this->getLlamaMessage($good, $all));
}
/**
* Message from Llama.
*
* @param int $g
* A count of entities with test coverage.
* @param int $a
* A count of all entities.
*
* @return string
* An information about progress of REST test coverage.
*/
protected function getLlamaMessage($g, $a) {
return "
________________________
/ Hi! \\
| It's llame to not have |
| complete REST tests! |
| |
| Progress: $g/$a. |
| ________________________/
|/
// o
l'>
ll
llama
|| ||
'' ''
";
}
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTest;
@trigger_error('The ' . __NAMESPACE__ . '\EntityTestResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\entity_test\Functional\Rest\EntityTestResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\entity_test\Functional\Rest\EntityTestResourceTestBase as EntityTestResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\entity_test\Functional\Rest\EntityTestResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class EntityTestResourceTestBase extends EntityTestResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTestBundle;
@trigger_error('The ' . __NAMESPACE__ . '\EntityTestBundleResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\entity_test\Functional\Rest\EntityTestBundleResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\entity_test\Functional\Rest\EntityTestBundleResourceTestBase as EntityTestBundleResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\entity_test\Functional\Rest\EntityTestBundleResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class EntityTestBundleResourceTestBase extends EntityTestBundleResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTestLabel;
@trigger_error('The ' . __NAMESPACE__ . '\EntityTestLabelResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\entity_test\Functional\Rest\EntityTestLabelResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\entity_test\Functional\Rest\EntityTestLabelResourceTestBase as EntityTestLabelResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\entity_test\Functional\Rest\EntityTestLabelResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class EntityTestLabelResourceTestBase extends EntityTestLabelResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\EntityViewDisplay;
@trigger_error('The ' . __NAMESPACE__ . '\EntityViewDisplayResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\FunctionalTests\Rest\EntityViewDisplayResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\FunctionalTests\Rest\EntityViewDisplayResourceTestBase as EntityViewDisplayResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\FunctionalTests\Rest\EntityViewDisplayResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class EntityViewDisplayResourceTestBase extends EntityViewDisplayResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\EntityViewMode;
@trigger_error('The ' . __NAMESPACE__ . '\EntityViewModeResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\FunctionalTests\Rest\EntityViewModeResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\FunctionalTests\Rest\EntityViewModeResourceTestBase as EntityViewModeResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\FunctionalTests\Rest\EntityViewModeResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class EntityViewModeResourceTestBase extends EntityViewModeResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Feed;
@trigger_error('The ' . __NAMESPACE__ . '\FeedResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\aggregator\Functional\Rest\FeedResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\aggregator\Functional\Rest\FeedResourceTestBase as FeedResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\aggregator\Functional\Rest\FeedResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class FeedResourceTestBase extends FeedResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\FieldConfig;
@trigger_error('The ' . __NAMESPACE__ . '\FieldConfigResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\field\Functional\Rest\FieldConfigResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\field\Functional\Rest\FieldConfigResourceTestBase as FieldConfigResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\field\Functional\Rest\FieldConfigResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class FieldConfigResourceTestBase extends FieldConfigResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\FieldStorageConfig;
@trigger_error('The ' . __NAMESPACE__ . '\FieldStorageConfigResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\field\Functional\Rest\FieldStorageConfigResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\field\Functional\Rest\FieldStorageConfigResourceTestBase as FieldStorageConfigResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\field\Functional\Rest\FieldStorageConfigResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class FieldStorageConfigResourceTestBase extends FieldStorageConfigResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\File;
@trigger_error('The ' . __NAMESPACE__ . '\FileResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\file\Functional\Rest\FileResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\file\Functional\Rest\FileResourceTestBase as FileResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\file\Functional\Rest\FileResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class FileResourceTestBase extends FileResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\FilterFormat;
@trigger_error('The ' . __NAMESPACE__ . '\FilterFormatResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\filter\Functional\Rest\FilterFormatResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\filter\Functional\Rest\FilterFormatResourceTestBase as FilterFormatResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\filter\Functional\Rest\FilterFormatResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class FilterFormatResourceTestBase extends FilterFormatResourceTestBaseReal {
}

View file

@ -0,0 +1,50 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource;
use Drupal\Core\Url;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
/**
* Provides test methods to assert BC on format-specific GET routes.
*
* @internal
*/
trait FormatSpecificGetBcRouteTestTrait {
/**
* @group legacy
*
* @see \Drupal\rest\RouteProcessor\RestResourceGetRouteProcessorBC
*/
public function testFormatSpecificGetBcRoute() {
$this->provisionEntityResource();
$url = $this->getEntityResourceUrl();
// BC: Format-specific GET routes are deprecated. They are available on both
// new and old sites, but trigger deprecation notices.
$bc_route = Url::fromRoute('rest.entity.' . static::$entityTypeId . '.GET.' . static::$format, $url->getRouteParameters(), $url->getOptions());
$bc_route->setUrlGenerator($this->container->get('url_generator'));
$this->expectDeprecation(sprintf("The 'rest.entity.entity_test.GET.%s' route is deprecated since version 8.5.x and will be removed in 9.0.0. Use the 'rest.entity.entity_test.GET' route instead.", static::$format));
$this->assertSame($url->toString(TRUE)->getGeneratedUrl(), $bc_route->toString(TRUE)->getGeneratedUrl());
}
/**
* @group legacy
*
* @see \Drupal\rest\Plugin\ResourceBase::routes
*/
public function testNoFormatSpecificGetBcRouteForOtherFormats() {
$this->setExpectedException(RouteNotFoundException::class);
$this->provisionEntityResource();
$url = $this->getEntityResourceUrl();
// Verify no format-specific GET BC routes are created for other formats.
$other_format = static::$format === 'json' ? 'xml' : 'json';
$bc_route_other_format = Url::fromRoute('rest.entity.entity_test.GET.' . $other_format, $url->getRouteParameters(), $url->getOptions());
$bc_route_other_format->setUrlGenerator($this->container->get('url_generator'));
$bc_route_other_format->toString(TRUE);
}
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\ImageStyle;
@trigger_error('The ' . __NAMESPACE__ . '\ImageStyleResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\image\Functional\Rest\ImageStyleResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\image\Functional\Rest\ImageStyleResourceTestBase as ImageStyleResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\image\Functional\Rest\ImageStyleResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class ImageStyleResourceTestBase extends ImageStyleResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Item;
@trigger_error('The ' . __NAMESPACE__ . '\ItemResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\aggregator\Functional\Rest\ItemResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\aggregator\Functional\Rest\ItemResourceTestBase as ItemResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\aggregator\Functional\Rest\ItemResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class ItemResourceTestBase extends ItemResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Media;
@trigger_error('The ' . __NAMESPACE__ . '\MediaResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\media\Functional\Rest\MediaResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\media\Functional\Rest\MediaResourceTestBase as MediaResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\media\Functional\Rest\MediaResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class MediaResourceTestBase extends MediaResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\MediaType;
@trigger_error('The ' . __NAMESPACE__ . '\MediaTypeResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\media\Functional\Rest\MediaTypeResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\media\Functional\Rest\MediaTypeResourceTestBase as MediaTypeResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\media\Functional\Rest\MediaTypeResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class MediaTypeResourceTestBase extends MediaTypeResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Menu;
@trigger_error('The ' . __NAMESPACE__ . '\MenuResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\system\Functional\Rest\MenuResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\system\Functional\Rest\MenuResourceTestBase as MenuResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\system\Functional\Rest\MenuResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class MenuResourceTestBase extends MenuResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\MenuLinkContent;
@trigger_error('The ' . __NAMESPACE__ . '\MenuLinkContentResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\menu_link_content\Functional\Rest\MenuLinkContentResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\menu_link_content\Functional\Rest\MenuLinkContentResourceTestBase as MenuLinkContentResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\menu_link_content\Functional\Rest\MenuLinkContentResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class MenuLinkContentResourceTestBase extends MenuLinkContentResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Message;
@trigger_error('The ' . __NAMESPACE__ . '\MessageResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\contact\Functional\Rest\MessageResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\contact\Functional\Rest\MessageResourceTestBase as MessageResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\contact\Functional\Rest\MessageResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class MessageResourceTestBase extends MessageResourceTestBaseReal {
}

View file

@ -0,0 +1,24 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\ModeratedNode;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
/**
* @group rest
*/
class ModeratedNodeJsonAnonTest extends ModeratedNodeResourceTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
}

View file

@ -0,0 +1,34 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\ModeratedNode;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group rest
*/
class ModeratedNodeJsonBasicAuthTest extends ModeratedNodeResourceTestBase {
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';
}

View file

@ -0,0 +1,29 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\ModeratedNode;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group rest
*/
class ModeratedNodeJsonCookieTest extends ModeratedNodeResourceTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,74 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\ModeratedNode;
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
use Drupal\Tests\node\Functional\Rest\NodeResourceTestBase;
/**
* Extend the Node resource test base and apply moderation to the entity.
*/
abstract class ModeratedNodeResourceTestBase extends NodeResourceTestBase {
use ContentModerationTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['content_moderation'];
/**
* The test editorial workflow.
*
* @var \Drupal\workflows\WorkflowInterface
*/
protected $workflow;
/**
* {@inheritdoc}
*/
protected function setUpAuthorization($method) {
parent::setUpAuthorization($method);
switch ($method) {
case 'POST':
case 'PATCH':
case 'DELETE':
$this->grantPermissionsToTestedRole(['use editorial transition publish', 'use editorial transition create_new_draft']);
break;
}
}
/**
* {@inheritdoc}
*/
protected function createEntity() {
$entity = parent::createEntity();
if (!$this->workflow) {
$this->workflow = $this->createEditorialWorkflow();
}
$this->workflow->getTypePlugin()->addEntityTypeAndBundle($entity->getEntityTypeId(), $entity->bundle());
$this->workflow->save();
return $entity;
}
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
return array_merge(parent::getExpectedNormalizedEntity(), [
'moderation_state' => [
[
'value' => 'published',
],
],
'vid' => [
[
'value' => (int) $this->entity->getRevisionId(),
],
],
]);
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\ModeratedNode;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class ModeratedNodeXmlAnonTest extends ModeratedNodeResourceTestBase {
use AnonResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
public function testPatchPath() {
// Deserialization of the XML format is not supported.
$this->markTestSkipped();
}
}

View file

@ -0,0 +1,44 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\ModeratedNode;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class ModeratedNodeXmlBasicAuthTest extends ModeratedNodeResourceTestBase {
use BasicAuthResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
/**
* {@inheritdoc}
*/
public function testPatchPath() {
// Deserialization of the XML format is not supported.
$this->markTestSkipped();
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\ModeratedNode;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class ModeratedNodeXmlCookieTest extends ModeratedNodeResourceTestBase {
use CookieResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
/**
* {@inheritdoc}
*/
public function testPatchPath() {
// Deserialization of the XML format is not supported.
$this->markTestSkipped();
}
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Node;
@trigger_error('The ' . __NAMESPACE__ . '\NodeResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\node\Functional\Rest\NodeResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\node\Functional\Rest\NodeResourceTestBase as NodeResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\node\Functional\Rest\NodeResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class NodeResourceTestBase extends NodeResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\NodeType;
@trigger_error('The ' . __NAMESPACE__ . '\NodeTypeResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\node\Functional\Rest\NodeTypeResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\node\Functional\Rest\NodeTypeResourceTestBase as NodeTypeResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\node\Functional\Rest\NodeTypeResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class NodeTypeResourceTestBase extends NodeTypeResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\RdfMapping;
@trigger_error('The ' . __NAMESPACE__ . '\RdfMappingResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\rdf\Functional\Rest\RdfMappingResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\rdf\Functional\Rest\RdfMappingResourceTestBase as RdfMappingResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\rdf\Functional\Rest\RdfMappingResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class RdfMappingResourceTestBase extends RdfMappingResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\ResponsiveImageStyle;
@trigger_error('The ' . __NAMESPACE__ . '\ResponsiveImageStyleResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\responsive_image\Functional\Rest\ResponsiveImageStyleResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\responsive_image\Functional\Rest\ResponsiveImageStyleResourceTestBase as ResponsiveImageStyleResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\responsive_image\Functional\Rest\ResponsiveImageStyleResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class ResponsiveImageStyleResourceTestBase extends ResponsiveImageStyleResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\RestResourceConfig;
@trigger_error('The ' . __NAMESPACE__ . '\RestResourceConfigResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\rest\Functional\Rest\RestResourceConfigResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\rest\Functional\Rest\RestResourceConfigResourceTestBase as RestResourceConfigResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\rest\Functional\Rest\RestResourceConfigResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class RestResourceConfigResourceTestBase extends RestResourceConfigResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Role;
@trigger_error('The ' . __NAMESPACE__ . '\RoleResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\user\Functional\Rest\RoleResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\user\Functional\Rest\RoleResourceTestBase as RoleResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\user\Functional\Rest\RoleResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class RoleResourceTestBase extends RoleResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\SearchPage;
@trigger_error('The ' . __NAMESPACE__ . '\SearchPageResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\search\Functional\Rest\SearchPageResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\search\Functional\Rest\SearchPageResourceTestBase as SearchPageResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\search\Functional\Rest\SearchPageResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class SearchPageResourceTestBase extends SearchPageResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Shortcut;
@trigger_error('The ' . __NAMESPACE__ . '\ShortcutResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\shortcut\Functional\Rest\ShortcutResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\shortcut\Functional\Rest\ShortcutResourceTestBase as ShortcutResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\shortcut\Functional\Rest\ShortcutResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class ShortcutResourceTestBase extends ShortcutResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\ShortcutSet;
@trigger_error('The ' . __NAMESPACE__ . '\ShortcutSetResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\shortcut\Functional\Rest\ShortcutSetResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\shortcut\Functional\Rest\ShortcutSetResourceTestBase as ShortcutSetResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\shortcut\Functional\Rest\ShortcutSetResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class ShortcutSetResourceTestBase extends ShortcutSetResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Term;
@trigger_error('The ' . __NAMESPACE__ . '\TermResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\taxonomy\Functional\Rest\TermResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\taxonomy\Functional\Rest\TermResourceTestBase as TermResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\taxonomy\Functional\Rest\TermResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class TermResourceTestBase extends TermResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Tour;
@trigger_error('The ' . __NAMESPACE__ . '\TourResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\tour\Functional\Rest\TourResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\tour\Functional\Rest\TourResourceTestBase as TourResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\tour\Functional\Rest\TourResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class TourResourceTestBase extends TourResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\User;
@trigger_error('The ' . __NAMESPACE__ . '\UserResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\user\Functional\Rest\UserResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\user\Functional\Rest\UserResourceTestBase as UserResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\user\Functional\Rest\UserResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class UserResourceTestBase extends UserResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\View;
@trigger_error('The ' . __NAMESPACE__ . '\ViewResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\views\Functional\Rest\ViewResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\views\Functional\Rest\ViewResourceTestBase as ViewResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\views\Functional\Rest\ViewResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class ViewResourceTestBase extends ViewResourceTestBaseReal {
}

View file

@ -0,0 +1,16 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource\Vocabulary;
@trigger_error('The ' . __NAMESPACE__ . '\VocabularyResourceTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use Drupal\Tests\taxonomy\Functional\Rest\VocabularyResourceTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\Tests\taxonomy\Functional\Rest\VocabularyResourceTestBase as VocabularyResourceTestBaseReal;
/**
* @deprecated in Drupal 8.6.x. Will be removed before Drupal 9.0.0. Use
* Drupal\Tests\taxonomy\Functional\Rest\VocabularyResourceTestBase instead.
*
* @see https://www.drupal.org/node/2971931
*/
abstract class VocabularyResourceTestBase extends VocabularyResourceTestBaseReal {
}

View file

@ -0,0 +1,160 @@
<?php
namespace Drupal\Tests\rest\Functional\EntityResource;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\BooleanItem;
use Drupal\Core\Field\Plugin\Field\FieldType\ChangedItem;
use Drupal\Core\Field\Plugin\Field\FieldType\CreatedItem;
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
use Drupal\Core\Field\Plugin\Field\FieldType\IntegerItem;
use Drupal\Core\Field\Plugin\Field\FieldType\TimestampItem;
use Drupal\file\Plugin\Field\FieldType\FileItem;
use Drupal\image\Plugin\Field\FieldType\ImageItem;
use Drupal\options\Plugin\Field\FieldType\ListIntegerItem;
use Drupal\path\Plugin\Field\FieldType\PathItem;
use Drupal\Tests\rest\Functional\XmlNormalizationQuirksTrait;
use Drupal\user\StatusItem;
/**
* Trait for EntityResourceTestBase subclasses testing $format='xml'.
*/
trait XmlEntityNormalizationQuirksTrait {
use XmlNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
$default_normalization = parent::getExpectedNormalizedEntity();
if ($this->entity instanceof FieldableEntityInterface) {
$normalization = $this->applyXmlFieldDecodingQuirks($default_normalization);
}
else {
$normalization = $this->applyXmlConfigEntityDecodingQuirks($default_normalization);
}
$normalization = $this->applyXmlDecodingQuirks($normalization);
return $normalization;
}
/**
* Applies the XML entity field encoding quirks that remain after decoding.
*
* The XML encoding:
* - loses type data (int and bool become string)
*
* @param array $normalization
* An entity normalization.
*
* @return array
* The updated fieldable entity normalization.
*
* @see \Symfony\Component\Serializer\Encoder\XmlEncoder
*/
protected function applyXmlFieldDecodingQuirks(array $normalization) {
foreach ($this->entity->getFields(TRUE) as $field_name => $field) {
// Not every field is accessible.
if (!isset($normalization[$field_name])) {
continue;
}
for ($i = 0; $i < count($normalization[$field_name]); $i++) {
switch ($field->getItemDefinition()->getClass()) {
case BooleanItem::class:
case StatusItem::class:
// @todo Remove the StatusItem case in
// https://www.drupal.org/project/drupal/issues/2936864.
$value = &$normalization[$field_name][$i]['value'];
$value = $value === TRUE ? '1' : '0';
break;
case IntegerItem::class:
case ListIntegerItem::class:
$value = &$normalization[$field_name][$i]['value'];
$value = (string) $value;
break;
case PathItem::class:
$pid = &$normalization[$field_name][$i]['pid'];
$pid = (string) $pid;
break;
case EntityReferenceItem::class:
case FileItem::class:
$target_id = &$normalization[$field_name][$i]['target_id'];
$target_id = (string) $target_id;
break;
case ChangedItem::class:
case CreatedItem::class:
case TimestampItem::class:
$value = &$normalization[$field_name][$i]['value'];
if (is_numeric($value)) {
$value = (string) $value;
}
break;
case ImageItem::class:
$height = &$normalization[$field_name][$i]['height'];
$height = (string) $height;
$width = &$normalization[$field_name][$i]['width'];
$width = (string) $width;
$target_id = &$normalization[$field_name][$i]['target_id'];
$target_id = (string) $target_id;
break;
}
}
if (count($normalization[$field_name]) === 1) {
$normalization[$field_name] = $normalization[$field_name][0];
}
}
return $normalization;
}
/**
* Applies the XML config entity encoding quirks that remain after decoding.
*
* The XML encoding:
* - loses type data (int and bool become string)
* - converts single-item arrays into single items (non-arrays)
*
* @param array $normalization
* An entity normalization.
*
* @return array
* The updated config entity normalization.
*
* @see \Symfony\Component\Serializer\Encoder\XmlEncoder
*/
protected function applyXmlConfigEntityDecodingQuirks(array $normalization) {
$normalization = static::castToString($normalization);
// When a single dependency is listed, it's not decoded into an array.
if (isset($normalization['dependencies'])) {
foreach ($normalization['dependencies'] as $dependency_type => $dependency_list) {
if (count($dependency_list) === 1) {
$normalization['dependencies'][$dependency_type] = $dependency_list[0];
}
}
}
return $normalization;
}
/**
* {@inheritdoc}
*/
public function testPost() {
// Deserialization of the XML format is not supported.
$this->markTestSkipped();
}
/**
* {@inheritdoc}
*/
public function testPatch() {
// Deserialization of the XML format is not supported.
$this->markTestSkipped();
}
}

View file

@ -0,0 +1,720 @@
<?php
namespace Drupal\Tests\rest\Functional;
use Drupal\Component\Render\PlainTextOutput;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Url;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\file\Entity\File;
use Drupal\rest\RestResourceConfigInterface;
use Drupal\user\Entity\User;
use GuzzleHttp\RequestOptions;
use Psr\Http\Message\ResponseInterface;
/**
* Tests binary data file upload route.
*/
abstract class FileUploadResourceTestBase extends ResourceTestBase {
use BcTimestampNormalizerUnixTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['rest_test', 'entity_test', 'file'];
/**
* {@inheritdoc}
*/
protected static $resourceConfigId = 'file.upload';
/**
* The POST URI.
*
* @var string
*/
protected static $postUri = 'file/upload/entity_test/entity_test/field_rest_file_test';
/**
* Test file data.
*
* @var string
*/
protected $testFileData = 'Hares sit on chairs, and mules sit on stools.';
/**
* The test field storage config.
*
* @var \Drupal\field\Entity\FieldStorageConfig
*/
protected $fieldStorage;
/**
* The field config.
*
* @var \Drupal\field\Entity\FieldConfig
*/
protected $field;
/**
* The parent entity.
*
* @var \Drupal\Core\Entity\EntityInterface
*/
protected $entity;
/**
* Created file entity.
*
* @var \Drupal\file\Entity\File
*/
protected $file;
/**
* An authenticated user.
*
* @var \Drupal\user\UserInterface
*/
protected $user;
/**
* The entity storage for the 'file' entity type.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $fileStorage;
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$this->fileStorage = $this->container->get('entity_type.manager')
->getStorage('file');
// Add a file field.
$this->fieldStorage = FieldStorageConfig::create([
'entity_type' => 'entity_test',
'field_name' => 'field_rest_file_test',
'type' => 'file',
'settings' => [
'uri_scheme' => 'public',
],
])
->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
$this->fieldStorage->save();
$this->field = FieldConfig::create([
'entity_type' => 'entity_test',
'field_name' => 'field_rest_file_test',
'bundle' => 'entity_test',
'settings' => [
'file_directory' => 'foobar',
'file_extensions' => 'txt',
'max_filesize' => '',
],
])
->setLabel('Test file field')
->setTranslatable(FALSE);
$this->field->save();
// Create an entity that a file can be attached to.
$this->entity = EntityTest::create([
'name' => 'Llama',
'type' => 'entity_test',
]);
$this->entity->setOwnerId(isset($this->account) ? $this->account->id() : 0);
$this->entity->save();
// Provision entity_test resource.
$this->resourceConfigStorage->create([
'id' => 'entity.entity_test',
'granularity' => RestResourceConfigInterface::RESOURCE_GRANULARITY,
'configuration' => [
'methods' => ['POST'],
'formats' => [static::$format],
'authentication' => [static::$auth],
],
'status' => TRUE,
])->save();
$this->refreshTestStateAfterRestConfigChange();
}
/**
* Tests using the file upload POST route.
*/
public function testPostFileUpload() {
$this->initAuthentication();
$this->provisionResource([static::$format], static::$auth ? [static::$auth] : [], ['POST']);
$uri = Url::fromUri('base:' . static::$postUri);
// DX: 403 when unauthorized.
$response = $this->fileRequest($uri, $this->testFileData);
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('POST'), $response);
$this->setUpAuthorization('POST');
// 404 when the field name is invalid.
$invalid_uri = Url::fromUri('base:file/upload/entity_test/entity_test/field_rest_file_test_invalid');
$response = $this->fileRequest($invalid_uri, $this->testFileData);
$this->assertResourceErrorResponse(404, 'Field "field_rest_file_test_invalid" does not exist', $response);
// This request will have the default 'application/octet-stream' content
// type header.
$response = $this->fileRequest($uri, $this->testFileData);
$this->assertSame(201, $response->getStatusCode());
$expected = $this->getExpectedNormalizedEntity();
$this->assertResponseData($expected, $response);
// Check the actual file data.
$this->assertSame($this->testFileData, file_get_contents('public://foobar/example.txt'));
// Test the file again but using 'filename' in the Content-Disposition
// header with no 'file' prefix.
$response = $this->fileRequest($uri, $this->testFileData, ['Content-Disposition' => 'filename="example.txt"']);
$this->assertSame(201, $response->getStatusCode());
$expected = $this->getExpectedNormalizedEntity(2, 'example_0.txt');
$this->assertResponseData($expected, $response);
// Check the actual file data.
$this->assertSame($this->testFileData, file_get_contents('public://foobar/example_0.txt'));
$this->assertTrue($this->fileStorage->loadUnchanged(1)->isTemporary());
// Verify that we can create an entity that references the uploaded file.
$entity_test_post_url = Url::fromRoute('rest.entity.entity_test.POST')
->setOption('query', ['_format' => static::$format]);
$request_options = [];
$request_options[RequestOptions::HEADERS]['Content-Type'] = static::$mimeType;
$request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions('POST'));
$request_options[RequestOptions::BODY] = $this->serializer->encode($this->getNormalizedPostEntity(), static::$format);
$response = $this->request('POST', $entity_test_post_url, $request_options);
$this->assertResourceResponse(201, FALSE, $response);
$this->assertTrue($this->fileStorage->loadUnchanged(1)->isPermanent());
$this->assertSame([
[
'target_id' => '1',
'display' => NULL,
'description' => "The most fascinating file ever!",
],
], EntityTest::load(2)->get('field_rest_file_test')->getValue());
}
/**
* Returns the normalized POST entity referencing the uploaded file.
*
* @return array
*
* @see ::testPostFileUpload()
* @see \Drupal\Tests\rest\Functional\EntityResource\EntityTest\EntityTestResourceTestBase::getNormalizedPostEntity()
*/
protected function getNormalizedPostEntity() {
return [
'type' => [
[
'value' => 'entity_test',
],
],
'name' => [
[
'value' => 'Dramallama',
],
],
'field_rest_file_test' => [
[
'target_id' => 1,
'description' => 'The most fascinating file ever!',
],
],
];
}
/**
* Tests using the file upload POST route with invalid headers.
*/
public function testPostFileUploadInvalidHeaders() {
$this->initAuthentication();
$this->provisionResource([static::$format], static::$auth ? [static::$auth] : [], ['POST']);
$this->setUpAuthorization('POST');
$uri = Url::fromUri('base:' . static::$postUri);
// The wrong content type header should return a 415 code.
$response = $this->fileRequest($uri, $this->testFileData, ['Content-Type' => static::$mimeType]);
$this->assertResourceErrorResponse(415, sprintf('No route found that matches "Content-Type: %s"', static::$mimeType), $response);
// An empty Content-Disposition header should return a 400.
$response = $this->fileRequest($uri, $this->testFileData, ['Content-Disposition' => '']);
$this->assertResourceErrorResponse(400, '"Content-Disposition" header is required. A file name in the format "filename=FILENAME" must be provided', $response);
// An empty filename with a context in the Content-Disposition header should
// return a 400.
$response = $this->fileRequest($uri, $this->testFileData, ['Content-Disposition' => 'file; filename=""']);
$this->assertResourceErrorResponse(400, 'No filename found in "Content-Disposition" header. A file name in the format "filename=FILENAME" must be provided', $response);
// An empty filename without a context in the Content-Disposition header
// should return a 400.
$response = $this->fileRequest($uri, $this->testFileData, ['Content-Disposition' => 'filename=""']);
$this->assertResourceErrorResponse(400, 'No filename found in "Content-Disposition" header. A file name in the format "filename=FILENAME" must be provided', $response);
// An invalid key-value pair in the Content-Disposition header should return
// a 400.
$response = $this->fileRequest($uri, $this->testFileData, ['Content-Disposition' => 'not_a_filename="example.txt"']);
$this->assertResourceErrorResponse(400, 'No filename found in "Content-Disposition" header. A file name in the format "filename=FILENAME" must be provided', $response);
// Using filename* extended format is not currently supported.
$response = $this->fileRequest($uri, $this->testFileData, ['Content-Disposition' => 'filename*="UTF-8 \' \' example.txt"']);
$this->assertResourceErrorResponse(400, 'The extended "filename*" format is currently not supported in the "Content-Disposition" header', $response);
}
/**
* Tests using the file upload POST route with a duplicate file name.
*
* A new file should be created with a suffixed name.
*/
public function testPostFileUploadDuplicateFile() {
$this->initAuthentication();
$this->provisionResource([static::$format], static::$auth ? [static::$auth] : [], ['POST']);
$this->setUpAuthorization('POST');
$uri = Url::fromUri('base:' . static::$postUri);
// This request will have the default 'application/octet-stream' content
// type header.
$response = $this->fileRequest($uri, $this->testFileData);
$this->assertSame(201, $response->getStatusCode());
// Make the same request again. The file should be saved as a new file
// entity that has the same file name but a suffixed file URI.
$response = $this->fileRequest($uri, $this->testFileData);
$this->assertSame(201, $response->getStatusCode());
// Loading expected normalized data for file 2, the duplicate file.
$expected = $this->getExpectedNormalizedEntity(2, 'example_0.txt');
$this->assertResponseData($expected, $response);
// Check the actual file data.
$this->assertSame($this->testFileData, file_get_contents('public://foobar/example_0.txt'));
}
/**
* Tests using the file upload route with any path prefixes being stripped.
*
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#Directives
*/
public function testFileUploadStrippedFilePath() {
$this->initAuthentication();
$this->provisionResource([static::$format], static::$auth ? [static::$auth] : [], ['POST']);
$this->setUpAuthorization('POST');
$uri = Url::fromUri('base:' . static::$postUri);
$response = $this->fileRequest($uri, $this->testFileData, ['Content-Disposition' => 'file; filename="directory/example.txt"']);
$this->assertSame(201, $response->getStatusCode());
$expected = $this->getExpectedNormalizedEntity();
$this->assertResponseData($expected, $response);
// Check the actual file data. It should have been written to the configured
// directory, not /foobar/directory/example.txt.
$this->assertSame($this->testFileData, file_get_contents('public://foobar/example.txt'));
$response = $this->fileRequest($uri, $this->testFileData, ['Content-Disposition' => 'file; filename="../../example_2.txt"']);
$this->assertSame(201, $response->getStatusCode());
$expected = $this->getExpectedNormalizedEntity(2, 'example_2.txt', TRUE);
$this->assertResponseData($expected, $response);
// Check the actual file data. It should have been written to the configured
// directory, not /foobar/directory/example.txt.
$this->assertSame($this->testFileData, file_get_contents('public://foobar/example_2.txt'));
$this->assertFalse(file_exists('../../example_2.txt'));
// Check a path from the root. Extensions have to be empty to allow a file
// with no extension to pass validation.
$this->field->setSetting('file_extensions', '')
->save();
$this->refreshTestStateAfterRestConfigChange();
$response = $this->fileRequest($uri, $this->testFileData, ['Content-Disposition' => 'file; filename="/etc/passwd"']);
$this->assertSame(201, $response->getStatusCode());
$expected = $this->getExpectedNormalizedEntity(3, 'passwd', TRUE);
// This mime will be guessed as there is no extension.
$expected['filemime'][0]['value'] = 'application/octet-stream';
$this->assertResponseData($expected, $response);
// Check the actual file data. It should have been written to the configured
// directory, not /foobar/directory/example.txt.
$this->assertSame($this->testFileData, file_get_contents('public://foobar/passwd'));
}
/**
* Tests using the file upload route with a unicode file name.
*/
public function testFileUploadUnicodeFilename() {
$this->initAuthentication();
$this->provisionResource([static::$format], static::$auth ? [static::$auth] : [], ['POST']);
$this->setUpAuthorization('POST');
$uri = Url::fromUri('base:' . static::$postUri);
$response = $this->fileRequest($uri, $this->testFileData, ['Content-Disposition' => 'file; filename="example-✓.txt"']);
$this->assertSame(201, $response->getStatusCode());
$expected = $this->getExpectedNormalizedEntity(1, 'example-✓.txt', TRUE);
$this->assertResponseData($expected, $response);
$this->assertSame($this->testFileData, file_get_contents('public://foobar/example-✓.txt'));
}
/**
* Tests using the file upload route with a zero byte file.
*/
public function testFileUploadZeroByteFile() {
$this->initAuthentication();
$this->provisionResource([static::$format], static::$auth ? [static::$auth] : [], ['POST']);
$this->setUpAuthorization('POST');
$uri = Url::fromUri('base:' . static::$postUri);
// Test with a zero byte file.
$response = $this->fileRequest($uri, NULL);
$this->assertSame(201, $response->getStatusCode());
$expected = $this->getExpectedNormalizedEntity();
// Modify the default expected data to account for the 0 byte file.
$expected['filesize'][0]['value'] = 0;
$this->assertResponseData($expected, $response);
// Check the actual file data.
$this->assertSame('', file_get_contents('public://foobar/example.txt'));
}
/**
* Tests using the file upload route with an invalid file type.
*/
public function testFileUploadInvalidFileType() {
$this->initAuthentication();
$this->provisionResource([static::$format], static::$auth ? [static::$auth] : [], ['POST']);
$this->setUpAuthorization('POST');
$uri = Url::fromUri('base:' . static::$postUri);
// Test with a JSON file.
$response = $this->fileRequest($uri, '{"test":123}', ['Content-Disposition' => 'filename="example.json"']);
$this->assertResourceErrorResponse(422, PlainTextOutput::renderFromHtml("Unprocessable Entity: file validation failed.\nOnly files with the following extensions are allowed: <em class=\"placeholder\">txt</em>."), $response);
// Make sure that no file was saved.
$this->assertEmpty(File::load(1));
$this->assertFalse(file_exists('public://foobar/example.txt'));
}
/**
* Tests using the file upload route with a file size larger than allowed.
*/
public function testFileUploadLargerFileSize() {
// Set a limit of 50 bytes.
$this->field->setSetting('max_filesize', 50)
->save();
$this->refreshTestStateAfterRestConfigChange();
$this->initAuthentication();
$this->provisionResource([static::$format], static::$auth ? [static::$auth] : [], ['POST']);
$this->setUpAuthorization('POST');
$uri = Url::fromUri('base:' . static::$postUri);
// Generate a string larger than the 50 byte limit set.
$response = $this->fileRequest($uri, $this->randomString(100));
$this->assertResourceErrorResponse(422, PlainTextOutput::renderFromHtml("Unprocessable Entity: file validation failed.\nThe file is <em class=\"placeholder\">100 bytes</em> exceeding the maximum file size of <em class=\"placeholder\">50 bytes</em>."), $response);
// Make sure that no file was saved.
$this->assertEmpty(File::load(1));
$this->assertFalse(file_exists('public://foobar/example.txt'));
}
/**
* Tests using the file upload POST route with malicious extensions.
*/
public function testFileUploadMaliciousExtension() {
$this->initAuthentication();
$this->provisionResource([static::$format], static::$auth ? [static::$auth] : [], ['POST']);
// Allow all file uploads but system.file::allow_insecure_uploads is set to
// FALSE.
$this->field->setSetting('file_extensions', '')->save();
$this->refreshTestStateAfterRestConfigChange();
$this->setUpAuthorization('POST');
$uri = Url::fromUri('base:' . static::$postUri);
$php_string = '<?php print "Drupal"; ?>';
// Test using a masked exploit file.
$response = $this->fileRequest($uri, $php_string, ['Content-Disposition' => 'filename="example.php"']);
// The filename is not munged because .txt is added and it is a known
// extension to apache.
$expected = $this->getExpectedNormalizedEntity(1, 'example.php.txt', TRUE);
// Override the expected filesize.
$expected['filesize'][0]['value'] = strlen($php_string);
$this->assertResponseData($expected, $response);
$this->assertTrue(file_exists('public://foobar/example.php.txt'));
// Add php as an allowed format. Allow insecure uploads still being FALSE
// should still not allow this. So it should still have a .txt extension
// appended even though it is not in the list of allowed extensions.
$this->field->setSetting('file_extensions', 'php')
->save();
$this->refreshTestStateAfterRestConfigChange();
$response = $this->fileRequest($uri, $php_string, ['Content-Disposition' => 'filename="example_2.php"']);
$expected = $this->getExpectedNormalizedEntity(2, 'example_2.php.txt', TRUE);
// Override the expected filesize.
$expected['filesize'][0]['value'] = strlen($php_string);
$this->assertResponseData($expected, $response);
$this->assertTrue(file_exists('public://foobar/example_2.php.txt'));
$this->assertFalse(file_exists('public://foobar/example_2.php'));
// Allow .doc file uploads and ensure even a mis-configured apache will not
// fallback to php because the filename will be munged.
$this->field->setSetting('file_extensions', 'doc')->save();
$this->refreshTestStateAfterRestConfigChange();
// Test using a masked exploit file.
$response = $this->fileRequest($uri, $php_string, ['Content-Disposition' => 'filename="example_3.php.doc"']);
// The filename is munged.
$expected = $this->getExpectedNormalizedEntity(3, 'example_3.php_.doc', TRUE);
// Override the expected filesize.
$expected['filesize'][0]['value'] = strlen($php_string);
// The file mime should be 'application/msword'.
$expected['filemime'][0]['value'] = 'application/msword';
$this->assertResponseData($expected, $response);
$this->assertTrue(file_exists('public://foobar/example_3.php_.doc'));
$this->assertFalse(file_exists('public://foobar/example_3.php.doc'));
// Now allow insecure uploads.
\Drupal::configFactory()
->getEditable('system.file')
->set('allow_insecure_uploads', TRUE)
->save();
// Allow all file uploads. This is very insecure.
$this->field->setSetting('file_extensions', '')->save();
$this->refreshTestStateAfterRestConfigChange();
$response = $this->fileRequest($uri, $php_string, ['Content-Disposition' => 'filename="example_4.php"']);
$expected = $this->getExpectedNormalizedEntity(4, 'example_4.php', TRUE);
// Override the expected filesize.
$expected['filesize'][0]['value'] = strlen($php_string);
// The file mime should also now be PHP.
$expected['filemime'][0]['value'] = 'application/x-httpd-php';
$this->assertResponseData($expected, $response);
$this->assertTrue(file_exists('public://foobar/example_4.php'));
}
/**
* Tests using the file upload POST route no extension configured.
*/
public function testFileUploadNoExtensionSetting() {
$this->initAuthentication();
$this->provisionResource([static::$format], static::$auth ? [static::$auth] : [], ['POST']);
$this->setUpAuthorization('POST');
$uri = Url::fromUri('base:' . static::$postUri);
$this->field->setSetting('file_extensions', '')
->save();
$this->refreshTestStateAfterRestConfigChange();
$response = $this->fileRequest($uri, $this->testFileData, ['Content-Disposition' => 'filename="example.txt"']);
$expected = $this->getExpectedNormalizedEntity(1, 'example.txt', TRUE);
$this->assertResponseData($expected, $response);
$this->assertTrue(file_exists('public://foobar/example.txt'));
}
/**
* {@inheritdoc}
*/
protected function assertNormalizationEdgeCases($method, Url $url, array $request_options) {
// The file upload resource only accepts binary data, so there are no
// normalization edge cases to test, as there are no normalized entity
// representations incoming.
}
/**
* {@inheritdoc}
*/
protected function getExpectedUnauthorizedAccessMessage($method) {
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'.";
}
/**
* Gets the expected file entity.
*
* @param int $fid
* The file ID to load and create normalized data for.
* @param string $expected_filename
* The expected filename for the stored file.
* @param bool $expected_as_filename
* Whether the expected filename should be the filename property too.
*
* @return array
* The expected normalized data array.
*/
protected function getExpectedNormalizedEntity($fid = 1, $expected_filename = 'example.txt', $expected_as_filename = FALSE) {
$author = User::load(static::$auth ? $this->account->id() : 0);
$file = File::load($fid);
$expected_normalization = [
'fid' => [
[
'value' => (int) $file->id(),
],
],
'uuid' => [
[
'value' => $file->uuid(),
],
],
'langcode' => [
[
'value' => 'en',
],
],
'uid' => [
[
'target_id' => (int) $author->id(),
'target_type' => 'user',
'target_uuid' => $author->uuid(),
'url' => base_path() . 'user/' . $author->id(),
],
],
'filename' => [
[
'value' => $expected_as_filename ? $expected_filename : 'example.txt',
],
],
'uri' => [
[
'value' => 'public://foobar/' . $expected_filename,
'url' => base_path() . $this->siteDirectory . '/files/foobar/' . rawurlencode($expected_filename),
],
],
'filemime' => [
[
'value' => 'text/plain',
],
],
'filesize' => [
[
'value' => strlen($this->testFileData),
],
],
'status' => [
[
'value' => FALSE,
],
],
'created' => [
$this->formatExpectedTimestampItemValues($file->getCreatedTime()),
],
'changed' => [
$this->formatExpectedTimestampItemValues($file->getChangedTime()),
],
];
return $expected_normalization;
}
/**
* Performs a file upload request. Wraps the Guzzle HTTP client.
*
* @see \GuzzleHttp\ClientInterface::request()
*
* @param \Drupal\Core\Url $url
* URL to request.
* @param string $file_contents
* The file contents to send as the request body.
* @param array $headers
* Additional headers to send with the request. Defaults will be added for
* Content-Type and Content-Disposition.
*
* @return \Psr\Http\Message\ResponseInterface
*/
protected function fileRequest(Url $url, $file_contents, array $headers = []) {
// Set the format for the response.
$url->setOption('query', ['_format' => static::$format]);
$request_options = [];
$request_options[RequestOptions::HEADERS] = $headers + [
// Set the required (and only accepted) content type for the request.
'Content-Type' => 'application/octet-stream',
// Set the required Content-Disposition header for the file name.
'Content-Disposition' => 'file; filename="example.txt"',
];
$request_options[RequestOptions::BODY] = $file_contents;
$request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions('POST'));
return $this->request('POST', $url, $request_options);
}
/**
* {@inheritdoc}
*/
protected function setUpAuthorization($method) {
switch ($method) {
case 'GET':
$this->grantPermissionsToTestedRole(['view test entity']);
break;
case 'POST':
$this->grantPermissionsToTestedRole(['create entity_test entity_test_with_bundle entities', 'access content']);
break;
}
}
/**
* Asserts expected normalized data matches response data.
*
* @param array $expected
* The expected data.
* @param \Psr\Http\Message\ResponseInterface $response
* The file upload response.
*/
protected function assertResponseData(array $expected, ResponseInterface $response) {
static::recursiveKSort($expected);
$actual = $this->serializer->decode((string) $response->getBody(), static::$format);
static::recursiveKSort($actual);
$this->assertSame($expected, $actual);
}
/**
* {@inheritdoc}
*/
protected function getExpectedUnauthorizedAccessCacheability() {
// There is cacheability metadata to check as file uploads only allows POST
// requests, which will not return cacheable responses.
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace Drupal\Tests\rest\Functional\Hal;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\rest\Functional\Rest\RestResourceConfigResourceTestBase;
/**
* @group hal
*/
class RestResourceConfigHalJsonAnonTest extends RestResourceConfigResourceTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
}

View file

@ -0,0 +1,35 @@
<?php
namespace Drupal\Tests\rest\Functional\Hal;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
use Drupal\Tests\rest\Functional\Rest\RestResourceConfigResourceTestBase;
/**
* @group hal
*/
class RestResourceConfigHalJsonBasicAuthTest extends RestResourceConfigResourceTestBase {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal', 'basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,35 @@
<?php
namespace Drupal\Tests\rest\Functional\Hal;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
use Drupal\Tests\rest\Functional\Rest\RestResourceConfigResourceTestBase;
/**
* @group hal
*/
class RestResourceConfigHalJsonCookieTest extends RestResourceConfigResourceTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,160 @@
<?php
namespace Drupal\Tests\rest\Functional;
use Drupal\Core\Session\AccountInterface;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\rest\Entity\RestResourceConfig;
use Drupal\rest\RestResourceConfigInterface;
use Drupal\Tests\BrowserTestBase;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
use GuzzleHttp\RequestOptions;
/**
* Tests the structure of a REST resource.
*
* @group rest
*/
class ResourceTest extends BrowserTestBase {
/**
* Modules to install.
*
* @var array
*/
public static $modules = ['hal', 'rest', 'entity_test', 'rest_test'];
/**
* The entity.
*
* @var \Drupal\Core\Entity\EntityInterface
*/
protected $entity;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Create an entity programmatic.
$this->entity = EntityTest::create([
'name' => $this->randomMachineName(),
'user_id' => 1,
'field_test_text' => [
0 => [
'value' => $this->randomString(),
'format' => 'plain_text',
],
],
]);
$this->entity->save();
Role::load(AccountInterface::ANONYMOUS_ROLE)
->grantPermission('view test entity')
->save();
}
/**
* Tests that a resource without formats cannot be enabled.
*/
public function testFormats() {
RestResourceConfig::create([
'id' => 'entity.entity_test',
'granularity' => RestResourceConfigInterface::METHOD_GRANULARITY,
'configuration' => [
'GET' => [
'supported_auth' => [
'basic_auth',
],
],
],
])->save();
// Verify that accessing the resource returns 406.
$this->drupalGet($this->entity->urlInfo()->setRouteParameter('_format', 'hal_json'));
// \Drupal\Core\Routing\RequestFormatRouteFilter considers the canonical,
// non-REST route a match, but a lower quality one: no format restrictions
// means there's always a match and hence when there is no matching REST
// route, the non-REST route is used, but can't render into
// application/hal+json, so it returns a 406.
$this->assertResponse('406', 'HTTP response code is 406 when the resource does not define formats, because it falls back to the canonical, non-REST route.');
}
/**
* Tests that a resource without authentication cannot be enabled.
*/
public function testAuthentication() {
RestResourceConfig::create([
'id' => 'entity.entity_test',
'granularity' => RestResourceConfigInterface::METHOD_GRANULARITY,
'configuration' => [
'GET' => [
'supported_formats' => [
'hal_json',
],
],
],
])->save();
// Verify that accessing the resource returns 401.
$this->drupalGet($this->entity->urlInfo()->setRouteParameter('_format', 'hal_json'));
// \Drupal\Core\Routing\RequestFormatRouteFilter considers the canonical,
// non-REST route a match, but a lower quality one: no format restrictions
// means there's always a match and hence when there is no matching REST
// route, the non-REST route is used, but can't render into
// application/hal+json, so it returns a 406.
$this->assertResponse('406', 'HTTP response code is 406 when the resource does not define formats, because it falls back to the canonical, non-REST route.');
}
/**
* Tests that serialization_class is optional.
*/
public function testSerializationClassIsOptional() {
RestResourceConfig::create([
'id' => 'serialization_test',
'granularity' => RestResourceConfigInterface::METHOD_GRANULARITY,
'configuration' => [
'POST' => [
'supported_formats' => [
'json',
],
'supported_auth' => [
'cookie',
],
],
],
])->save();
\Drupal::service('router.builder')->rebuildIfNeeded();
Role::load(RoleInterface::ANONYMOUS_ID)
->grantPermission('restful post serialization_test')
->save();
$serialized = $this->container->get('serializer')->serialize(['foo', 'bar'], 'json');
$request_options = [
RequestOptions::HEADERS => ['Content-Type' => 'application/json'],
RequestOptions::BODY => $serialized,
];
/** @var \GuzzleHttp\ClientInterface $client */
$client = $this->getSession()->getDriver()->getClient()->getClient();
$response = $client->request('POST', $this->buildUrl('serialization_test', ['query' => ['_format' => 'json']]), $request_options);
$this->assertSame(200, $response->getStatusCode());
$this->assertSame('["foo","bar"]', (string) $response->getBody());
}
/**
* Tests that resource URI paths are formatted properly.
*/
public function testUriPaths() {
/** @var \Drupal\rest\Plugin\Type\ResourcePluginManager $manager */
$manager = \Drupal::service('plugin.manager.rest');
foreach ($manager->getDefinitions() as $resource => $definition) {
foreach ($definition['uri_paths'] as $key => $uri_path) {
$this->assertFalse(strpos($uri_path, '//'), 'The resource URI path does not have duplicate slashes.');
}
}
}
}

View file

@ -0,0 +1,505 @@
<?php
namespace Drupal\Tests\rest\Functional;
use Behat\Mink\Driver\BrowserKitDriver;
use Drupal\Core\Url;
use Drupal\rest\RestResourceConfigInterface;
use Drupal\Tests\BrowserTestBase;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
use GuzzleHttp\RequestOptions;
use Psr\Http\Message\ResponseInterface;
/**
* Subclass this for every REST resource, every format and every auth provider.
*
* For more guidance see
* \Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase
* which has recommendations for testing the
* \Drupal\rest\Plugin\rest\resource\EntityResource REST resource for every
* format and every auth provider. It's a special case (because that single REST
* resource generates supports not just one thing, but many things  multiple
* entity types), but the same principles apply.
*/
abstract class ResourceTestBase extends BrowserTestBase {
/**
* The format to use in this test.
*
* A format is the combination of a certain normalizer and a certain
* serializer.
*
* @see https://www.drupal.org/developing/api/8/serialization
*
* (The default is 'json' because that doesn't depend on any module.)
*
* @var string
*/
protected static $format = 'json';
/**
* The MIME type that corresponds to $format.
*
* (Sadly this cannot be computed automatically yet.)
*
* @var string
*/
protected static $mimeType = 'application/json';
/**
* The authentication mechanism to use in this test.
*
* (The default is 'cookie' because that doesn't depend on any module.)
*
* @var string
*/
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
*
* @see \Drupal\rest\Entity\RestResourceConfig::__construct()
*/
protected static $resourceConfigId = NULL;
/**
* The account to use for authentication, if any.
*
* @var null|\Drupal\Core\Session\AccountInterface
*/
protected $account = NULL;
/**
* The REST resource config entity storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $resourceConfigStorage;
/**
* The serializer service.
*
* @var \Symfony\Component\Serializer\Serializer
*/
protected $serializer;
/**
* Modules to install.
*
* @var array
*/
public static $modules = ['rest'];
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$this->serializer = $this->container->get('serializer');
// Ensure the anonymous user role has no permissions at all.
$user_role = Role::load(RoleInterface::ANONYMOUS_ID);
foreach ($user_role->getPermissions() as $permission) {
$user_role->revokePermission($permission);
}
$user_role->save();
assert([] === $user_role->getPermissions(), 'The anonymous user role has no permissions at all.');
if (static::$auth !== FALSE) {
// Ensure the authenticated user role has no permissions at all.
$user_role = Role::load(RoleInterface::AUTHENTICATED_ID);
foreach ($user_role->getPermissions() as $permission) {
$user_role->revokePermission($permission);
}
$user_role->save();
assert([] === $user_role->getPermissions(), 'The authenticated user role has no permissions at all.');
// Create an account.
$this->account = $this->createUser();
}
else {
// Otherwise, also create an account, so that any test involving User
// entities will have the same user IDs regardless of authentication.
$this->createUser();
}
$this->resourceConfigStorage = $this->container->get('entity_type.manager')->getStorage('rest_resource_config');
// Ensure there's a clean slate: delete all REST resource config entities.
$this->resourceConfigStorage->delete($this->resourceConfigStorage->loadMultiple());
$this->refreshTestStateAfterRestConfigChange();
}
/**
* Provisions the REST resource under test.
*
* @param string[] $formats
* The allowed formats for this resource.
* @param string[] $authentication
* The allowed authentication providers for this resource.
*/
protected function provisionResource($formats = [], $authentication = [], array $methods = ['GET', 'POST', 'PATCH', 'DELETE']) {
$this->resourceConfigStorage->create([
'id' => static::$resourceConfigId,
'granularity' => RestResourceConfigInterface::RESOURCE_GRANULARITY,
'configuration' => [
'methods' => $methods,
'formats' => $formats,
'authentication' => $authentication,
],
'status' => TRUE,
])->save();
$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();
}
/**
* Return the expected error message.
*
* @param string $method
* The HTTP method (GET, POST, PATCH, DELETE).
*
* @return string
* The error string.
*/
protected function getExpectedUnauthorizedAccessMessage($method) {
$resource_plugin_id = str_replace('.', ':', static::$resourceConfigId);
$permission = 'restful ' . strtolower($method) . ' ' . $resource_plugin_id;
return "The '$permission' permission is required.";
}
/**
* Sets up the necessary authorization.
*
* In case of a test verifying publicly accessible REST resources: grant
* permissions to the anonymous user role.
*
* In case of a test verifying behavior when using a particular authentication
* provider: create a user with a particular set of permissions.
*
* Because of the $method parameter, it's possible to first set up
* authentication for only GET, then add POST, et cetera. This then also
* allows for verifying a 403 in case of missing authorization.
*
* @param string $method
* The HTTP method for which to set up authentication.
*
* @see ::grantPermissionsToAnonymousRole()
* @see ::grantPermissionsToAuthenticatedRole()
*/
abstract protected function setUpAuthorization($method);
/**
* Verifies the error response in case of missing authentication.
*
* @param string $method
* HTTP method.
* @param \Psr\Http\Message\ResponseInterface $response
* The response to assert.
*/
abstract protected function assertResponseWhenMissingAuthentication($method, ResponseInterface $response);
/**
* Asserts normalization-specific edge cases.
*
* (Should be called before sending a well-formed request.)
*
* @see \GuzzleHttp\ClientInterface::request()
*
* @param string $method
* HTTP method.
* @param \Drupal\Core\Url $url
* URL to request.
* @param array $request_options
* Request options to apply.
*/
abstract protected function assertNormalizationEdgeCases($method, Url $url, array $request_options);
/**
* Asserts authentication provider-specific edge cases.
*
* (Should be called before sending a well-formed request.)
*
* @see \GuzzleHttp\ClientInterface::request()
*
* @param string $method
* HTTP method.
* @param \Drupal\Core\Url $url
* URL to request.
* @param array $request_options
* Request options to apply.
*/
abstract protected function assertAuthenticationEdgeCases($method, Url $url, array $request_options);
/**
* Returns the expected cacheability of an unauthorized access response.
*
* @return \Drupal\Core\Cache\RefinableCacheableDependencyInterface
* The expected cacheability.
*/
abstract protected function getExpectedUnauthorizedAccessCacheability();
/**
* Initializes authentication.
*
* E.g. for cookie authentication, we first need to get a cookie.
*/
protected function initAuthentication() {}
/**
* Returns Guzzle request options for authentication.
*
* @param string $method
* The HTTP method for this authenticated request.
*
* @return array
* Guzzle request options to use for authentication.
*
* @see \GuzzleHttp\ClientInterface::request()
*/
protected function getAuthenticationRequestOptions($method) {
return [];
}
/**
* Grants permissions to the anonymous role.
*
* @param string[] $permissions
* Permissions to grant.
*/
protected function grantPermissionsToAnonymousRole(array $permissions) {
$this->grantPermissions(Role::load(RoleInterface::ANONYMOUS_ID), $permissions);
}
/**
* Grants permissions to the authenticated role.
*
* @param string[] $permissions
* Permissions to grant.
*/
protected function grantPermissionsToAuthenticatedRole(array $permissions) {
$this->grantPermissions(Role::load(RoleInterface::AUTHENTICATED_ID), $permissions);
}
/**
* Grants permissions to the tested role: anonymous or authenticated.
*
* @param string[] $permissions
* Permissions to grant.
*
* @see ::grantPermissionsToAuthenticatedRole()
* @see ::grantPermissionsToAnonymousRole()
*/
protected function grantPermissionsToTestedRole(array $permissions) {
if (static::$auth) {
$this->grantPermissionsToAuthenticatedRole($permissions);
}
else {
$this->grantPermissionsToAnonymousRole($permissions);
}
}
/**
* Performs a HTTP request. Wraps the Guzzle HTTP client.
*
* Why wrap the Guzzle HTTP client? Because we want to keep the actual test
* code as simple as possible, and hence not require them to specify the
* 'http_errors = FALSE' request option, nor do we want them to have to
* convert Drupal Url objects to strings.
*
* We also don't want to follow redirects automatically, to ensure these tests
* are able to detect when redirects are added or removed.
*
* @see \GuzzleHttp\ClientInterface::request()
*
* @param string $method
* HTTP method.
* @param \Drupal\Core\Url $url
* URL to request.
* @param array $request_options
* Request options to apply.
*
* @return \Psr\Http\Message\ResponseInterface
*/
protected function request($method, Url $url, array $request_options) {
$request_options[RequestOptions::HTTP_ERRORS] = FALSE;
$request_options[RequestOptions::ALLOW_REDIRECTS] = FALSE;
$request_options = $this->decorateWithXdebugCookie($request_options);
$client = $this->getHttpClient();
return $client->request($method, $url->setAbsolute(TRUE)->toString(), $request_options);
}
/**
* Asserts that a resource response has the given status code and body.
*
* @param int $expected_status_code
* The expected response status.
* @param string|false $expected_body
* The expected response body. FALSE in case this should not be asserted.
* @param \Psr\Http\Message\ResponseInterface $response
* The response to assert.
* @param string[]|false $expected_cache_tags
* (optional) The expected cache tags in the X-Drupal-Cache-Tags response
* header, or FALSE if that header should be absent. Defaults to FALSE.
* @param string[]|false $expected_cache_contexts
* (optional) The expected cache contexts in the X-Drupal-Cache-Contexts
* response header, or FALSE if that header should be absent. Defaults to
* FALSE.
* @param string|false $expected_page_cache_header_value
* (optional) The expected X-Drupal-Cache response header value, or FALSE if
* that header should be absent. Possible strings: 'MISS', 'HIT'. Defaults
* to FALSE.
* @param string|false $expected_dynamic_page_cache_header_value
* (optional) The expected X-Drupal-Dynamic-Cache response header value, or
* FALSE if that header should be absent. Possible strings: 'MISS', 'HIT'.
* Defaults to FALSE.
*/
protected function assertResourceResponse($expected_status_code, $expected_body, ResponseInterface $response, $expected_cache_tags = FALSE, $expected_cache_contexts = FALSE, $expected_page_cache_header_value = FALSE, $expected_dynamic_page_cache_header_value = FALSE) {
$this->assertSame($expected_status_code, $response->getStatusCode());
if ($expected_status_code === 204) {
// 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());
}
else {
$this->assertSame([static::$mimeType], $response->getHeader('Content-Type'));
if ($expected_body !== FALSE) {
$this->assertSame($expected_body, (string) $response->getBody());
}
}
// Expected cache tags: X-Drupal-Cache-Tags header.
$this->assertSame($expected_cache_tags !== FALSE, $response->hasHeader('X-Drupal-Cache-Tags'));
if (is_array($expected_cache_tags)) {
$this->assertSame($expected_cache_tags, explode(' ', $response->getHeader('X-Drupal-Cache-Tags')[0]));
}
// Expected cache contexts: X-Drupal-Cache-Contexts header.
$this->assertSame($expected_cache_contexts !== FALSE, $response->hasHeader('X-Drupal-Cache-Contexts'));
if (is_array($expected_cache_contexts)) {
$this->assertSame($expected_cache_contexts, explode(' ', $response->getHeader('X-Drupal-Cache-Contexts')[0]));
}
// Expected Page Cache header value: X-Drupal-Cache header.
if ($expected_page_cache_header_value !== FALSE) {
$this->assertTrue($response->hasHeader('X-Drupal-Cache'));
$this->assertSame($expected_page_cache_header_value, $response->getHeader('X-Drupal-Cache')[0]);
}
else {
$this->assertFalse($response->hasHeader('X-Drupal-Cache'));
}
// Expected Dynamic Page Cache header value: X-Drupal-Dynamic-Cache header.
if ($expected_dynamic_page_cache_header_value !== FALSE) {
$this->assertTrue($response->hasHeader('X-Drupal-Dynamic-Cache'));
$this->assertSame($expected_dynamic_page_cache_header_value, $response->getHeader('X-Drupal-Dynamic-Cache')[0]);
}
else {
$this->assertFalse($response->hasHeader('X-Drupal-Dynamic-Cache'));
}
}
/**
* Asserts that a resource error response has the given message.
*
* @param int $expected_status_code
* The expected response status.
* @param string $expected_message
* The expected error message.
* @param \Psr\Http\Message\ResponseInterface $response
* The error response to assert.
* @param string[]|false $expected_cache_tags
* (optional) The expected cache tags in the X-Drupal-Cache-Tags response
* header, or FALSE if that header should be absent. Defaults to FALSE.
* @param string[]|false $expected_cache_contexts
* (optional) The expected cache contexts in the X-Drupal-Cache-Contexts
* response header, or FALSE if that header should be absent. Defaults to
* FALSE.
* @param string|false $expected_page_cache_header_value
* (optional) The expected X-Drupal-Cache response header value, or FALSE if
* that header should be absent. Possible strings: 'MISS', 'HIT'. Defaults
* to FALSE.
* @param string|false $expected_dynamic_page_cache_header_value
* (optional) The expected X-Drupal-Dynamic-Cache response header value, or
* FALSE if that header should be absent. Possible strings: 'MISS', 'HIT'.
* Defaults to FALSE.
*/
protected function assertResourceErrorResponse($expected_status_code, $expected_message, ResponseInterface $response, $expected_cache_tags = FALSE, $expected_cache_contexts = FALSE, $expected_page_cache_header_value = FALSE, $expected_dynamic_page_cache_header_value = FALSE) {
$expected_body = ($expected_message !== FALSE) ? $this->serializer->encode(['message' => $expected_message], static::$format) : FALSE;
$this->assertResourceResponse($expected_status_code, $expected_body, $response, $expected_cache_tags, $expected_cache_contexts, $expected_page_cache_header_value, $expected_dynamic_page_cache_header_value);
}
/**
* 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;
}
/**
* Recursively sorts an array by key.
*
* @param array $array
* An array to sort.
*
* @return array
* The sorted array.
*/
protected static function recursiveKSort(array &$array) {
// First, sort the main array.
ksort($array);
// Then check for child arrays.
foreach ($array as $key => &$value) {
if (is_array($value)) {
static::recursiveKSort($value);
}
}
}
}

View file

@ -0,0 +1,24 @@
<?php
namespace Drupal\Tests\rest\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
/**
* @group rest
*/
class RestResourceConfigJsonAnonTest extends RestResourceConfigResourceTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
}

View file

@ -0,0 +1,34 @@
<?php
namespace Drupal\Tests\rest\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group rest
*/
class RestResourceConfigJsonBasicAuthTest extends RestResourceConfigResourceTestBase {
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';
}

View file

@ -0,0 +1,29 @@
<?php
namespace Drupal\Tests\rest\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group rest
*/
class RestResourceConfigJsonCookieTest extends RestResourceConfigResourceTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

Some files were not shown because too many files have changed in this diff Show more