You are here

RestfulViewEntityTestCase.test in RESTful 7.2

Same filename and directory in other branches
  1. 7 tests/RestfulViewEntityTestCase.test

File

tests/RestfulViewEntityTestCase.test
View source
<?php

/**
 * @file
 * Contains \RestfulViewEntityTestCase.
 */
use Drupal\restful\Http\RequestInterface;
use Drupal\restful\Http\Request;
class RestfulViewEntityTestCase extends RestfulCurlBaseTestCase {

  /**
   * Overrides DrupalWebTestCase::getInfo().
   */
  public static function getInfo() {
    return array(
      'name' => 'View entity',
      'description' => 'Test the viewing of an entity.',
      'group' => 'RESTful',
    );
  }

  /**
   * Overrides DrupalWebTestCase::setUp().
   */
  public function setUp() {
    parent::setUp('restful_example', 'restful_test', 'entityreference');
    restful_test_add_fields();
  }

  /**
   * Test viewing an entity (GET method).
   *
   * v1.0 - Simple entity view (id, label, self).
   * v1.1 - Text and entity reference fields.
   * v1.2 - "callback" and "process callback".
   * v1.3 - Non-existing "callback" property.
   * v1.4 - Non-existing "process callback" property.
   * v1.6 - XML output format.
   */
  public function testViewEntity() {
    $user1 = $this
      ->drupalCreateUser();
    $entity1 = entity_create('entity_test', array(
      'name' => 'main',
      'uid' => $user1->uid,
    ));
    $entity1
      ->save();
    $entity2 = entity_create('entity_test', array(
      'name' => 'main',
      'uid' => $user1->uid,
    ));
    $entity2
      ->save();
    $entity3 = entity_create('entity_test', array(
      'name' => 'main',
      'uid' => $user1->uid,
    ));
    $wrapper = entity_metadata_wrapper('entity_test', $entity3);
    $text1 = $this
      ->randomName();
    $text2 = $this
      ->randomName();
    $wrapper->text_single
      ->set($text1);
    $wrapper->text_multiple
      ->set(array(
      $text1,
      $text2,
    ));
    $wrapper->entity_reference_single
      ->set($entity1);
    $wrapper->entity_reference_multiple[] = $entity1;
    $wrapper->entity_reference_multiple[] = $entity2;
    $wrapper
      ->save();
    $id = $entity3->pid;
    $base_expected_result = array(
      'id' => $id,
      'label' => 'Main test type',
    );
    $resource_manager = restful()
      ->getResourceManager();

    // v1.0 - Simple entity view (id, label, self).
    $handler = $resource_manager
      ->getPlugin('main:1.0');
    $base_expected_result['self'] = $handler
      ->versionedUrl($id);
    $expected_result = $base_expected_result;
    $response = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->doGet($id), 'json'));
    $response = $response['data'];
    $result = $response[0];
    $this
      ->assertEqual($result, $expected_result, 'Entity view has expected result for "main" resource v1');

    // v1.1 - Text and entity reference field.
    $handler = $resource_manager
      ->getPlugin('main:1.1');
    $request = Request::create('api/main/v1.1/' . $id);
    $handler
      ->setRequest($request);
    $base_expected_result['self'] = $handler
      ->versionedUrl($id);
    $handler
      ->setPath($id);
    $response = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $response = $response['data'];
    $result = $response[0];
    $base_expected_result_v1 = $base_expected_result;

    // NULL fields.
    $base_expected_result_v1 += array(
      'text_single_processing' => NULL,
      'text_multiple_processing' => NULL,
      'term_single' => NULL,
      'term_multiple' => NULL,
      'file_single' => NULL,
      'file_multiple' => NULL,
      'image_single' => NULL,
      'image_multiple' => NULL,
    );
    $expected_result = $base_expected_result_v1;
    $expected_result['text_single'] = $text1;
    $expected_result['text_multiple'] = array(
      $text1,
      $text2,
    );
    $expected_result['entity_reference_single'] = $entity1->pid;
    $expected_result['entity_reference_multiple'] = array(
      $entity1->pid,
      $entity2->pid,
    );
    $request = Request::create('api/main/v1.1/' . $entity1->pid);
    $handler
      ->setRequest($request);
    $handler
      ->setPath($entity1->pid);
    $response = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $response = $response['data'];
    $expected_result['entity_reference_single_resource'] = $response[0];
    $response1 = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process()));
    $response1 = $response1['data'];
    $request2 = Request::create('api/main/v1.1/' . $entity2->pid);
    $handler
      ->setRequest($request2);
    $response2 = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process()));
    $response2 = $response2['data'];
    $expected_result['entity_reference_multiple_resource'] = array(
      $response1[0],
      $response2[0],
    );
    $stripped_result = $result;
    $stripped_result['text_single'] = trim(strip_tags($result['text_single']));
    $stripped_result['text_multiple'][0] = trim(strip_tags($result['text_multiple'][0]));
    $stripped_result['text_multiple'][1] = trim(strip_tags($result['text_multiple'][1]));
    ksort($stripped_result);
    ksort($expected_result);
    $this
      ->assertFalse(drupal_array_diff_assoc_recursive($result, $stripped_result), 'Entity view has correct result for "main" resource v1.1');

    // Test the "fullView" property on a referenced entity.
    // We change the definition via the handler instead of creating another
    // plugin.
    $field_definitions = $handler
      ->getFieldDefinitions();

    // Single entity reference field with "resource".
    $reference_field = $field_definitions
      ->get('entity_reference_single_resource');
    $reference_field
      ->setResource(array(
      'name' => 'main',
      'fullView' => FALSE,
    ));
    $field_definitions
      ->set('entity_reference_single_resource', $reference_field);
    $handler
      ->setFieldDefinitions($field_definitions);
    $request = Request::create('api/main/v1.1/' . $id);
    $handler
      ->setRequest($request);
    $handler
      ->setPath($id);
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $this
      ->assertEqual($result[0]['entity_reference_single_resource'], $entity1->pid, '"fullView" property is working properly.');

    // Empty the text and entity reference fields.
    $wrapper->text_single
      ->set(NULL);
    $wrapper->text_multiple
      ->set(NULL);
    $wrapper->entity_reference_single
      ->set(NULL);
    $wrapper->entity_reference_multiple
      ->set(NULL);
    $wrapper
      ->save();
    $handler
      ->setRequest($request);
    $handler
      ->setPath($id);
    $response = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $response = $response['data'];
    $result = $response[0];
    $expected_result = $base_expected_result_v1;
    $expected_result['text_single'] = NULL;
    $expected_result['text_multiple'] = NULL;
    $expected_result['text_single'] = NULL;
    $expected_result['text_multiple'] = NULL;
    $expected_result['entity_reference_single'] = NULL;
    $expected_result['entity_reference_multiple'] = NULL;
    $expected_result['entity_reference_single_resource'] = NULL;
    $expected_result['entity_reference_multiple_resource'] = NULL;
    ksort($result);
    ksort($expected_result);
    $this
      ->assertEqual($result, $expected_result, 'Entity view has correct result for "main" resource v1.1 with empty entity reference.');

    // Load an entity by an alternate field.
    $entity4 = entity_create('entity_test', array(
      'name' => 'main',
      'uid' => $user1->uid,
    ));
    $wrapper = entity_metadata_wrapper('entity_test', $entity4);
    $text = $this
      ->randomName();
    $wrapper->text_single
      ->set($text);
    $wrapper
      ->save();
    $request = Request::create('api/main/v1.1/' . $text, array(
      'loadByFieldName' => 'text_single',
    ));
    $handler
      ->setRequest($request);
    $handler
      ->setPath($text);
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $this
      ->assertNotNull($result[0]);

    // Make sure canonical header is added.
    $result = $this
      ->httpRequest('api/main/v1.1/' . $text, RequestInterface::METHOD_GET, array(
      'loadByFieldName' => 'text_single',
    ));
    $canonical_link = $handler
      ->versionedUrl($wrapper
      ->getIdentifier(), array(), FALSE) . '; rel="canonical"';
    $this
      ->assertTrue(strpos($result['headers'], $canonical_link));

    // v1.2 - "callback" and "process callback".
    $handler = $resource_manager
      ->getPlugin('main:1.2');
    $request = Request::create('api/main/v1.2/' . $id);
    $handler
      ->setRequest($request);
    $base_expected_result['self'] = $handler
      ->versionedUrl($id);
    $handler
      ->setPath($id);
    $response = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $response = $response['data'];
    $result = $response[0];
    $expected_result = $base_expected_result;
    $expected_result['callback'] = 'callback';
    $expected_result['process_callback_from_callback'] = 'callback processed from callback';
    $expected_result['process_callback_from_value'] = $id . ' processed from value';
    $this
      ->assertEqual($result, $expected_result, 'Entity view has correct result for "main" resource v1.2');

    // v1.3 - Non-existing "callback" property.
    $handler = $resource_manager
      ->getPlugin('main:1.3');
    $request = Request::create('api/main/v1.3/' . $id);
    $handler
      ->setRequest($request);
    try {
      $handler
        ->setPath($id);
      restful()
        ->getFormatterManager()
        ->format($handler
        ->process(), 'json');
      $this
        ->fail('Non-existing "callback" property did not trigger an exception.');
    } catch (Exception $e) {
      $this
        ->pass('Non-existing "callback" property triggered an exception.');
    }

    // v1.4 - Non-existing "process callback" property.
    $handler = $resource_manager
      ->getPlugin('main:1.4');
    $request = Request::create('api/main/v1.4/' . $id);
    $handler
      ->setRequest($request);
    try {
      $handler
        ->setPath($id);
      restful()
        ->getFormatterManager()
        ->format($handler
        ->process(), 'json');
      $this
        ->fail('Non-existing "process callback" property did not trigger an exception.');
    } catch (Exception $e) {
      $this
        ->pass('Non-existing "process callback" property triggered an exception.');
    }

    // v1.6 - XML output format.
    $settings = array(
      'type' => 'article',
      'uid' => $user1->uid,
    );
    $node = $this
      ->drupalCreateNode($settings);
    $response = $this
      ->httpRequest('api/v1.6/articles', RequestInterface::METHOD_GET);

    // Returns something like:
    // <api>
    //   <data>
    //     <item0>
    //       <id>1</id>
    //       <label>Foo</label>
    //       <self>http://example.com/node/1</self>
    //       <body>...</body>
    //     </item0>
    //   </data>
    //   <count>50</count>
    //   <_links>
    //     <next>https://example.com/api/v1.0/articles</next>
    //   </_links>
    // </api>
    $xml = new SimpleXMLElement($response['body']);
    $results = $xml
      ->xpath('/api/_embedded/articles/item0/label');
    $result = reset($results);
    $this
      ->assertEqual($node->title, $result
      ->__toString(), 'XML parsed correctly.');

    // Test Image variations based on image styles.
    // Add the multiple images field to the article bundle.
    $field = array(
      'field_name' => 'field_images',
      'type' => 'image',
      'settings' => array(),
      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
    );
    field_create_field($field);
    $instance = array(
      'field_name' => 'field_images',
      'entity_type' => 'node',
      'label' => 'Image multiple',
      'bundle' => 'article',
    );
    field_create_instance($instance);
    $images = $this
      ->drupalGetTestFiles('image');
    $image = array_shift($images);
    $image = file_save((object) $image);

    // Test multiple Image variations based on image styles.
    $article = array(
      'type' => 'article',
      'field_images' => array(
        LANGUAGE_NONE => array(),
      ),
      'field_image' => array(
        LANGUAGE_NONE => array(
          array(
            'fid' => $image->fid,
          ),
        ),
      ),
    );
    foreach ($images as $image) {
      $image = file_save((object) $image);
      $article['field_images'][LANGUAGE_NONE][] = array(
        'fid' => $image->fid,
      );
    }
    $article = $this
      ->drupalCreateNode($article);
    $resource_manager
      ->clearPluginCache('articles:1.5');
    $handler = $resource_manager
      ->getPlugin('articles:1.5');
    $request = Request::create('api/v1.5/articles/' . $article->nid);
    $handler
      ->setRequest($request);
    $handler
      ->setPath($article->nid);
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $this
      ->assertEqual(array_keys($result[0]['image']['styles']) == array(
      'thumbnail',
      'medium',
      'large',
    ), 'The selected image styles are present.');
    $this
      ->assertEqual(count(array_filter(array_values($result[0]['image']['styles']))) == 3, 'The image styles are populated.');
    $this
      ->assertEqual(count($result[0]['images']), count($images), 'The number of images is correct.');
    $this
      ->assertEqual(array_keys($result[0]['images'][0]['styles']) == array(
      'thumbnail',
      'medium',
      'large',
    ), 'The selected image styles are present.');
    $this
      ->assertEqual(count(array_filter(array_values($result[0]['images'][0]['styles']))) == 3, 'The image styles are populated.');
  }

  /**
   * Test the generation of the Vary headers.
   */
  public function testHeaders() {
    $node = $this
      ->drupalCreateNode(array(
      'type' => 'article',
    ));

    // When there is no header version passed in there is no need of Vary.
    $response = $this
      ->httpRequest('api/v1.1/articles');
    $this
      ->assertFalse(preg_match('/X-API-Version/', $response['headers']), 'The Vary header was not added.');

    // Make sure that the version header is present in the response.
    $this
      ->assertTrue(preg_match('/v1\\.1/', $response['headers']), 'The Vary header was added.');
    $response = $this
      ->httpRequest('api/articles', RequestInterface::METHOD_GET, NULL, array(
      'X-API-Version' => 'v1.1',
    ));
    $this
      ->assertTrue(preg_match('/X-API-Version/', $response['headers']), 'The Vary header was added.');

    // Make sure that the version header is present in the response.
    $this
      ->assertTrue(preg_match('/v1\\.1/', $response['headers']), 'The Vary header was added.');

    // Test that if there is no explicit formatter in the plugin definition then
    // it is selected based on the Accept header.
    variable_set('restful_default_output_formatter', 'invalid');
    $response = $this
      ->httpRequest('api/v1.0/articles/' . $node->nid, RequestInterface::METHOD_GET, NULL, array(
      'Accept' => 'application/hal+json',
    ));
    $this
      ->assertNotNull(drupal_json_decode($response['body']), 'JSON output detected.');

    // Test XML selection.
    $response = $this
      ->httpRequest('api/v1.0/articles/' . $node->nid, RequestInterface::METHOD_GET, NULL, array(
      'Accept' => 'application/xml',
    ));
    $this
      ->assertNotNull(new SimpleXMLElement($response['body']), 'XML output detected.');

    // Test wildcard selection.
    $response = $this
      ->httpRequest('api/v1.0/articles/' . $node->nid, RequestInterface::METHOD_GET, NULL, array(
      'Accept' => 'application/*',
    ));
    $this
      ->assertEqual($response['code'], 200, 'Some output format detected for wildcard Accept.');

    // Test that plugin definition takes precedence.
    $response = $this
      ->httpRequest('api/v1.6/articles/' . $node->nid, RequestInterface::METHOD_GET, NULL, array(
      'Accept' => 'application/hal+json',
    ));
    $this
      ->assertNotNull(new SimpleXMLElement($response['body']), 'Plugin definition takes precedence.');

    // The following should resolve to the 'invalid' formatter. It should raise
    // an exception.
    $response = $this
      ->httpRequest('api/v1.0/articles/' . $node->nid, RequestInterface::METHOD_GET, NULL, array(
      'Accept' => 'non-existing',
    ));
    $this
      ->assertEqual($response['code'], 503, 'Error shown for invalid formatter.');
  }

}

Classes