ProviderRepositoryTest.php

Same filename in this branch
  1. 9 core/modules/media/tests/src/Kernel/ProviderRepositoryTest.php
  2. 9 core/modules/media/tests/src/Functional/ProviderRepositoryTest.php
Same filename and directory in other branches
  1. 8.9.x core/modules/media/tests/src/Functional/ProviderRepositoryTest.php
  2. 10 core/modules/media/tests/src/Unit/ProviderRepositoryTest.php
  3. 10 core/modules/media/tests/src/Functional/ProviderRepositoryTest.php
  4. 11.x core/modules/media/tests/src/Unit/ProviderRepositoryTest.php
  5. 11.x core/modules/media/tests/src/Functional/ProviderRepositoryTest.php

Namespace

Drupal\Tests\media\Unit

File

core/modules/media/tests/src/Unit/ProviderRepositoryTest.php

View source
<?php

namespace Drupal\Tests\media\Unit;

use Drupal\Core\KeyValueStore\KeyValueMemoryFactory;
use Drupal\Core\Logger\LoggerChannelFactory;
use Drupal\Core\Logger\RfcLogLevel;
use Drupal\media\OEmbed\ProviderException;
use Drupal\media\OEmbed\ProviderRepository;
use Drupal\Tests\UnitTestCase;
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use Prophecy\Argument;

/**
 * @coversDefaultClass \Drupal\media\OEmbed\ProviderRepository
 *
 * @group media
 */
class ProviderRepositoryTest extends UnitTestCase {
    
    /**
     * The provider repository under test.
     *
     * @var \Drupal\media\OEmbed\ProviderRepository
     */
    private $repository;
    
    /**
     * The HTTP client handler which will serve responses.
     *
     * @var \GuzzleHttp\Handler\MockHandler
     */
    private $responses;
    
    /**
     * The key-value store.
     *
     * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
     */
    private $keyValue;
    
    /**
     * The time that the current test began.
     *
     * @var int
     */
    private $currentTime;
    
    /**
     * The mocked logger channel.
     *
     * @var \Psr\Log\LoggerInterface|\Prophecy\Prophecy\ObjectProphecy
     */
    private $logger;
    
    /**
     * {@inheritdoc}
     */
    protected function setUp() : void {
        parent::setUp();
        $config_factory = $this->getConfigFactoryStub([
            'media.settings' => [
                'oembed_providers_url' => 'https://oembed.com/providers.json',
            ],
        ]);
        $key_value_factory = new KeyValueMemoryFactory();
        $this->keyValue = $key_value_factory->get('media');
        $this->currentTime = time();
        $time = $this->prophesize('\\Drupal\\Component\\Datetime\\TimeInterface');
        $time->getCurrentTime()
            ->willReturn($this->currentTime);
        $this->logger = $this->prophesize('\\Psr\\Log\\LoggerInterface');
        $logger_factory = new LoggerChannelFactory();
        $logger_factory->addLogger($this->logger
            ->reveal());
        $this->responses = new MockHandler();
        $client = new Client([
            'handler' => HandlerStack::create($this->responses),
        ]);
        $this->repository = new ProviderRepository($client, $config_factory, $time->reveal(), $key_value_factory, $logger_factory);
    }
    
    /**
     * Tests that a successful fetch stores the provider database in key-value.
     */
    public function testSuccessfulFetch() : void {
        $body = <<<END
[
  {
    "provider_name": "YouTube",
    "provider_url": "https:\\/\\/www.youtube.com\\/",
    "endpoints": [
      {
        "schemes": [
          "https:\\/\\/*.youtube.com\\/watch*",
          "https:\\/\\/*.youtube.com\\/v\\/*"
        ],
        "url": "https:\\/\\/www.youtube.com\\/oembed",
        "discovery": true
      }
    ]
  }
]
END;
        $response = new Response(200, [], $body);
        $this->responses
            ->append($response);
        $provider = $this->repository
            ->get('YouTube');
        $stored_data = [
            'data' => [
                'YouTube' => $provider,
            ],
            'expires' => $this->currentTime + 604800,
        ];
        $this->assertSame($stored_data, $this->keyValue
            ->get('oembed_providers'));
    }
    
