View source
<?php
namespace Drupal\Tests\lightning_api\Functional;
use Drupal\Component\Serialization\Json;
use Drupal\consumers\Entity\Consumer;
use Drupal\Core\Url;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\Tests\BrowserTestBase;
use GuzzleHttp\Exception\ClientException;
use Psr\Http\Message\ResponseInterface;
class ApiTest extends BrowserTestBase {
protected $defaultTheme = 'stark';
protected static $modules = [
'lightning_api',
'taxonomy',
];
protected function setUp() {
parent::setUp();
$this
->config('jsonapi.settings')
->set('read_only', FALSE)
->save();
$account = $this
->drupalCreateUser([], NULL, TRUE);
$this
->drupalLogin($account);
$url = Url::fromRoute('lightning_api.generate_keys');
$values = [
'dir' => \Drupal::service('file_system')
->realpath('temporary://'),
'private_key' => 'private.key',
'public_key' => 'public.key',
];
$conf = getenv('OPENSSL_CONF');
if ($conf) {
$values['conf'] = $conf;
}
$this
->drupalPostForm($url, $values, 'Generate keys');
$this
->assertSession()
->pageTextContains('A key pair was generated successfully.');
$this
->drupalLogout();
}
protected function createContentType(array $values = []) {
$node_type = $this
->drupalCreateContentType($values);
$this->container
->get('router.builder')
->rebuild();
return $node_type;
}
private function getCreator($node_type) {
return $this
->createApiUser([
"access content",
"bypass node access",
"create {$node_type} content",
"create url aliases",
"delete {$node_type} revisions",
"edit any {$node_type} content",
"edit own {$node_type} content",
"revert {$node_type} revisions",
"view all revisions",
"view own unpublished content",
"view {$node_type} revisions",
]);
}
private function createApiUser(array $permissions = [], $name = NULL, $admin = FALSE) {
$account = $this
->createUser($permissions, $name, $admin);
$roles = $account
->getRoles(TRUE);
$secret = $this
->randomString(32);
$client = Consumer::create([
'label' => 'API Test Client',
'secret' => $secret,
'confidential' => TRUE,
'user_id' => $account
->id(),
'roles' => reset($roles),
]);
$client
->save();
$url = $this
->buildUrl('/oauth/token');
$response = $this->container
->get('http_client')
->post($url, [
'form_params' => [
'grant_type' => 'password',
'client_id' => $client
->uuid(),
'client_secret' => $secret,
'username' => $account
->getAccountName(),
'password' => $account->passRaw,
],
]);
$body = $this
->decodeResponse($response);
$this
->assertArrayHasKey('access_token', $body);
return $body['access_token'];
}
public function testEntities() {
$access_token = $this
->createApiUser([], NULL, TRUE);
$vocabulary = Vocabulary::create([
'name' => "I'm a vocab",
'vid' => 'im_a_vocab',
'status' => TRUE,
]);
$vocabulary
->save();
$endpoint = '/jsonapi/taxonomy_vocabulary/taxonomy_vocabulary/' . $vocabulary
->uuid();
$response = $this
->request($endpoint, 'get', $access_token);
$body = $this
->decodeResponse($response);
$this
->assertSame($vocabulary
->label(), $body['data']['attributes']['name']);
$vocabulary
->set('name', 'Still a vocab, just a different title');
$vocabulary
->save();
$this->container
->get('router.builder')
->rebuild();
$response = $this
->request($endpoint, 'get', $access_token);
$body = $this
->decodeResponse($response);
$this
->assertSame($vocabulary
->label(), $body['data']['attributes']['name']);
$response = $this
->request('/jsonapi/taxonomy_term/im_a_vocab');
$this
->assertSame(200, $response
->getStatusCode());
$name = 'zebra';
$term_uuid = $this->container
->get('uuid')
->generate();
$endpoint = '/jsonapi/taxonomy_term/im_a_vocab/' . $term_uuid;
$this
->request('/jsonapi/taxonomy_term/im_a_vocab', 'post', $access_token, [
'data' => [
'type' => 'taxonomy_term--im_a_vocab',
'id' => $term_uuid,
'attributes' => [
'name' => $name,
'uuid' => $term_uuid,
],
'relationships' => [
'vid' => [
'data' => [
'type' => 'taxonomy_vocabulary--taxonomy_vocabulary',
'id' => $vocabulary
->uuid(),
],
],
],
],
]);
$response = $this
->request($endpoint, 'get', $access_token);
$body = $this
->decodeResponse($response);
$this
->assertSame($name, $body['data']['attributes']['name']);
$new_name = 'squid';
$this
->request($endpoint, 'patch', $access_token, [
'data' => [
'type' => 'taxonomy_term--im_a_vocab',
'id' => $term_uuid,
'attributes' => [
'name' => $new_name,
],
],
]);
$response = $this
->request($endpoint, 'get', $access_token);
$body = $this
->decodeResponse($response);
$this
->assertSame($new_name, $body['data']['attributes']['name']);
}
public function testAllowed() {
$this
->createContentType([
'type' => 'page',
]);
$published_node = $this
->drupalCreateNode();
$unpublished_node = $published_node
->createDuplicate()
->setUnpublished();
$unpublished_node
->save();
$response = $this
->request('/jsonapi/node/page/' . $published_node
->uuid());
$this
->assertSame(200, $response
->getStatusCode());
$body = $this
->decodeResponse($response);
$this
->assertSame($published_node
->getTitle(), $body['data']['attributes']['title']);
$access_token = $this
->getCreator('page');
$response = $this
->request('/jsonapi/node/page/' . $unpublished_node
->uuid(), 'get', $access_token);
$this
->assertSame(200, $response
->getStatusCode());
$body = $this
->decodeResponse($response);
$this
->assertSame($unpublished_node
->getTitle(), $body['data']['attributes']['title']);
$count = (int) \Drupal::entityQuery('node')
->count()
->execute();
$this
->request('/jsonapi/node/page', 'post', $access_token, [
'data' => [
'type' => 'node--page',
'attributes' => [
'title' => 'With my own two hands',
],
],
]);
$this
->assertSame(++$count, (int) \Drupal::entityQuery('node')
->count()
->execute());
}
public function testForbidden() {
$this
->createContentType([
'type' => 'page',
]);
$response = $this
->request('/jsonapi/user_role/user_role', 'get', $this
->getCreator('page'));
$body = $this
->decodeResponse($response);
$this
->assertSame('array', gettype($body['meta']['omitted']['links']));
$this
->assertNotEmpty($body['meta']['omitted']['links']);
unset($body['meta']['omitted']['links']['help']);
foreach ($body['meta']['omitted']['links'] as $link) {
$this
->assertSame("The current user is not allowed to GET the selected resource. The 'administer permissions' permission is required.", $link['meta']['detail']);
}
$unpublished_node = $this
->drupalCreateNode()
->setUnpublished();
$unpublished_node
->save();
$url = $this
->buildUrl('/jsonapi/node/page/' . $unpublished_node
->uuid());
$this
->expectException(ClientException::class);
$this
->expectExceptionMessage("Client error: `GET {$url}` resulted in a `403 Forbidden`");
$this->container
->get('http_client')
->get($url);
}
private function request($endpoint, $method = 'get', $token = NULL, array $data = NULL) {
$options = NULL;
if ($token) {
$options = [
'headers' => [
'Authorization' => 'Bearer ' . $token,
'Content-Type' => 'application/vnd.api+json',
],
];
}
if ($data) {
$options['json'] = $data;
}
$url = $this
->buildUrl($endpoint);
return $this->container
->get('http_client')
->{$method}($url, $options);
}
private function decodeResponse(ResponseInterface $response) {
$body = (string) $response
->getBody();
$data = Json::decode($body);
if (json_last_error() === JSON_ERROR_NONE) {
return $data;
}
else {
$this
->fail($body);
}
}
}