You are here

UpdateTest.php in Zircon Profile 8

Namespace

Drupal\rest\Tests

File

core/modules/rest/src/Tests/UpdateTest.php
View source
<?php

/**
 * @file
 * Contains \Drupal\rest\Tests\UpdateTest.
 */
namespace Drupal\rest\Tests;

use Drupal\Component\Serialization\Json;

/**
 * Tests the update of resources.
 *
 * @group rest
 */
class UpdateTest extends RESTTestBase {

  /**
   * Modules to install.
   *
   * @var array
   */
  public static $modules = array(
    'hal',
    'rest',
    'entity_test',
  );

  /**
   * Tests several valid and invalid partial update requests on test entities.
   */
  public function testPatchUpdate() {
    $serializer = $this->container
      ->get('serializer');

    // @todo Test all other entity types here as well.
    $entity_type = 'entity_test';
    $this
      ->enableService('entity:' . $entity_type, 'PATCH');

    // Create a user account that has the required permissions to create
    // resources via the REST API.
    $permissions = $this
      ->entityPermissions($entity_type, 'update');
    $permissions[] = 'restful patch entity:' . $entity_type;
    $account = $this
      ->drupalCreateUser($permissions);
    $this
      ->drupalLogin($account);
    $context = [
      'account' => $account,
    ];

    // Create an entity and save it to the database.
    $entity = $this
      ->entityCreate($entity_type);
    $entity
      ->save();

    // Create a second stub entity for overwriting a field.
    $patch_values['field_test_text'] = array(
      0 => array(
        'value' => $this
          ->randomString(),
        'format' => 'plain_text',
      ),
    );
    $patch_entity = entity_create($entity_type, $patch_values);

    // We don't want to overwrite the UUID.
    unset($patch_entity->uuid);
    $serialized = $serializer
      ->serialize($patch_entity, $this->defaultFormat, $context);

    // Update the entity over the REST API.
    $this
      ->httpRequest($entity
      ->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
    $this
      ->assertResponse(204);

    // Re-load updated entity from the database.
    $entity = entity_load($entity_type, $entity
      ->id(), TRUE);
    $this
      ->assertEqual($entity->field_test_text->value, $patch_entity->field_test_text->value, 'Field was successfully updated.');

    // Make sure that the field does not get deleted if it is not present in the
    // PATCH request.
    $normalized = $serializer
      ->normalize($patch_entity, $this->defaultFormat, $context);
    unset($normalized['field_test_text']);
    $serialized = $serializer
      ->encode($normalized, $this->defaultFormat);
    $this
      ->httpRequest($entity
      ->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
    $this
      ->assertResponse(204);
    $entity = entity_load($entity_type, $entity
      ->id(), TRUE);
    $this
      ->assertNotNull($entity->field_test_text->value . 'Test field has not been deleted.');

    // Try to empty a field.
    $normalized['field_test_text'] = array();
    $serialized = $serializer
      ->encode($normalized, $this->defaultFormat);

    // Update the entity over the REST API.
    $this
      ->httpRequest($entity
      ->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
    $this
      ->assertResponse(204);

    // Re-load updated entity from the database.
    $entity = entity_load($entity_type, $entity
      ->id(), TRUE);
    $this
      ->assertNull($entity->field_test_text->value, 'Test field has been cleared.');

    // Enable access protection for the text field.
    // @see entity_test_entity_field_access()
    $entity->field_test_text->value = 'no edit access value';
    $entity->field_test_text->format = 'plain_text';
    $entity
      ->save();

    // Try to empty a field that is access protected.
    $this
      ->httpRequest($entity
      ->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
    $this
      ->assertResponse(403);

    // Re-load the entity from the database.
    $entity = entity_load($entity_type, $entity
      ->id(), TRUE);
    $this
      ->assertEqual($entity->field_test_text->value, 'no edit access value', 'Text field was not deleted.');

    // Try to update an access protected field.
    $normalized = $serializer
      ->normalize($patch_entity, $this->defaultFormat, $context);
    $normalized['field_test_text'][0]['value'] = 'no access value';
    $serialized = $serializer
      ->serialize($normalized, $this->defaultFormat, $context);
    $this
      ->httpRequest($entity
      ->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
    $this
      ->assertResponse(403);

    // Re-load the entity from the database.
    $entity = entity_load($entity_type, $entity
      ->id(), TRUE);
    $this
      ->assertEqual($entity->field_test_text->value, 'no edit access value', 'Text field was not updated.');

    // Try to update the field with a text format this user has no access to.
    // First change the original field value so we're allowed to edit it again.
    $entity->field_test_text->value = 'test';
    $entity
      ->save();
    $patch_entity
      ->set('field_test_text', array(
      'value' => 'test',
      'format' => 'full_html',
    ));
    $serialized = $serializer
      ->serialize($patch_entity, $this->defaultFormat, $context);
    $this
      ->httpRequest($entity
      ->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
    $this
      ->assertResponse(422);

    // Re-load the entity from the database.
    $entity = entity_load($entity_type, $entity
      ->id(), TRUE);
    $this
      ->assertEqual($entity->field_test_text->format, 'plain_text', 'Text format was not updated.');

    // Restore the valid test value.
    $entity->field_test_text->value = $this
      ->randomString();
    $entity
      ->save();

    // Try to send no data at all, which does not make sense on PATCH requests.
    $this
      ->httpRequest($entity
      ->urlInfo(), 'PATCH', NULL, $this->defaultMimeType);
    $this
      ->assertResponse(400);

    // Try to update a non-existing entity with ID 9999.
    $this
      ->httpRequest($entity_type . '/9999', 'PATCH', $serialized, $this->defaultMimeType);
    $this
      ->assertResponse(404);
    $loaded_entity = entity_load($entity_type, 9999, TRUE);
    $this
      ->assertFalse($loaded_entity, 'Entity 9999 was not created.');

    // Try to send invalid data to trigger the entity validation constraints.
    // Send a UUID that is too long.
    $entity
      ->set('uuid', $this
      ->randomMachineName(129));
    $invalid_serialized = $serializer
      ->serialize($entity, $this->defaultFormat, $context);
    $response = $this
      ->httpRequest($entity
      ->urlInfo(), 'PATCH', $invalid_serialized, $this->defaultMimeType);
    $this
      ->assertResponse(422);
    $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 update an entity without proper permissions.
    $this
      ->drupalLogout();
    $this
      ->httpRequest($entity
      ->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
    $this
      ->assertResponse(403);

    // Try to update a resource which is not REST API enabled.
    $this
      ->enableService(FALSE);
    $this
      ->drupalLogin($account);
    $this
      ->httpRequest($entity
      ->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
    $this
      ->assertResponse(405);
  }

  /**
   * Tests several valid and invalid update requests for the 'user' entity type.
   */
  public function testUpdateUser() {
    $serializer = $this->container
      ->get('serializer');
    $entity_type = 'user';

    // Enables the REST service for 'user' entity type.
    $this
      ->enableService('entity:' . $entity_type, 'PATCH');
    $permissions = $this
      ->entityPermissions($entity_type, 'update');
    $permissions[] = 'restful patch entity:' . $entity_type;
    $account = $this
      ->drupalCreateUser($permissions);
    $account
      ->set('mail', 'old-email@example.com');
    $this
      ->drupalLogin($account);

    // Create an entity and save it to the database.
    $account
      ->save();
    $account
      ->set('changed', NULL);

    // Try and set a new email without providing the password.
    $account
      ->set('mail', 'new-email@example.com');
    $context = [
      'account' => $account,
    ];
    $normalized = $serializer
      ->normalize($account, $this->defaultFormat, $context);
    $serialized = $serializer
      ->serialize($normalized, $this->defaultFormat, $context);
    $response = $this
      ->httpRequest($account
      ->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
    $this
      ->assertResponse(422);
    $error = Json::decode($response);
    $this
      ->assertEqual($error['error'], "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the <em class=\"placeholder\">Email</em>.\n");

    // Try and send the new email with a password.
    $normalized['pass'][0]['existing'] = 'wrong';
    $serialized = $serializer
      ->serialize($normalized, $this->defaultFormat, $context);
    $response = $this
      ->httpRequest($account
      ->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
    $this
      ->assertResponse(422);
    $error = Json::decode($response);
    $this
      ->assertEqual($error['error'], "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the <em class=\"placeholder\">Email</em>.\n");

    // Try again with the password.
    $normalized['pass'][0]['existing'] = $account->pass_raw;
    $serialized = $serializer
      ->serialize($normalized, $this->defaultFormat, $context);
    $this
      ->httpRequest($account
      ->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
    $this
      ->assertResponse(204);

    // Try to change the password without providing the current password.
    $new_password = $this
      ->randomString();
    $normalized = $serializer
      ->normalize($account, $this->defaultFormat, $context);
    $normalized['pass'][0]['value'] = $new_password;
    $serialized = $serializer
      ->serialize($normalized, $this->defaultFormat, $context);
    $response = $this
      ->httpRequest($account
      ->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
    $this
      ->assertResponse(422);
    $error = Json::decode($response);
    $this
      ->assertEqual($error['error'], "Unprocessable Entity: validation failed.\npass: Your current password is missing or incorrect; it's required to change the <em class=\"placeholder\">Password</em>.\n");

    // Try again with the password.
    $normalized['pass'][0]['existing'] = $account->pass_raw;
    $serialized = $serializer
      ->serialize($normalized, $this->defaultFormat, $context);
    $this
      ->httpRequest($account
      ->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
    $this
      ->assertResponse(204);

    // Verify that we can log in with the new password.
    $account->pass_raw = $new_password;
    $this
      ->drupalLogin($account);
  }

}

Classes

Namesort descending Description
UpdateTest Tests the update of resources.