You are here

RestfulListTestCase.test in RESTful 7.2

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

Contains RestfulListTestCase.

File

tests/RestfulListTestCase.test
View source
<?php

/**
 * @file
 * Contains RestfulListTestCase.
 */
use Drupal\restful\Exception\BadRequestException;
use Drupal\restful\Exception\UnprocessableEntityException;
use Drupal\restful\Http\Request;
use Drupal\restful\Http\RequestInterface;

/**
 * Class RestfulListTestCase.
 */
class RestfulListTestCase extends RestfulCurlBaseTestCase {

  /**
   * {@inheritdoc}
   */
  public static function getInfo() {
    return array(
      'name' => 'List entities',
      'description' => 'Test the listing of entities.',
      'group' => 'RESTful',
    );
  }

  /**
   * {@inheritdoc}
   */
  public function setUp() {
    parent::setUp('restful_example', 'restful_test');
  }

  /**
   * Test the sorting of entities.
   */
  public function testSort() {

    // Allow the anonymous users access to the author field.
    user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array(
      'access user profiles' => TRUE,
    ));
    $user1 = $this
      ->drupalCreateUser();
    $user2 = $this
      ->drupalCreateUser();
    $settings = array(
      'type' => 'article',
    );
    $info = array(
      'abc' => $user1->uid,
      'xyz' => $user1->uid,
      'efg' => $user2->uid,
    );
    $nodes = array();
    foreach ($info as $title => $uid) {
      $settings['title'] = $title;
      $settings['uid'] = $uid;
      $node = $this
        ->drupalCreateNode($settings);
      $nodes[$title] = $node->nid;
    }

    // Add unpublished node, to confirm it is not listed.
    $settings['status'] = NODE_NOT_PUBLISHED;
    $this
      ->drupalCreateNode($settings);
    $resource_manager = restful()
      ->getResourceManager();
    $handler = $resource_manager
      ->getPlugin('articles:1.0');
    $query['fields'] = 'id,label';
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');

    // No sorting (default sorting).
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $expected_result = array(
      array(
        'id' => $nodes['abc'],
        'label' => 'abc',
      ),
      array(
        'id' => $nodes['xyz'],
        'label' => 'xyz',
      ),
      array(
        'id' => $nodes['efg'],
        'label' => 'efg',
      ),
    );
    $this
      ->assertEqual($result, $expected_result, 'No sorting (default sorting).');

    // Sort by ID descending.
    $query['sort'] = '-id';
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $expected_result = array(
      array(
        'id' => $nodes['efg'],
        'label' => 'efg',
      ),
      array(
        'id' => $nodes['xyz'],
        'label' => 'xyz',
      ),
      array(
        'id' => $nodes['abc'],
        'label' => 'abc',
      ),
    );
    $this
      ->assertEqual($result, $expected_result, 'Sort by ID descending.');

    // Sort by label ascending.
    $query['sort'] = 'label';
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $expected_result = array(
      array(
        'id' => $nodes['abc'],
        'label' => 'abc',
      ),
      array(
        'id' => $nodes['efg'],
        'label' => 'efg',
      ),
      array(
        'id' => $nodes['xyz'],
        'label' => 'xyz',
      ),
    );
    $this
      ->assertEqual($result, $expected_result, 'Sort by label ascending.');

    // Sort by label and by ID. For that we add another node titled "abc".
    $settings = array(
      'type' => 'article',
      'title' => 'abc',
    );
    $node = $this
      ->drupalCreateNode($settings);
    $query['sort'] = 'label,id';
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $expected_result = array(
      array(
        'id' => $nodes['abc'],
        'label' => 'abc',
      ),
      array(
        'id' => $node->nid,
        'label' => 'abc',
      ),
      array(
        'id' => $nodes['efg'],
        'label' => 'efg',
      ),
      array(
        'id' => $nodes['xyz'],
        'label' => 'xyz',
      ),
    );
    $this
      ->assertEqual($result, $expected_result, 'Sort by ID and by label.');

    // Test default sorting from plugin definition; by label, then by reverse
    // id.
    $handler = $resource_manager
      ->getPlugin('test_articles:1.1');
    unset($query['sort']);
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $expected_result = array(
      array(
        'id' => $node->nid,
        'label' => 'abc',
        'self' => $handler
          ->versionedUrl($node->nid),
      ),
      array(
        'id' => $nodes['abc'],
        'label' => 'abc',
        'self' => $handler
          ->versionedUrl($nodes['abc']),
      ),
      array(
        'id' => $nodes['efg'],
        'label' => 'efg',
        'self' => $handler
          ->versionedUrl($nodes['efg']),
      ),
      array(
        'id' => $nodes['xyz'],
        'label' => 'xyz',
        'self' => $handler
          ->versionedUrl($nodes['xyz']),
      ),
    );
    $this
      ->assertEqual($result, $expected_result, 'Default sort by ID and by label.');

