MediaResourceTestBase.php

Same filename 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.