UpdateTest.php 10.2 KB
Newer Older
1 2 3 4
<?php

/**
 * @file
5
 * Contains \Drupal\rest\Tests\UpdateTest.
6 7 8 9
 */

namespace Drupal\rest\Tests;

10
use Drupal\Component\Serialization\Json;
11 12

/**
13 14 15
 * Tests the update of resources.
 *
 * @group rest
16 17 18 19
 */
class UpdateTest extends RESTTestBase {

  /**
20
   * Modules to install.
21 22 23
   *
   * @var array
   */
24
  public static $modules = array('hal', 'rest', 'entity_test');
25 26 27 28 29

  /**
   * Tests several valid and invalid partial update requests on test entities.
   */
  public function testPatchUpdate() {
30
    $serializer = $this->container->get('serializer');
31
    // @todo Test all other entity types here as well.
32 33
    $entity_type = 'entity_test';

34
    $this->enableService('entity:' . $entity_type, 'PATCH');
35
    // Create a user account that has the required permissions to create
36
    // resources via the REST API.
37 38 39
    $permissions = $this->entityPermissions($entity_type, 'update');
    $permissions[] = 'restful patch entity:' . $entity_type;
    $account = $this->drupalCreateUser($permissions);
40 41
    $this->drupalLogin($account);

42 43
    $context = ['account' => $account];

44 45 46 47 48
    // 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.
49 50 51 52
    $patch_values['field_test_text'] = array(0 => array(
      'value' => $this->randomString(),
      'format' => 'plain_text',
    ));
53 54 55
    $patch_entity = $this->container->get('entity_type.manager')
      ->getStorage($entity_type)
      ->create($patch_values);
56
    // We don't want to overwrite the UUID.
57
    $patch_entity->set('uuid', NULL);
58
    $serialized = $serializer->serialize($patch_entity, $this->defaultFormat, $context);
59

60
    // Update the entity over the REST API.
61
    $this->httpRequest($entity->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
62 63 64 65 66 67
    $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.');

68 69
    // Make sure that the field does not get deleted if it is not present in the
    // PATCH request.
70
    $normalized = $serializer->normalize($patch_entity, $this->defaultFormat, $context);
71 72
    unset($normalized['field_test_text']);
    $serialized = $serializer->encode($normalized, $this->defaultFormat);
73
    $this->httpRequest($entity->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
74 75 76 77 78 79
    $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.
80
    $normalized['field_test_text'] = array();
81
    $serialized = $serializer->encode($normalized, $this->defaultFormat);
82

83
    // Update the entity over the REST API.
84
    $this->httpRequest($entity->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
85 86 87 88 89 90
    $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.');

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

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

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

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

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

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

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

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

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

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

146 147
    // Try to send invalid data to trigger the entity validation constraints.
    // Send a UUID that is too long.
148
    $entity->set('uuid', $this->randomMachineName(129));
149
    $invalid_serialized = $serializer->serialize($entity, $this->defaultFormat, $context);
150
    $response = $this->httpRequest($entity->urlInfo(), 'PATCH', $invalid_serialized, $this->defaultMimeType);
151
    $this->assertResponse(422);
152
    $error = Json::decode($response);
153
    $this->assertEqual($error['error'], "Unprocessable Entity: validation failed.\nuuid.0.value: <em class=\"placeholder\">UUID</em>: may not be longer than 128 characters.\n");
154

155 156
    // Try to update an entity without proper permissions.
    $this->drupalLogout();
157
    $this->httpRequest($entity->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
158 159
    $this->assertResponse(403);

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

167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
  /**
   * 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);

  }

231
}