diff --git a/core/modules/rest/src/Tests/NodeTest.php b/core/modules/rest/src/Tests/NodeTest.php index ccbee60..02b5ae9 100644 --- a/core/modules/rest/src/Tests/NodeTest.php +++ b/core/modules/rest/src/Tests/NodeTest.php @@ -42,6 +42,28 @@ protected function enableNodeConfiguration($method, $operation) { $this->drupalLogin($account); } + protected function postNode($data) { + $this->enableNodeConfiguration('POST', 'create'); + $this->enableService('entity:node', 'POST', 'json'); + + // Create a JSON version of a simple node with the title. + $serialized = $this->container->get('serializer')->serialize($data, 'json'); + + // Post to the REST service to create the node. + return $this->httpRequest('/entity/node', 'POST', $serialized, 'application/json'); + } + + protected function assertNodeTitleMatch($data) { + /** @var \Drupal\node\Entity\Node $node */ + // Load the newly created node. + $node = Node::load(1); + + // Test that the title is the same as what we posted. + $this->assertEqual($node->title->value, $data['title'][0]['value']); + + return $node; + } + /** * Performs various tests on nodes and their REST API. */ @@ -95,35 +117,75 @@ public function testNodes() { * Test creating a node using json serialization. */ public function testCreate() { - $this->enableNodeConfiguration('POST', 'create'); - $this->enableService('entity:node', 'POST', 'json'); - - // Create a title. - $title = $this->randomString(); - // Data to be used for serialization. $data = [ 'type' => [['target_id' => 'resttest']], - 'title' => [['value' => $title ]], + 'title' => [['value' => $this->randomString() ]], ]; - // Create a JSON version of a simple node with the title. - $serialized = $this->container->get('serializer')->serialize($data, 'json'); - - // Post to the REST service to create the node. - $this->httpRequest('/entity/node', 'POST', $serialized, 'application/json'); + $this->postNode($data); // Make sure the response is "CREATED". $this->assertResponse(201); - /** @var \Drupal\node\Entity\Node $node */ - // Load the newly created node. - $node = Node::load(1); - - // Test that the title is the same as what we posted. - $this->assertEqual($node->title->value, $title); + // Make sure the node was created and the title matches. + $node = $this->assertNodeTitleMatch($data); // Make sure the request returned a redirect header to view the node. $this->assertHeader('Location', $node->url('canonical', ['absolute' => TRUE])); } + + /** + * Test bundle normalization when posting bundle as a simple string. + */ + public function testBundleNormalization() { + // Data to be used for serialization. + $data = [ + 'type' => 'resttest', + 'title' => [['value' => $this->randomString() ]], + ]; + + // testing + $this->postNode($data); + + // Make sure the response is "CREATED". + $this->assertResponse(201); + + // Make sure the node was created and the title matches. + $this->assertNodeTitleMatch($data); + } + + /** + * Test bundle normalization when posting using a simple string. + */ + public function testInvalidBundle() { + // Data to be used for serialization. + $data = [ + 'type' => 'bad_bundle_name', + 'title' => [['value' => $this->randomString() ]], + ]; + + $this->postNode($data); + + // Make sure the response is "Bad Request". + $this->assertResponse(400); + $this->assertResponseBody('{"error":"\"bad_bundle_name\" is not a valid bundle type for denormalization."}'); + } + + /** + * Test when the bundle is missing. + */ + public function testMissingBundle() { + // Data to be used for serialization. + $data = [ + 'title' => [['value' => $this->randomString() ]], + ]; + + // testing + $this->postNode($data); + + // Make sure the response is "Bad Request". + $this->assertResponse(400); + $this->assertResponseBody('{"error":"\"\" is not a valid bundle type for denormalization."}'); + } } diff --git a/core/modules/rest/src/Tests/RESTTestBase.php b/core/modules/rest/src/Tests/RESTTestBase.php index 46003af..b75a02a 100644 --- a/core/modules/rest/src/Tests/RESTTestBase.php +++ b/core/modules/rest/src/Tests/RESTTestBase.php @@ -7,11 +7,9 @@ namespace Drupal\rest\Tests; -use Drupal\Core\Session\AccountInterface; -use Drupal\Core\Url; +use Drupal\Component\Utility\SafeMarkup; use Drupal\node\NodeInterface; use Drupal\simpletest\WebTestBase; -use Drupal\user\UserInterface; /** * Test helper class that provides a REST client method to send HTTP requests. @@ -46,6 +44,14 @@ */ protected $defaultAuth; + + /** + * The raw response body from http request operations. + * + * @var array + */ + protected $responseBody; + /** * Modules to install. * @@ -153,7 +159,7 @@ protected function httpRequest($url, $method, $body = NULL, $mime_type = NULL) { break; } - $response = $this->curlExec($curl_options); + $this->responseBody = $this->curlExec($curl_options); // Ensure that any changes to variables in the other thread are picked up. $this->refreshVariables(); @@ -163,9 +169,9 @@ protected function httpRequest($url, $method, $body = NULL, $mime_type = NULL) { $this->verbose($method . ' request to: ' . $url . '
Code: ' . curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE) . '
Response headers: ' . nl2br(print_r($headers, TRUE)) . - '
Response body: ' . $response); + '
Response body: ' . $this->responseBody); - return $response; + return $this->responseBody; } /** @@ -361,4 +367,27 @@ protected function removeNodeFieldsForNonAdminUsers(NodeInterface $node) { return $node; } + /** + * Check to see if the http request response body is identical to the expected + * value. + * + * @param $expected + * The first value to check. + * @param $message + * (optional) A message to display with the assertion. Do not translate + * messages: use \Drupal\Component\Utility\SafeMarkup::format() to embed + * variables in the message text, not t(). If left blank, a default message + * will be displayed. + * @param $group + * (optional) The group this message is in, which is displayed in a column + * in test output. Use 'Debug' to indicate this is debugging output. Do not + * translate this string. Defaults to 'Other'; most tests do not override + * this default. + * + * @return + * TRUE if the assertion succeeded, FALSE otherwise. + */ + protected function assertResponseBody($expected, $message = '', $group = 'REST Response') { + return $this->assertIdentical($expected, $this->responseBody, $message ? $message : SafeMarkup::format('Response body @expected (expected) is equal to @response (actual).', array('@expected' => var_export($expected, TRUE), '@response' => var_export($this->responseBody, TRUE))), $group); + } } diff --git a/core/modules/serialization/src/Normalizer/EntityNormalizer.php b/core/modules/serialization/src/Normalizer/EntityNormalizer.php index 219c263..35aa0b0 100644 --- a/core/modules/serialization/src/Normalizer/EntityNormalizer.php +++ b/core/modules/serialization/src/Normalizer/EntityNormalizer.php @@ -47,18 +47,18 @@ public function denormalize($data, $class, $format = NULL, array $context = []) // Get the entity type ID letting the context definition override the $class. $entity_type_id = !empty($context['entity_type']) ? $context['entity_type'] : $this->entityManager->getEntityTypeFromClass($class); - /** @var \Drupal\Core\Entity\EntityTypeInterface $entity_type */ + /** @var \Drupal\Core\Entity\EntityTypeInterface $entity_type_definition */ // Get the entity type definition. - $entity_type = $this->entityManager->getDefinition($entity_type_id, FALSE); + $entity_type_definition = $this->entityManager->getDefinition($entity_type_id, FALSE); // Don't try to create an entity without an entity type id. - if (!$entity_type) { + if (!$entity_type_definition) { throw new UnexpectedValueException('A valid entity type is required for denormalization.'); } // The bundle property will be required to denormalize a bundleable entity. - if ($entity_type->hasKey('bundle')) { - $bundle_key = $entity_type->getKey('bundle'); + if ($entity_type_definition->hasKey('bundle')) { + $bundle_key = $entity_type_definition->getKey('bundle'); // Get the base field definitions for this entity type. $base_field_definitions = $this->entityManager->getBaseFieldDefinitions($entity_type_id); @@ -70,12 +70,16 @@ public function denormalize($data, $class, $format = NULL, array $context = []) } // Normalize the bundle if it is not explicitly set. - $data[$bundle_key] = isset($data[$bundle_key][0][$key_id]) ? $data[$bundle_key][0][$key_id] : $data[$bundle_key]; + $data[$bundle_key] = isset($data[$bundle_key][0][$key_id]) + ? $data[$bundle_key][0][$key_id] + : (isset($data[$bundle_key]) ? $data[$bundle_key] : NULL); - $bundle_entity_type = $entity_type->getBundleEntityType(); + // Get the bundle entity type from the entity type definition. + $bundle_entity_type = $entity_type_definition->getBundleEntityType(); + // @todo http://drupal.org/node/2346857 default to NULL. $bundle_types = ($bundle_entity_type !== 'bundle') ? $this->entityManager->getStorage($bundle_entity_type)->getQuery()->execute() : []; - // Make sure the bundle is a simple string. + // Make sure the submitted bundle is a valid bundle for the entity type. if (!is_string($data[$bundle_key]) || ($bundle_types && !in_array($data[$bundle_key], $bundle_types))) { throw new UnexpectedValueException(sprintf('"%s" is not a valid bundle type for denormalization.', $data[$bundle_key])); }