    // Test that the default sort can be overridden.
    $query['sort'] = 'id';
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $expected_result = array(
      array(
        'id' => $nodes['abc'],
        'label' => 'abc',
        'self' => $handler
          ->versionedUrl($nodes['abc']),
      ),
      array(
        'id' => $nodes['xyz'],
        'label' => 'xyz',
        'self' => $handler
          ->versionedUrl($nodes['xyz']),
      ),
      array(
        'id' => $nodes['efg'],
        'label' => 'efg',
        'self' => $handler
          ->versionedUrl($nodes['efg']),
      ),
      array(
        'id' => $node->nid,
        'label' => 'abc',
        'self' => $handler
          ->versionedUrl($node->nid),
      ),
    );
    $this
      ->assertEqual($result, $expected_result, 'Sort by ID, overriding default sort.');

    // Illegal sort property.
    $query['sort'] = 'wrong_key';
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    try {
      restful()
        ->getFormatterManager()
        ->format($handler
        ->process(), 'json');
      $this
        ->fail('Illegal sort property used.');
    } catch (BadRequestException $e) {
      $this
        ->pass('Exception thrown on illegal sort property.');
    }

    // Illegal sort property, descending.
    $query['sort'] = '-wrong_key';
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    try {
      restful()
        ->getFormatterManager()
        ->format($handler
        ->process(), 'json');
      $this
        ->fail('Illegal sort property, descending, used.');
    } catch (BadRequestException $e) {
      $this
        ->pass('Exception thrown on illegal sort property, descending.');
    }

    // Test valid sort with sort params disabled.
    $resource_manager
      ->clearPluginCache($handler
      ->getPluginId());
    $plugin_definition = $handler
      ->getPluginDefinition();
    $plugin_definition['dataProvider']['urlParams'] = array(
      'filter' => TRUE,
      'sort' => FALSE,
      'range' => TRUE,
    );
    $handler
      ->setPluginDefinition($plugin_definition);

    // Re-instantiate the data provider.
    $handler
      ->setDataProvider(NULL);
    $query['sort'] = 'label,id';
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    try {
      restful()
        ->getFormatterManager()
        ->format($handler
        ->process(), 'json');
      $this
        ->fail('Exception not raised for disabled sort parameter.');
    } catch (UnprocessableEntityException $e) {
      $this
        ->pass('Exception raised for disabled sort parameter.');
    }

    // Test the range overrides.
    unset($query['sort']);
    $query['range'] = 2;
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $this
      ->assertEqual(count($result), $query['range'], 'Range parameter overridden correctly');

