CreateTest.php in Zircon Profile 8
Same filename and directory in other branches
Contains \Drupal\rest\Tests\CreateTest.
Namespace
Drupal\rest\TestsFile
core/modules/rest/src/Tests/CreateTest.phpView source
<?php
/**
* @file
* Contains \Drupal\rest\Tests\CreateTest.
*/
namespace Drupal\rest\Tests;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Entity\EntityInterface;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\node\Entity\Node;
use Drupal\user\Entity\User;
use Drupal\comment\Entity\Comment;
/**
* Tests the creation of resources.
*
* @group rest
*/
class CreateTest extends RESTTestBase {
use CommentTestTrait;
/**
* Modules to install.
*
* @var array
*/
public static $modules = array(
'hal',
'rest',
'entity_test',
'comment',
);
/**
* The 'serializer' service.
*
* @var \Symfony\Component\Serializer\Serializer
*/
protected $serializer;
protected function setUp() {
parent::setUp();
$this
->addDefaultCommentField('node', 'resttest');
// Get the 'serializer' service.
$this->serializer = $this->container
->get('serializer');
}
/**
* Try to create a resource which is not REST API enabled.
*/
public function testCreateResourceRestApiNotEnabled() {
$entity_type = 'entity_test';
// Enables the REST service for a specific entity type.
$this
->enableService('entity:' . $entity_type, 'POST');
// Get the necessary user permissions to create the current entity type.
$permissions = $this
->entityPermissions($entity_type, 'create');
// POST method must be allowed for the current entity type.
$permissions[] = 'restful post entity:' . $entity_type;
// Create the user.
$account = $this
->drupalCreateUser($permissions);
// Populate some entity properties before create the entity.
$entity_values = $this
->entityValues($entity_type);
$entity = EntityTest::create($entity_values);
// Serialize the entity before the POST request.
$serialized = $this->serializer
->serialize($entity, $this->defaultFormat, [
'account' => $account,
]);
// Disable all resource types.
$this
->enableService(FALSE);
$this
->drupalLogin($account);
// POST request to create the current entity. GET request for CSRF token
// is included into the httpRequest() method.
$this
->httpRequest('entity/entity_test', 'POST', $serialized, $this->defaultMimeType);
// The resource is not enabled. So, we receive a 'not found' response.
$this
->assertResponse(404);
$this
->assertFalse(EntityTest::loadMultiple(), 'No entity has been created in the database.');
}
/**
* Ensure that an entity cannot be created without the restful permission.
*/
public function testCreateWithoutPermission() {
$entity_type = 'entity_test';
// Enables the REST service for 'entity_test' entity type.
$this
->enableService('entity:' . $entity_type, 'POST');
$permissions = $this
->entityPermissions($entity_type, 'create');
// Create a user without the 'restful post entity:entity_test permission.
$account = $this
->drupalCreateUser($permissions);
$this
->drupalLogin($account);
// Populate some entity properties before create the entity.
$entity_values = $this
->entityValues($entity_type);
$entity = EntityTest::create($entity_values);
// Serialize the entity before the POST request.
$serialized = $this->serializer
->serialize($entity, $this->defaultFormat, [
'account' => $account,
]);
// Create the entity over the REST API.
$this
->httpRequest('entity/' . $entity_type, 'POST', $serialized, $this->defaultMimeType);
$this
->assertResponse(403);
$this
->assertFalse(EntityTest::loadMultiple(), 'No entity has been created in the database.');
}
/**
* Tests valid and invalid create requests for 'entity_test' entity type.
*/
public function testCreateEntityTest() {
$entity_type = 'entity_test';
// Enables the REST service for 'entity_test' entity type.
$this
->enableService('entity:' . $entity_type, 'POST');
// Create two accounts with the required permissions to create resources.
// The second one has administrative permissions.
$accounts = $this
->createAccountPerEntity($entity_type);
// Verify create requests per user.
foreach ($accounts as $key => $account) {
$this
->drupalLogin($account);
// Populate some entity properties before create the entity.
$entity_values = $this
->entityValues($entity_type);
$entity = EntityTest::create($entity_values);
// Serialize the entity before the POST request.
$serialized = $this->serializer
->serialize($entity, $this->defaultFormat, [
'account' => $account,
]);
// Create the entity over the REST API.
$this
->assertCreateEntityOverRestApi($entity_type, $serialized);
// Get the entity ID from the location header and try to read it from the
// database.
$this
->assertReadEntityIdFromHeaderAndDb($entity_type, $entity, $entity_values);
// Try to create an entity with an access protected field.
// @see entity_test_entity_field_access()
$normalized = $this->serializer
->normalize($entity, $this->defaultFormat, [
'account' => $account,
]);
$normalized['field_test_text'][0]['value'] = 'no access value';
$this
->httpRequest('entity/' . $entity_type, 'POST', $this->serializer
->serialize($normalized, $this->defaultFormat, [
'account' => $account,
]), $this->defaultMimeType);
$this
->assertResponse(403);
$this
->assertFalse(EntityTest::loadMultiple(), 'No entity has been created in the database.');
// Try to create a field with a text format this user has no access to.
$entity->field_test_text->value = $entity_values['field_test_text'][0]['value'];
$entity->field_test_text->format = 'full_html';
$serialized = $this->serializer
->serialize($entity, $this->defaultFormat, [
'account' => $account,
]);
$this
->httpRequest('entity/' . $entity_type, 'POST', $serialized, $this->defaultMimeType);
// The value selected is not a valid choice because the format must be
// 'plain_txt'.
$this
->assertResponse(422);
$this
->assertFalse(EntityTest::loadMultiple(), 'No entity has been created in the database.');
// Restore the valid test value.
$entity->field_test_text->format = 'plain_text';
$serialized = $this->serializer
->serialize($entity, $this->defaultFormat, [
'account' => $account,
]);
// Try to send invalid data that cannot be correctly deserialized.
$this
->assertCreateEntityInvalidData($entity_type);
// Try to send no data at all, which does not make sense on POST requests.
$this
->assertCreateEntityNoData($entity_type);
// Try to send invalid data to trigger the entity validation constraints.
// Send a UUID that is too long.
$this
->assertCreateEntityInvalidSerialized($entity, $entity_type);
// Try to create an entity without proper permissions.
$this
->assertCreateEntityWithoutProperPermissions($entity_type, $serialized, [
'account' => $account,
]);
}
}
/**
* Tests several valid and invalid create requests for 'node' entity type.
*/
public function testCreateNode() {
$entity_type = 'node';
// Enables the REST service for 'node' entity type.
$this
->enableService('entity:' . $entity_type, 'POST');
// Create two accounts that have the required permissions to create
// resources. The second one has administrative permissions.
$accounts = $this
->createAccountPerEntity($entity_type);
// Verify create requests per user.
foreach ($accounts as $key => $account) {
$this
->drupalLogin($account);
// Populate some entity properties before create the entity.
$entity_values = $this
->entityValues($entity_type);
$entity = Node::create($entity_values);
// Verify that user cannot create content when trying to write to fields
// where it is not possible.
if (!$account
->hasPermission('administer nodes')) {
$serialized = $this->serializer
->serialize($entity, $this->defaultFormat, [
'account' => $account,
]);
$this
->httpRequest('entity/' . $entity_type, 'POST', $serialized, $this->defaultMimeType);
$this
->assertResponse(403);
// Remove fields where non-administrative users cannot write.
$entity = $this
->removeNodeFieldsForNonAdminUsers($entity);
}
else {
// Changed and revision_timestamp fields can never be added.
unset($entity->changed);
unset($entity->revision_timestamp);
}
$serialized = $this->serializer
->serialize($entity, $this->defaultFormat, [
'account' => $account,
]);
// Create the entity over the REST API.
$this
->assertCreateEntityOverRestApi($entity_type, $serialized);
// Get the new entity ID from the location header and try to read it from
// the database.
$this
->assertReadEntityIdFromHeaderAndDb($entity_type, $entity, $entity_values);
// Try to send invalid data that cannot be correctly deserialized.
$this
->assertCreateEntityInvalidData($entity_type);
// Try to send no data at all, which does not make sense on POST requests.
$this
->assertCreateEntityNoData($entity_type);
// Try to send invalid data to trigger the entity validation constraints. Send a UUID that is too long.
$this
->assertCreateEntityInvalidSerialized($entity, $entity_type);
// Try to create an entity without proper permissions.
$this
->assertCreateEntityWithoutProperPermissions($entity_type, $serialized);
}
}
/**
* Test comment creation.
*/
protected function testCreateComment() {
$node = Node::create([
'type' => 'resttest',
'title' => 'some node',
]);
$node
->save();
$entity_type = 'comment';
// Enable the REST service for 'comment' entity type.
$this
->enableService('entity:' . $entity_type, 'POST');
// Create two accounts that have the required permissions to create
// resources, The second one has administrative permissions.
$accounts = $this
->createAccountPerEntity($entity_type);
$account = end($accounts);
$this
->drupalLogin($account);
$entity_values = $this
->entityValues($entity_type);
$entity_values['entity_id'] = $node
->id();
$entity = Comment::create($entity_values);
// Changed field can never be added.
unset($entity->changed);
$serialized = $this->serializer
->serialize($entity, $this->defaultFormat, [
'account' => $account,
]);
// Create the entity over the REST API.
$this
->assertCreateEntityOverRestApi($entity_type, $serialized);
// Get the new entity ID from the location header and try to read it from
// the database.
$this
->assertReadEntityIdFromHeaderAndDb($entity_type, $entity, $entity_values);
// Try to send invalid data that cannot be correctly deserialized.
$this
->assertCreateEntityInvalidData($entity_type);
// Try to send no data at all, which does not make sense on POST requests.
$this
->assertCreateEntityNoData($entity_type);
// Try to send invalid data to trigger the entity validation constraints.
// Send a UUID that is too long.
$this
->assertCreateEntityInvalidSerialized($entity, $entity_type);
}
/**
* Tests several valid and invalid create requests for 'user' entity type.
*/
public function testCreateUser() {
$entity_type = 'user';
// Enables the REST service for 'user' entity type.
$this
->enableService('entity:' . $entity_type, 'POST');
// Create two accounts that have the required permissions to create
// resources. The second one has administrative permissions.
$accounts = $this
->createAccountPerEntity($entity_type);
foreach ($accounts as $key => $account) {
$this
->drupalLogin($account);
$entity_values = $this
->entityValues($entity_type);
$entity = User::create($entity_values);
// Verify that only administrative users can create users.
if (!$account
->hasPermission('administer users')) {
$serialized = $this->serializer
->serialize($entity, $this->defaultFormat, [
'account' => $account,
]);
$this
->httpRequest('entity/' . $entity_type, 'POST', $serialized, $this->defaultMimeType);
$this
->assertResponse(403);
continue;
}
// Changed field can never be added.
unset($entity->changed);
$serialized = $this->serializer
->serialize($entity, $this->defaultFormat, [
'account' => $account,
]);
// Create the entity over the REST API.
$this
->assertCreateEntityOverRestApi($entity_type, $serialized);
// Get the new entity ID from the location header and try to read it from
// the database.
$this
->assertReadEntityIdFromHeaderAndDb($entity_type, $entity, $entity_values);
// Try to send invalid data that cannot be correctly deserialized.
$this
->assertCreateEntityInvalidData($entity_type);
// Try to send no data at all, which does not make sense on POST requests.
$this
->assertCreateEntityNoData($entity_type);
// Try to send invalid data to trigger the entity validation constraints.
// Send a UUID that is too long.
$this
->assertCreateEntityInvalidSerialized($entity, $entity_type);
}
}
/**
* Creates user accounts that have the required permissions to create
* resources via the REST API. The second one has administrative permissions.
*
* @param string $entity_type
* Entity type needed to apply user permissions.
* @return array
* An array that contains user accounts.
*/
public function createAccountPerEntity($entity_type) {
$accounts = array();
// Get the necessary user permissions for the current $entity_type creation.
$permissions = $this
->entityPermissions($entity_type, 'create');
// POST method must be allowed for the current entity type.
$permissions[] = 'restful post entity:' . $entity_type;
// Create user without administrative permissions.
$accounts[] = $this
->drupalCreateUser($permissions);
// Add administrative permissions for nodes and users.
$permissions[] = 'administer nodes';
$permissions[] = 'administer users';
$permissions[] = 'administer comments';
// Create an administrative user.
$accounts[] = $this
->drupalCreateUser($permissions);
return $accounts;
}
/**
* Creates the entity over the REST API.
*
* @param string $entity_type
* The type of the entity that should be created.
* @param string $serialized
* The body for the POST request.
*/
public function assertCreateEntityOverRestApi($entity_type, $serialized = NULL) {
// Note: this will fail with PHP 5.6 when always_populate_raw_post_data is
// set to something other than -1. See https://www.drupal.org/node/2456025.
$this
->httpRequest('entity/' . $entity_type, 'POST', $serialized, $this->defaultMimeType);
$this
->assertResponse(201);
}
/**
* Gets the new entity ID from the location header and tries to read it from
* the database.
*
* @param string $entity_type
* Entity type we need to load the entity from DB.
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity we want to check that was inserted correctly.
* @param array $entity_values
* The values of $entity.
*/
public function assertReadEntityIdFromHeaderAndDb($entity_type, EntityInterface $entity, array $entity_values = array()) {
// Get the location from the HTTP response header.
$location_url = $this
->drupalGetHeader('location');
$url_parts = explode('/', $location_url);
$id = end($url_parts);
// Get the entity using the ID found.
$loaded_entity = \Drupal::entityManager()
->getStorage($entity_type)
->load($id);
$this
->assertNotIdentical(FALSE, $loaded_entity, 'The new ' . $entity_type . ' was found in the database.');
$this
->assertEqual($entity
->uuid(), $loaded_entity
->uuid(), 'UUID of created entity is correct.');
// Verify that the field values sent and received from DB are the same.
foreach ($entity_values as $property => $value) {
$actual_value = $loaded_entity
->get($property)->value;
$send_value = $entity
->get($property)->value;
$this
->assertEqual($send_value, $actual_value, 'Created property ' . $property . ' expected: ' . $send_value . ', actual: ' . $actual_value);
}
// Delete the entity loaded from DB.
$loaded_entity
->delete();
}
/**
* Try to send invalid data that cannot be correctly deserialized.
*
* @param string $entity_type
* The type of the entity that should be created.
*/
public function assertCreateEntityInvalidData($entity_type) {
$this
->httpRequest('entity/' . $entity_type, 'POST', 'kaboom!', $this->defaultMimeType);
$this
->assertResponse(400);
}
/**
* Try to send no data at all, which does not make sense on POST requests.
*
* @param string $entity_type
* The type of the entity that should be created.
*/
public function assertCreateEntityNoData($entity_type) {
$this
->httpRequest('entity/' . $entity_type, 'POST', NULL, $this->defaultMimeType);
$this
->assertResponse(400);
}
/**
* Send an invalid UUID to trigger the entity validation.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity we want to check that was inserted correctly.
* @param string $entity_type
* The type of the entity that should be created.
* @param array $context
* Options normalizers/encoders have access to.
*/
public function assertCreateEntityInvalidSerialized(EntityInterface $entity, $entity_type, array $context = array()) {
// Add a UUID that is too long.
$entity
->set('uuid', $this
->randomMachineName(129));
$invalid_serialized = $this->serializer
->serialize($entity, $this->defaultFormat, $context);
$response = $this
->httpRequest('entity/' . $entity_type, 'POST', $invalid_serialized, $this->defaultMimeType);
// Unprocessable Entity as response.
$this
->assertResponse(422);
// Verify that the text of the response is correct.
$error = Json::decode($response);
$this
->assertEqual($error['error'], "Unprocessable Entity: validation failed.\nuuid.0.value: <em class=\"placeholder\">UUID</em>: may not be longer than 128 characters.\n");
}
/**
* Try to create an entity without proper permissions.
*
* @param string $entity_type
* The type of the entity that should be created.
* @param string $serialized
* The body for the POST request.
*/
public function assertCreateEntityWithoutProperPermissions($entity_type, $serialized = NULL) {
$this
->drupalLogout();
$this
->httpRequest('entity/' . $entity_type, 'POST', $serialized, $this->defaultMimeType);
// Forbidden Error as response.
$this
->assertResponse(403);
$this
->assertFalse(\Drupal::entityManager()
->getStorage($entity_type)
->loadMultiple(), 'No entity has been created in the database.');
}
}
Classes
Name | Description |
---|---|
CreateTest | Tests the creation of resources. |