MediaResourceTestBase.php

Same filename and directory in other branches
  1. 9 core/modules/media/tests/src/Functional/Rest/MediaResourceTestBase.php
  2. 8.9.x core/modules/media/tests/src/Functional/Rest/MediaResourceTestBase.php
  3. 8.9.x core/modules/rest/tests/src/Functional/EntityResource/Media/MediaResourceTestBase.php
  4. 11.x core/modules/media/tests/src/Functional/Rest/MediaResourceTestBase.php

Namespace

Drupal\Tests\media\Functional\Rest

File

core/modules/media/tests/src/Functional/Rest/MediaResourceTestBase.php

View source
<?php

declare (strict_types=1);
namespace Drupal\Tests\media\Functional\Rest;

use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Url;
use Drupal\file\Entity\File;
use Drupal\media\Entity\Media;
use Drupal\media\Entity\MediaType;
use Drupal\rest\RestResourceConfigInterface;
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
use Drupal\user\RoleInterface;
use GuzzleHttp\RequestOptions;
abstract class MediaResourceTestBase extends EntityResourceTestBase {
  
  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'content_translation',
    'media',
  ];
  
  /**
   * {@inheritdoc}
   */
  protected static $entityTypeId = 'media';
  
  /**
   * @var \Drupal\media\MediaInterface
   */
  protected $entity;
  
  /**
   * {@inheritdoc}
   */
  protected static $patchProtectedFieldNames = [
    'changed' => NULL,
  ];
  
  /**
   * {@inheritdoc}
   */
  protected function setUp() : void {
    parent::setUp();
    \Drupal::configFactory()->getEditable('media.settings')
      ->set('standalone_url', TRUE)
      ->save(TRUE);
    // Provisioning the Media REST resource without the File REST resource does
    // not make sense.
    $this->resourceConfigStorage
      ->create([
      'id' => 'entity.file',
      'granularity' => RestResourceConfigInterface::RESOURCE_GRANULARITY,
      'configuration' => [
        'methods' => [
          'GET',
        ],
        'formats' => [
          static::$format,
        ],
        'authentication' => isset(static::$auth) ? [
          static::$auth,
        ] : [],
      ],
      'status' => TRUE,
    ])
      ->save();
    $this->container
      ->get('router.builder')
      ->rebuild();
  }
  
  /**
   * {@inheritdoc}
   */
  protected function setUpAuthorization($method) {
    switch ($method) {
      case 'GET':
        $this->grantPermissionsToTestedRole([
          'view media',
        ]);
        break;

      case 'POST':
        $this->grantPermissionsToTestedRole([
          'create camelids media',
          'access content',
        ]);
        break;

      case 'PATCH':
        $this->grantPermissionsToTestedRole([
          'edit any camelids media',
        ]);
        // @todo Remove this in https://www.drupal.org/node/2824851.
        $this->grantPermissionsToTestedRole([
          'access content',
        ]);
        break;

      case 'DELETE':
        $this->grantPermissionsToTestedRole([
          'delete any camelids media',
        ]);
        break;

    }
  }
  
  /**
   * {@inheritdoc}
   */
  protected function createEntity() {
    if (!MediaType::load('camelids')) {
      // Create a "Camelids" media type.
      $media_type = MediaType::create([
        'label' => 'Camelids',
        'id' => 'camelids',
        'description' => 'Camelids are large, strictly herbivorous animals with slender necks and long legs.',
        'source' => 'file',
      ]);
      $media_type->save();
      // Create the source field.
      $source_field = $media_type->getSource()
        ->createSourceField($media_type);
      $source_field->getFieldStorageDefinition()
        ->save();
      $source_field->save();
      $media_type->set('source_configuration', [
        'source_field' => $source_field->getName(),
      ])
        ->save();
    }
    // Create a file to upload.
    $file = File::create([
      'uri' => 'public://llama.txt',
    ]);
    $file->setPermanent();
    $file->save();
    // Create a "Llama" media item.
    $media = Media::create([
      'bundle' => 'camelids',
      'field_media_file' => [
        'target_id' => $file->id(),
      ],
    ]);
    $media->setName('Llama')
      ->setPublished()
      ->setCreatedTime(123456789)
      ->setOwnerId(static::$auth ? $this->account
      ->id() : 0)
      ->setRevisionUserId(static::$auth ? $this->account
      ->id() : 0)
      ->save();
    return $media;
  }
  
  /**
   * {@inheritdoc}
   */
  protected function getExpectedNormalizedEntity() {
    $file = File::load(1);
    $thumbnail = File::load(2);
    $author = User::load($this->entity
      ->getOwnerId());
    return [
      'mid' => [
        [
          'value' => 1,
        ],
      ],
      'uuid' => [
        [
          'value' => $this->entity
            ->uuid(),
        ],
      ],
      'vid' => [
        [
          'value' => 1,
        ],
      ],
      'langcode' => [
        [
          'value' => 'en',
        ],
      ],
      'bundle' => [
        [
          'target_id' => 'camelids',
          'target_type' => 'media_type',
          'target_uuid' => MediaType::load('camelids')->uuid(),
        ],
      ],
      'name' => [
        [
          'value' => 'Llama',
        ],
      ],
      'field_media_file' => [
        [
          'description' => NULL,
          'display' => NULL,
          'target_id' => (int) $file->id(),
          'target_type' => 'file',
          'target_uuid' => $file->uuid(),
          'url' => $file->createFileUrl(FALSE),
        ],
      ],
      'thumbnail' => [
        [
          'alt' => '',
          'width' => 180,
          'height' => 180,
          'target_id' => (int) $thumbnail->id(),
          'target_type' => 'file',
          'target_uuid' => $thumbnail->uuid(),
          'title' => NULL,
          'url' => $thumbnail->createFileUrl(FALSE),
        ],
      ],
      'status' => [
        [
          'value' => TRUE,
        ],
      ],
      'created' => [
        [
          'value' => (new \DateTime())->setTimestamp(123456789)
            ->setTimezone(new \DateTimeZone('UTC'))
            ->format(\DateTime::RFC3339),
          'format' => \DateTime::RFC3339,
        ],
      ],
      'changed' => [
        [
          'value' => (new \DateTime())->setTimestamp((int) $this->entity
            ->getChangedTime())
            ->setTimezone(new \DateTimeZone('UTC'))
            ->format(\DateTime::RFC3339),
          'format' => \DateTime::RFC3339,
        ],
      ],
      'revision_created' => [
        [
          'value' => (new \DateTime())->setTimestamp((int) $this->entity
            ->getRevisionCreationTime())
            ->setTimezone(new \DateTimeZone('UTC'))
            ->format(\DateTime::RFC3339),
          'format' => \DateTime::RFC3339,
        ],
      ],
      'default_langcode' => [
        [
          'value' => TRUE,
        ],
      ],
      'uid' => [
        [
          'target_id' => (int) $author->id(),
          'target_type' => 'user',
          'target_uuid' => $author->uuid(),
          'url' => base_path() . 'user/' . $author->id(),
        ],
      ],
      'revision_user' => [
        [
          'target_id' => (int) $author->id(),
          'target_type' => 'user',
          'target_uuid' => $author->uuid(),
          'url' => base_path() . 'user/' . $author->id(),
        ],
      ],
      'revision_translation_affected' => [
        [
          'value' => TRUE,
        ],
      ],
    ];
  }
  
  /**
   * {@inheritdoc}
   */
  protected function getNormalizedPostEntity() {
    return [
      'bundle' => [
        [
          'target_id' => 'camelids',
        ],
      ],
      'name' => [
        [
          'value' => 'Drama llama',
        ],
      ],
      'field_media_file' => [
        [
          'description' => NULL,
          'display' => NULL,
          'target_id' => 3,
        ],
      ],
    ];
  }
  
  /**
   * {@inheritdoc}
   */
  protected function getNormalizedPatchEntity() {
    return array_diff_key($this->getNormalizedPostEntity(), [
      'field_media_file' => TRUE,
    ]);
  }
  
  /**
   * {@inheritdoc}
   */
  protected function getExpectedUnauthorizedAccessMessage($method) {
    switch ($method) {
      case 'GET':
        return "The 'view media' permission is required when the media item is published.";
      case 'POST':
        return "The following permissions are required: 'administer media' OR 'create media' OR 'create camelids media'.";
      case 'PATCH':
        return "The following permissions are required: 'update any media' OR 'update own media' OR 'camelids: edit any media' OR 'camelids: edit own media'.";
      case 'DELETE':
        return "The following permissions are required: 'delete any media' OR 'delete own media' OR 'camelids: delete any media' OR 'camelids: delete own media'.";
      default:
        return parent::getExpectedUnauthorizedAccessMessage($method);
    }
  }
  
  /**
   * {@inheritdoc}
   */
  protected function getExpectedCacheContexts() {
    return [
      'languages:language_interface',
      'url.site',
      'user.permissions',
    ];
  }
  
  /**
   * {@inheritdoc}
   */
  public function testPost() : void {
    $file_storage = $this->container
      ->get('entity_type.manager')
      ->getStorage('file');
    // Step 1: upload file, results in File entity marked temporary.
    $this->uploadFile();
    $file = $file_storage->loadUnchanged(3);
    $this->assertTrue($file->isTemporary());
    $this->assertFalse($file->isPermanent());
    // Step 2: create Media entity using the File, makes File entity permanent.
    parent::testPost();
    $file = $file_storage->loadUnchanged(3);
    $this->assertFalse($file->isTemporary());
    $this->assertTrue($file->isPermanent());
  }
  
  /**
   * Tests the 'file_upload' REST resource plugin.
   *
   * This test duplicates some of the 'file_upload' REST resource plugin test
   * coverage.
   *
   * @see \Drupal\Tests\rest\Functional\FileUploadResourceTestBase
   */
  protected function uploadFile() {
    // Enable the 'file_upload' REST resource for the current format + auth.
    $this->resourceConfigStorage
      ->create([
      'id' => 'file.upload',
      'granularity' => RestResourceConfigInterface::RESOURCE_GRANULARITY,
      'configuration' => [
        'methods' => [
          'POST',
        ],
        'formats' => [
          static::$format,
        ],
        'authentication' => isset(static::$auth) ? [
          static::$auth,
        ] : [],
      ],
      'status' => TRUE,
    ])
      ->save();
    $this->refreshTestStateAfterRestConfigChange();
    $this->initAuthentication();
    // POST to create a File entity.
    $url = Url::fromUri('base:file/upload/media/camelids/field_media_file');
    $url->setOption('query', [
      '_format' => static::$format,
    ]);
    $request_options = [];
    $request_options[RequestOptions::HEADERS] = [
      // Set the required (and only accepted) content type for the request.
'Content-Type' => 'application/octet-stream',
      // Set the required Content-Disposition header for the file name.
'Content-Disposition' => 'file; filename="drupal rocks 🤘.txt"',
    ];
    $request_options[RequestOptions::BODY] = 'Drupal is the best!';
    $request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions('POST'));
    $response = $this->request('POST', $url, $request_options);
    $this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('POST'), $response);
    // Grant necessary permission, retry.
    $this->grantPermissionsToTestedRole([
      'create camelids media',
    ]);
    $response = $this->request('POST', $url, $request_options);
    $this->assertSame(201, $response->getStatusCode());
    $expected = $this->getExpectedNormalizedFileEntity();
    static::recursiveKSort($expected);
    $actual = $this->serializer
      ->decode((string) $response->getBody(), static::$format);
    static::recursiveKSort($actual);
    $this->assertSame($expected, $actual);
    // Make sure the role save below properly invalidates cache tags.
    $this->refreshVariables();
    // To still run the complete test coverage for POSTing a Media entity, we
    // must revoke the additional permissions that we granted.
    $role = Role::load(static::$auth ? RoleInterface::AUTHENTICATED_ID : RoleInterface::ANONYMOUS_ID);
    $role->revokePermission('create camelids media');
    $role->trustData()
      ->save();
  }
  
  /**
   * Gets the expected file entity.
   *
   * @return array
   *   The expected normalized data array.
   */
  protected function getExpectedNormalizedFileEntity() {
    $file = File::load(3);
    $owner = static::$auth ? $this->account : User::load(0);
    return [
      'fid' => [
        [
          'value' => 3,
        ],
      ],
      'uuid' => [
        [
          'value' => $file->uuid(),
        ],
      ],
      'langcode' => [
        [
          'value' => 'en',
        ],
      ],
      'uid' => [
        [
          'target_id' => (int) $owner->id(),
          'target_type' => 'user',
          'target_uuid' => $owner->uuid(),
          'url' => base_path() . 'user/' . $owner->id(),
        ],
      ],
      'filename' => [
        [
          'value' => 'drupal rocks 🤘.txt',
        ],
      ],
      'uri' => [
        [
          'value' => 'public://' . date('Y-m') . '/drupal rocks 🤘.txt',
          'url' => base_path() . $this->siteDirectory . '/files/' . date('Y-m') . '/drupal%20rocks%20%F0%9F%A4%98.txt',
        ],
      ],
      'filemime' => [
        [
          'value' => 'text/plain',
        ],
      ],
      'filesize' => [
        [
          'value' => 19,
        ],
      ],
      'status' => [
        [
          'value' => FALSE,
        ],
      ],
      'created' => [
        [
          'value' => (new \DateTime())->setTimestamp($file->getCreatedTime())
            ->setTimezone(new \DateTimeZone('UTC'))
            ->format(\DateTime::RFC3339),
          'format' => \DateTime::RFC3339,
        ],
      ],
      'changed' => [
        [
          'value' => (new \DateTime())->setTimestamp($file->getChangedTime())
            ->setTimezone(new \DateTimeZone('UTC'))
            ->format(\DateTime::RFC3339),
          'format' => \DateTime::RFC3339,
        ],
      ],
    ];
  }
  
  /**
   * {@inheritdoc}
   */
  protected function getExpectedUnauthorizedEntityAccessCacheability($is_authenticated) {
    // @see \Drupal\media\MediaAccessControlHandler::checkAccess()
    return parent::getExpectedUnauthorizedEntityAccessCacheability($is_authenticated)->addCacheTags([
      'media:1',
    ]);
  }

}

Classes

Title Deprecated Summary
MediaResourceTestBase

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.