    /**
     * Tests handling of invalid JSON when fetching the provider database.
     *
     * @param int $expiration_offset
     *   An offset to add to the current time to determine when the primed data,
     *   if any, expires.
     *
     * @dataProvider providerInvalidResponse
     */
    public function testInvalidResponse(int $expiration_offset) : void {
        $provider = $this->prophesize('\\Drupal\\media\\OEmbed\\Provider')
            ->reveal();
        // This stored data should be returned, irrespective of whether it's fresh.
        $this->keyValue
            ->set('oembed_providers', [
            'data' => [
                'YouTube' => $provider,
            ],
            'expires' => $this->currentTime + $expiration_offset,
        ]);
        $response = new Response(200, [], "This certainly isn't valid JSON.");
        $this->responses
            ->append($response, $response);
        $this->assertSame($provider, $this->repository
            ->get('YouTube'));
        // When there is no stored data, we should get an exception.
        $this->keyValue
            ->delete('oembed_providers');
        $this->expectException(ProviderException::class);
        $this->repository
            ->get('YouTube');
    }
    
    /**
     * Data provider for ::testInvalidResponse().
     *
     * @return array[]
     *   Sets of arguments to pass to the test method.
     */
    public function providerInvalidResponse() : array {
        return [
            'expired' => [
                -86400,
            ],
            'fresh' => [
                86400,
            ],
        ];
    }
    
    /**
     * Tests handling of exceptions when fetching the provider database.
     */
    public function testRequestException() : void {
        $provider = $this->prophesize('\\Drupal\\media\\OEmbed\\Provider')
            ->reveal();
        // This data is expired (stale), but it should be returned anyway.
        $this->keyValue
            ->set('oembed_providers', [
            'data' => [
                'YouTube' => $provider,
            ],
            'expires' => $this->currentTime - 86400,
        ]);
        $response = new Response(503);
        $this->responses
            ->append($response, $response);
        $this->assertSame($provider, $this->repository
            ->get('YouTube'));
        // When there is no stored data, we should get an exception.
        $this->keyValue
            ->delete('oembed_providers');
        $this->expectException(ProviderException::class);
        $this->repository
            ->get('YouTube');
    }
    
    /**
     * Tests a successful fetch but with a single corrupt item.
     */
    public function testCorruptProviderIgnored() : void {
        $body = <<<END
[
  {
    "provider_name": "YouTube",
    "provider_url": "https:\\/\\/www.youtube.com\\/",
    "endpoints": [
      {
        "schemes": [
          "https:\\/\\/*.youtube.com\\/watch*",
          "https:\\/\\/*.youtube.com\\/v\\/*"
        ],
        "url": "https:\\/\\/www.youtube.com\\/oembed",
        "discovery": true
      }
    ]
  },
  {
    "provider_name": "Uncle Rico's football videos",
    "provider_url": "not a real url",
    "endpoints": []
  }
]
END;
        $response = new Response(200, [], $body);
        $this->responses
            ->append($response);
        // The corrupt provider should cause a warning to be logged.
        $this->logger
            ->log(RfcLogLevel::WARNING, "Provider Uncle Rico's football videos does not define a valid external URL.", Argument::type('array'))
            ->shouldBeCalled();
        $youtube = $this->repository
            ->get('YouTube');
        // The corrupt provider should not be stored.
        $stored_data = [
            'data' => [
                'YouTube' => $youtube,
            ],
            'expires' => $this->currentTime + 604800,
        ];
        $this->assertSame($stored_data, $this->keyValue
            ->get('oembed_providers'));
        $this->expectException('InvalidArgumentException');
        $this->repository
            ->get("Uncle Rico's football videos");
    }

}

Classes

Title Deprecated Summary
ProviderRepositoryTest @coversDefaultClass \Drupal\media\OEmbed\ProviderRepository

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