Newer
Older
<?php
/**
* @file
* Contains \Drupal\rest\Tests\UpdateTest.
*/
namespace Drupal\rest\Tests;
Angie Byron
committed
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
Angie Byron
committed
// resources via the REST API.
Dries Buytaert
committed
$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 = $this->container->get('entity_type.manager')
->getStorage($entity_type)
->create($patch_values);
// We don't want to overwrite the UUID.
$patch_entity->set('uuid', NULL);
$serialized = $serializer->serialize($patch_entity, $this->defaultFormat, $context);
Angie Byron
committed
// 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);
Angie Byron
committed
// 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.');
Dries Buytaert
committed
// 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';
Dries Buytaert
committed
$entity->save();
// Try to empty a field that is access protected.
$this->httpRequest($entity->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
Dries Buytaert
committed
$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.');
Dries Buytaert
committed
// 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);
Dries Buytaert
committed
$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.');
Dries Buytaert
committed
// Restore the valid test value.
$entity->field_test_text->value = $this->randomString();
$entity->save();
Alex Pott
committed
// Try to send no data at all, which does not make sense on PATCH requests.
$this->httpRequest($entity->urlInfo(), 'PATCH', NULL, $this->defaultMimeType);
Alex Pott
committed
$this->assertResponse(400);
// Try to update a non-existing entity with ID 9999.
catch
committed
$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.');
Alex Pott
committed
// Try to send invalid data to trigger the entity validation constraints.
// Send a UUID that is too long.
Alex Pott
committed
$entity->set('uuid', $this->randomMachineName(129));
$invalid_serialized = $serializer->serialize($entity, $this->defaultFormat, $context);
$response = $this->httpRequest($entity->urlInfo(), 'PATCH', $invalid_serialized, $this->defaultMimeType);
Alex Pott
committed
$this->assertResponse(422);
$error = Json::decode($response);
Alex Pott
committed
$this->assertEqual($error['error'], "Unprocessable Entity: validation failed.\nuuid.0.value: <em class=\"placeholder\">UUID</em>: may not be longer than 128 characters.\n");
Alex Pott
committed
// Try to update an entity without proper permissions.
$this->drupalLogout();
$this->httpRequest($entity->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType);
$this->assertResponse(403);
Angie Byron
committed
// 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);
catch
committed
$this->assertResponse(405);
}
Alex Pott
committed
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);
}