    // Test the max cap in the the annotation configuration.
    $resource_manager
      ->clearPluginCache($handler
      ->getPluginId());
    $plugin_definition = $handler
      ->getPluginDefinition();
    $plugin_definition['range'] = 1;
    $handler
      ->setPluginDefinition($plugin_definition);
    $query['range'] = 2;
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->doGet('', $query), 'json'));
    $this
      ->assertEqual(count($result['data']), $query['range'], 'Range is limited to the configured maximum.');

    // Test invalid range.
    $query['range'] = $this
      ->randomName();
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    try {
      restful()
        ->getFormatterManager()
        ->format($handler
        ->process(), 'json');
      $this
        ->fail('Exception not raised on invalid range parameter.');
    } catch (BadRequestException $e) {
      $this
        ->pass('Exception raised on invalid range parameter.');
    }

    // Test valid range with range params disabled.
    $resource_manager
      ->clearPluginCache($handler
      ->getPluginId());
    $plugin_definition = $handler
      ->getPluginDefinition();
    $plugin_definition['dataProvider']['urlParams'] = array(
      'filter' => TRUE,
      'sort' => TRUE,
      'range' => FALSE,
    );

    // Unset the previously added range.
    unset($plugin_definition['range']);
    $handler
      ->setPluginDefinition($plugin_definition);

    // Re-instantiate the data provider.
    $handler
      ->setDataProvider(NULL);
    $query['range'] = 2;
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    try {
      restful()
        ->getFormatterManager()
        ->format($handler
        ->process(), 'json');
      $this
        ->fail('Exception not raised for disabled range parameter.');
    } catch (UnprocessableEntityException $e) {
      $this
        ->pass('Exception raised for disabled range parameter.');
    }

    // Sort by an entity metadata wrapper property that is different from the
    // DB column name.
    $handler = $resource_manager
      ->getPlugin('articles:1.5');
    $query = array(
      'sort' => '-user',
    );
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $this
      ->assertEqual($result[0]['user']['id'], 3, 'List sorted by the "author" entity metadata wrapper property, which maps to the "uid" DB column name.');
    $query = array(
      'sort' => 'static',
    );
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    try {
      restful()
        ->getFormatterManager()
        ->format($handler
        ->process(), 'json');
      $this
        ->fail('Exception not thrown for invalid sort.');
    } catch (BadRequestException $e) {
      $this
        ->pass('Exception thrown for invalid sort.');
    }
  }

  /**
   * Test filtering.
   */
  public function testFilter() {
    $resource_manager = restful()
      ->getResourceManager();
    $user1 = $this
      ->drupalCreateUser();
    $user2 = $this
      ->drupalCreateUser();
    $this
      ->addIntegerFields();
    $info = array(
      array(
        'title' => 'abc',
        'integer_single' => 1,
        'integer_multiple' => array(
          1,
          2,
          3,
        ),
        'uid' => $user1->uid,
      ),
      array(
        'title' => 'another abc',
        'integer_single' => 5,
        'integer_multiple' => array(
          3,
          4,
          5,
        ),
        'uid' => $user1->uid,
      ),
      array(
        'title' => 'last',
        'integer_single' => NULL,
        'integer_multiple' => array(),
        'uid' => $user2->uid,
      ),
    );
    $nodes = array();
    foreach ($info as $row) {
      $title = $row['title'];
      $settings = array(
        'type' => 'article',
        'title' => $title,
      );
      $settings['integer_single'][LANGUAGE_NONE][0]['value'] = $row['integer_single'];
      foreach ($row['integer_multiple'] as $key => $value) {
        $settings['integer_multiple'][LANGUAGE_NONE][$key]['value'] = $value;
      }
      $settings['uid'] = $row['uid'];
      $node = $this
        ->drupalCreateNode($settings);
      $nodes[$title] = $node->nid;
    }
    $handler = $resource_manager
      ->getPlugin('test_articles:1.2');
    $fields = array(
      'id',
      'label',
      'integer_single',
      'intger_multiple',
    );
    $query['fields'] = implode(',', $fields);

    // Single value property.
    $query['filter'] = array(
      'label' => 'abc',
    );
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $this
      ->assertEqual($result[0]['id'], $nodes['abc'], 'Filter list by single value property.');

    // Assert count is correct.
    $formatter_handler = restful()
      ->getFormatterManager()
      ->getPlugin('hal_json');
    $instance_configuration = $formatter_handler
      ->getConfiguration();
    $formatter_handler
      ->setConfiguration(array_merge($instance_configuration ?: array(), array(
      'resource' => $handler,
    )));
    $output = $formatter_handler
      ->prepare($result);
    $this
      ->assertEqual($output['count'], 1, '"count" property is correct.');

    // Single value field.
    $resource_manager
      ->clearPluginCache($handler
      ->getPluginId());
    $handler = $resource_manager
      ->getPlugin('test_articles:1.2');
    $query['filter'] = array(
      'integer_single' => '1',
    );
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $this
      ->assertEqual($result[0]['id'], $nodes['abc'], 'Filter list by Single value field.');

    // LIKE operator.
    $input['filter'] = array(
      'label' => array(
        'value' => '%nothe%',
        'operator' => 'LIKE',
      ),
    );
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->doGet('', $input), 'json'));
    $result = $result['data'];
    $this
      ->assertEqual($result[0]['id'], $nodes['another abc'], 'Filter list using LIKE operator.');

    // STARTS_WITH operator.
    $input['filter'] = array(
      'label' => array(
        'value' => 'las',
        'operator' => 'STARTS_WITH',
      ),
    );
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->doGet('', $input), 'json'));
    $result = $result['data'];
    $this
      ->assertEqual($result[0]['id'], $nodes['last'], 'Filter list using STARTS_WITH operator.');

    // CONTAINS operator.
    $input['filter'] = array(
      'label' => array(
        'value' => 'bc',
        'operator' => 'CONTAINS',
      ),
    );
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->doGet('', $input), 'json'));
    $result = $result['data'];

    // Sort the results before checking it.
    usort($result, function ($a, $b) {
      return strcmp($a['label'], $b['label']);
    });
    $this
      ->assertEqual($result[0]['id'], $nodes['abc'], 'Filter list using CONTAINS operator.');
    $this
      ->assertEqual($result[1]['id'], $nodes['another abc'], 'Filter list using CONTAINS operator.');

    // Multiple value field.
    $query['filter'] = array(
      'integer_multiple' => array(
        'value' => array(
          4,
          5,
        ),
        'operator' => 'BETWEEN',
      ),
    );
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $this
      ->assertEqual($result[0]['id'], $nodes['another abc'], 'Filter list by multiple value field.');

    // Invalid key.
    $query['filter'] = array(
      'invalid_key' => '3',
    );
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    try {
      restful()
        ->getFormatterManager()
        ->format($handler
        ->process(), 'json');
      $this
        ->fail('No exception was thrown on invalid key for filter.');
    } catch (BadRequestException $e) {
      $this
        ->pass('Correct exception was thrown on invalid key for filter.');
    } catch (\Exception $e) {
      $this
        ->fail('Incorrect exception was thrown on invalid key for filter.');
    }

    // Assert filtering doesn't apply for non-list request
    // (e.g. /api/v1.0/articles/1?filter[label]=foo), as this might be called
    // from a formatter plugin, after RESTful's error handling has finished.
    $query_string = array(
      'filter' => array(
        'invalid-key' => 'foo',
      ),
    );
    $result = $this
      ->httpRequest('api/v1.0/articles/1', RequestInterface::METHOD_GET, $query_string);
    $this
      ->assertEqual($result['code'], '200', 'Invalid filter key was ignored on non-list query.');

    // Test multiple filters on the same field.
    $query = array(
      'filter' => array(
        'integer_single' => array(
          'value' => array(
            1,
            4,
          ),
          'operator' => array(
            '>',
            '<>',
          ),
        ),
      ),
    );
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $this
      ->assertEqual($nodes['another abc'], $result[0]['id']);
    $query = array(
      'filter' => array(
        'integer_single' => array(
          'value' => array(
            1,
            5,
          ),
          'operator' => array(
            '>',
            '<>',
          ),
        ),
      ),
    );
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $this
      ->assertEqual($result, array());
    $query = array(
      'filter' => array(
        'integer_multiple' => array(
          'value' => array(
            3,
            4,
          ),
        ),
      ),
    );
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $this
      ->assertEqual($nodes['another abc'], $result[0]['id']);

    // Test valid filter with filter params disabled.
    $resource_manager
      ->clearPluginCache($handler
      ->getPluginId());
    $plugin_definition = $handler
      ->getPluginDefinition();
    $plugin_definition['dataProvider']['urlParams'] = array(
      'filter' => FALSE,
      'sort' => TRUE,
      'range' => TRUE,
    );
    $handler
      ->setPluginDefinition($plugin_definition);
    $handler
      ->setDataProvider(NULL);
    $query['filter'] = array(
      'label' => 'abc',
    );
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    try {
      restful()
        ->getFormatterManager()
        ->format($handler
        ->process(), 'json');
      $this
        ->fail('Exception not raised for disabled filter parameter.');
    } catch (UnprocessableEntityException $e) {
      $this
        ->pass('Exception raised for disabled filter parameter.');
    }

    // Filter by an entity metadata wrapper property that is different from the
    // DB column name.
    $handler = $resource_manager
      ->getPlugin('articles:1.5');
    $query = array(
      'filter' => array(
        'user' => array(
          'value' => $user1->uid,
        ),
      ),
    );
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $result = $result['data'];
    $this
      ->assertEqual(count($result), 2, 'List filtered by the "author" entity metadata wrapper property, which maps to the "uid" DB column name.');
    $query = array(
      'filter' => array(
        'static' => array(
          'value' => 0,
        ),
      ),
    );
    $handler
      ->setRequest(Request::create('', $query, RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    try {
      restful()
        ->getFormatterManager()
        ->format($handler
        ->process(), 'json');
      $this
        ->fail('Illegal filter property used.');
    } catch (BadRequestException $e) {
      $this
        ->pass('Exception thrown on illegal filter property.');
    }
  }

  /**
   * Test pagination.
   */
  public function testPagination() {
    $resource_manager = restful()
      ->getResourceManager();
    foreach (range(1, 9) as $key) {
      $settings = array(
        'type' => 'article',
        'title' => $key,
      );
      $this
        ->drupalCreateNode($settings);
    }
    $handler = $resource_manager
      ->getPlugin('articles:1.0');
    $formatter_handler = restful()
      ->getFormatterManager()
      ->negotiateFormatter('');
    $instance_configuration = $formatter_handler
      ->getConfiguration();
    $formatter_handler
      ->setConfiguration(array_merge($instance_configuration ?: array(), array(
      'resource' => $handler,
    )));

    // Set a smaller range for the pagination.
    $data_provider = $handler
      ->getDataProvider();
    $data_provider
      ->setRange(3);

    // Check pagination of first page.
    $handler
      ->setRequest(Request::create('', array(
      'page' => 1,
    ), RequestInterface::METHOD_GET));
    $handler
      ->setPath('');
    $result = drupal_json_decode($formatter_handler
      ->format($handler
      ->process()));
    $this
      ->assertEqual(count($result['data']), 3);
    $this
      ->assertTrue($result['next'], '"Next" link exists on the first page.');
    $this
      ->assertTrue(empty($result['previous']), '"Previous" link does not exist on the first page.');

    // Check pagination of middle pages.
    $handler
      ->setRequest(Request::create('', array(
      'page' => 2,
    ), RequestInterface::METHOD_GET));
    $result = drupal_json_decode($formatter_handler
      ->format($handler
      ->process()));
    $this
      ->assertTrue($result['next'], '"Next" link exists on the middle page.');
    $this
      ->assertEqual($result['next']['href'], $handler
      ->versionedUrl('', array(
      'query' => array(
        'page' => array(
          'number' => 3,
        ),
      ),
    )));
    $this
      ->assertTrue($result['previous'], '"Previous" link exists on the middle page.');
    $this
      ->assertEqual($result['previous']['href'], $handler
      ->versionedUrl('', array(
      'query' => array(
        'page' => array(
          'number' => 1,
        ),
      ),
    )));

    // Check pagination of last page.
    $handler
      ->setRequest(Request::create('', array(
      'page' => 3,
    ), RequestInterface::METHOD_GET));
    $result = drupal_json_decode($formatter_handler
      ->format($handler
      ->process()));
    $this
      ->assertTrue(empty($result['next']), '"Next" link does not exist on the last page.');
    $this
      ->assertTrue($result['previous'], '"Previous" link exists on the last page.');

    // Check other query strings are retained in the _links.
    $handler
      ->setRequest(Request::create('', array(
      'page' => 3,
      'sort' => '-id',
    ), RequestInterface::METHOD_GET));
    $result = drupal_json_decode($formatter_handler
      ->format($handler
      ->process()));
    $this
      ->assertTrue(strpos($result['previous']['href'], 'sort=-id'), 'Query strings are retained in the _links.');

    // Check pagination with non-numeric value.
    $handler
      ->setRequest(Request::create('', array(
      'page' => 'string',
    ), RequestInterface::METHOD_GET));
    try {
      restful()
        ->getFormatterManager()
        ->format($handler
        ->process(), 'json');
      $this
        ->fail('No exception thrown for pagination with non-numeric value.');
    } catch (BadRequestException $e) {
      $this
        ->pass('Correct exception thrown for pagination with non-numeric value.');
    } catch (\Exception $e) {
      $this
        ->fail('Incorrect exception thrown for pagination with non-numeric value.');
    }

    // Check pagination with 0 value.
    $handler
      ->setRequest(Request::create('', array(
      'page' => 0,
    ), RequestInterface::METHOD_GET));
    try {
      restful()
        ->getFormatterManager()
        ->format($handler
        ->process(), 'json');
      $this
        ->fail('No exception thrown for pagination with 0 value.');
    } catch (BadRequestException $e) {
      $this
        ->pass('Correct exception thrown for pagination with 0 value.');
    } catch (\Exception $e) {
      $this
        ->fail('Incorrect exception thrown for pagination with 0 value.');
    }

    // Check pagination with high number, where there are not items, yielded no
    // results, but is a valid call.
    $handler
      ->setRequest(Request::create('', array(
      'page' => 100,
    ), RequestInterface::METHOD_GET));
    $result = drupal_json_decode($formatter_handler
      ->format($handler
      ->process()));
    $this
      ->assertEqual($result['data'], array(), 'pagination with high number, where there are not items yielded no results.');

    // Check total number of results.
    $handler
      ->setRequest(Request::create('', array(
      'page' => 3,
    ), RequestInterface::METHOD_GET));
    $result = drupal_json_decode($formatter_handler
      ->format($handler
      ->process()));
    $this
      ->assertEqual($result['count'], 9, 'Total count exists and is correct.');
  }

  /**
   * Helper function; Add single and multiple integer fields.
   */
  private function addIntegerFields() {

    // Integer - single.
    $field = array(
      'field_name' => 'integer_single',
      'type' => 'number_integer',
      'entity_types' => array(
        'node',
      ),
      'cardinality' => 1,
    );
    field_create_field($field);
    $instance = array(
      'field_name' => 'integer_single',
      'bundle' => 'article',
      'entity_type' => 'node',
      'label' => t('Integer single'),
    );
    field_create_instance($instance);

    // Integer - multiple.
    $field = array(
      'field_name' => 'integer_multiple',
      'type' => 'number_integer',
      'entity_types' => array(
        'node',
      ),
      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
    );
    field_create_field($field);
    $instance = array(
      'field_name' => 'integer_multiple',
      'bundle' => 'article',
      'entity_type' => 'node',
      'label' => t('Integer multiple'),
    );
    field_create_instance($instance);
  }

  /**
   * Test error handling when no access is granted to an entity in a list.
   */
  public function testAccessHandling() {
    $resource_manager = restful()
      ->getResourceManager();
    $settings = array(
      'type' => 'article',
    );
    $node1 = $this
      ->drupalCreateNode($settings);
    $node2 = $this
      ->drupalCreateNode($settings);
    $node3 = $this
      ->drupalCreateNode($settings);
    $user1 = $this
      ->drupalCreateUser();

    // Deny access via hook_node_access() to a specific node.
    restful_test_deny_access_node($node2->nid);
    variable_set('restful_show_access_denied', TRUE);
    $handler = $resource_manager
      ->getPlugin('articles:1.0');
    $handler
      ->setAccount($user1);
    $handler
      ->setRequest(Request::create('api/articles/v1.0'));
    $handler
      ->setPath('');
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $this
      ->assertEqual(count($result['data']), 2, 'List returned and ignored un-accessible entity.');
    $this
      ->assertEqual(count($result['denied']), 1, 'A denied entity was detected.');

    // Get a list with specific IDs.
    $ids = array(
      $node1->nid,
      $node2->nid,
      $node3->nid,
    );
    $handler
      ->setRequest(Request::create('api/articles/v1.0' . implode(',', $ids)));
    $handler
      ->setPath(implode(',', $ids));
    $result = drupal_json_decode(restful()
      ->getFormatterManager()
      ->format($handler
      ->process(), 'json'));
    $this
      ->assertEqual(count($result['data']), 2, 'List of specific items returned and ignored un-accessible entity.');
    $this
      ->assertEqual(count($result['denied']), 1, 'A denied entity was detected.');
  }

  /**
   * Test node count and pager when there are unpublished nodes.
   */
  public function testCountWithUnpublished() {
    foreach (range(1, 9) as $key) {
      $settings = array(
        'type' => 'article',
        'title' => $key,
        'status' => NODE_PUBLISHED,
      );
      $this
        ->drupalCreateNode($settings);
    }
    foreach (range(1, 3) as $key) {
      $settings = array(
        'type' => 'article',
        'title' => $key,
        'status' => NODE_NOT_PUBLISHED,
      );
      $this
        ->drupalCreateNode($settings);
    }
    $handler = restful()
      ->getResourceManager()
      ->getPlugin('articles:1.0');
    $formatter = restful()
      ->getFormatterManager()
      ->getPlugin('json');
    $formatter
      ->setResource($handler);

    // Set a range for pagination to check only .
    $handler
      ->getDataProvider()
      ->setRange(9);

    // Check pagination of first page.
    $result = $handler
      ->doGet('', array(
      'page' => 1,
    ));
    $output = drupal_json_decode($formatter
      ->format($result));
    $this
      ->assertEqual(count($result), 9, 'Number of results displayed');
    $this
      ->assertEqual(count($result), $handler
      ->getDataProvider()
      ->count(), 'Count of results takes into account unpublished nodes');
    $this
      ->assertTrue(empty($output['next']), '"Next" link does not exist on the first page.');
    $this
      ->assertTrue(empty($output['previous']), '"Previous" link does not exist on the first page.');
  }

}

Classes

Namesort descending Description
RestfulListTestCase Class RestfulListTestCase.