class FileUrlGeneratorTest in CDN 8.3
@coversDefaultClass \Drupal\cdn\File\FileUrlGenerator @group cdn
Hierarchy
- class \Drupal\Tests\UnitTestCase extends \PHPUnit\Framework\TestCase uses PhpunitCompatibilityTrait
- class \Drupal\Tests\cdn\Unit\File\FileUrlGeneratorTest
Expanded class hierarchy of FileUrlGeneratorTest
File
- tests/
src/ Unit/ File/ FileUrlGeneratorTest.php, line 24
Namespace
Drupal\Tests\cdn\Unit\FileView source
class FileUrlGeneratorTest extends UnitTestCase {
/**
* The private key to use in tests.
*
* @var string
*/
protected static $privateKey = 'super secret key that really is just some string';
/**
* {@inheritdoc}
*/
protected function setUp() : void {
parent::setUp();
$settings = [
'hash_salt' => $this
->randomMachineName(),
];
new Settings($settings);
}
/**
* @covers ::generate
* @dataProvider urlProvider
*/
public function testGenerate($scheme, $base_path, $uri, $expected_result) {
$gen = $this
->createFileUrlGenerator($base_path, [
'status' => TRUE,
'mapping' => [
'type' => 'complex',
'fallback_domain' => 'cdn.example.com',
'domains' => [
0 => [
'type' => 'simple',
'domain' => 'static.example.com',
'conditions' => [
'extensions' => [
'css',
'js',
],
],
],
1 => [
'type' => 'auto-balanced',
'domains' => [
'img1.example.com',
'img2.example.com',
],
'conditions' => [
'extensions' => [
'jpg',
'jpeg',
'png',
],
],
],
],
],
'scheme' => $scheme,
'farfuture' => [
'status' => FALSE,
],
'stream_wrappers' => [
'public',
],
]);
$this
->assertSame($expected_result, $gen
->generate($uri));
}
public function urlProvider() {
$cases_root = [
'absolute URL' => [
'http://example.com/llama.jpg',
FALSE,
],
'scheme-relative URL' => [
'//example.com/llama.jpg',
FALSE,
],
'shipped file (fallback)' => [
'core/misc/something.else',
'//cdn.example.com/core/misc/something.else',
],
'shipped file (simple)' => [
'core/misc/simple.css',
'//static.example.com/core/misc/simple.css',
],
'shipped file (auto-balanced)' => [
'core/misc/auto-balanced.png',
'//img2.example.com/core/misc/auto-balanced.png',
],
'shipped file with querystring (e.g. in url() in CSS)' => [
'core/misc/something.else?foo=bar&baz=qux',
'//cdn.example.com/core/misc/something.else?foo=bar&baz=qux',
],
'shipped file with fragment (e.g. in url() in CSS)' => [
'core/misc/something.else#llama',
'//cdn.example.com/core/misc/something.else#llama',
],
'shipped file with querystring & fragment (e.g. in url() in CSS)' => [
'core/misc/something.else?foo=bar&baz=qux#llama',
'//cdn.example.com/core/misc/something.else?foo=bar&baz=qux#llama',
],
'managed public file (fallback)' => [
'public://something.else',
'//cdn.example.com/sites/default/files/something.else',
],
'managed public file (spublic public imple)' => [
'public://simple.css',
'//static.example.com/sites/default/files/simple.css',
],
'managed public file (auto-balanced)' => [
'public://auto-balanced.png',
'//img2.example.com/sites/default/files/auto-balanced.png',
],
'managed private file (fallback)' => [
'private://something.else',
FALSE,
],
'unicode' => [
'public://újjáépítésérol — 100% in B&W.jpg',
'//img1.example.com/sites/default/files/%C3%BAjj%C3%A1%C3%A9p%C3%ADt%C3%A9s%C3%A9rol%20%E2%80%94%20100%25%20in%20B%26W.jpg',
],
'encoded' => [
'public://llama%20.jpg',
'//img2.example.com/sites/default/files/llama%2520.jpg',
],
'reserved characters in RFC3986' => [
'public://gendelims :?#[]@ subdelims !$&\'()*+,;=.something',
'//cdn.example.com/sites/default/files/gendelims%20%3A%3F%23%5B%5D%40%20subdelims%20%21%24%26%27%28%29%2A%2B%2C%3B%3D.something',
],
];
$cases_subdir = [
'absolute URL' => [
'http://example.com/llama.jpg',
FALSE,
],
'scheme-relative URL' => [
'//example.com/llama.jpg',
FALSE,
],
'shipped file (fallback)' => [
'core/misc/feed.svg',
'//cdn.example.com/subdir/core/misc/feed.svg',
],
'shipped file (simple)' => [
'core/misc/simple.css',
'//static.example.com/subdir/core/misc/simple.css',
],
'shipped file (auto-balanced)' => [
'core/misc/auto-balanced.png',
'//img2.example.com/subdir/core/misc/auto-balanced.png',
],
'shipped file with querystring (e.g. in url() in CSS)' => [
'core/misc/something.else?foo=bar&baz=qux',
'//cdn.example.com/subdir/core/misc/something.else?foo=bar&baz=qux',
],
'shipped file with fragment (e.g. in url() in CSS)' => [
'core/misc/something.else#llama',
'//cdn.example.com/subdir/core/misc/something.else#llama',
],
'shipped file with querystring & fragment (e.g. in url() in CSS)' => [
'core/misc/something.else?foo=bar&baz=qux#llama',
'//cdn.example.com/subdir/core/misc/something.else?foo=bar&baz=qux#llama',
],
'managed public file (fallback)' => [
'public://something.else',
'//cdn.example.com/subdir/sites/default/files/something.else',
],
'managed public file (simple)' => [
'public://simple.css',
'//static.example.com/subdir/sites/default/files/simple.css',
],
'managed public file (auto-balanced)' => [
'public://auto-balanced.png',
'//img2.example.com/subdir/sites/default/files/auto-balanced.png',
],
'managed private file (fallback)' => [
'private://something.else',
FALSE,
],
'unicode' => [
'public://újjáépítésérol — 100% in B&W.jpg',
'//img1.example.com/subdir/sites/default/files/%C3%BAjj%C3%A1%C3%A9p%C3%ADt%C3%A9s%C3%A9rol%20%E2%80%94%20100%25%20in%20B%26W.jpg',
],
'encoded' => [
'public://llama%20.jpg',
'//img2.example.com/subdir/sites/default/files/llama%2520.jpg',
],
'reserved characters in RFC3986' => [
'public://gendelims :?#[]@ subdelims !$&\'()*+,;=.something',
'//cdn.example.com/subdir/sites/default/files/gendelims%20%3A%3F%23%5B%5D%40%20subdelims%20%21%24%26%27%28%29%2A%2B%2C%3B%3D.something',
],
];
$cases = [];
assert(count($cases_root) === count($cases_subdir));
foreach ($cases_root as $description => $case) {
$cases['root, ' . $description] = array_merge([
'',
], $case);
}
foreach ($cases_subdir as $description => $case) {
$cases['subdir, ' . $description] = array_merge([
'/subdir',
], $case);
}
// Generate `https://`, `http://` and `//` permutations for each case.
$cases_with_scheme = [];
foreach ($cases as $description => $case) {
foreach ([
'https://',
'http://',
'//',
] as $scheme) {
list($base_path, $uri, $expected_result) = $case;
$cases_with_scheme['scheme=' . $scheme . ', ' . $description] = [
$scheme,
$base_path,
$uri,
!is_string($expected_result) ? $expected_result : $scheme . substr($expected_result, 2),
];
}
}
return $cases_with_scheme;
}
/**
* @covers ::generate
*/
public function testGenerateFarfuture() {
$config = [
'status' => TRUE,
'mapping' => [
'type' => 'simple',
'domain' => 'cdn.example.com',
'conditions' => [],
],
'scheme' => '//',
'farfuture' => [
'status' => TRUE,
],
// File is used here generically to test a stream wrapper that is not
// shipped with Drupal, but is natively supported by PHP.
// @see \Drupal\cdn\File\FileUrlGenerator::generate(), which uses
// file_exists() and would require actually configuring the stream
// wrapper in the context of the unit test.
'stream_wrappers' => [
'public',
'file',
],
];
// Generate file for testing managed file.
$llama_jpg_filename = 'llama%20 (' . $this
->randomMachineName() . ').jpg';
$llama_jpg_filepath = $this->root . '/sites/default/files/' . $llama_jpg_filename;
file_put_contents($llama_jpg_filepath, $this
->randomMachineName());
$llama_jpg_mtime = filemtime($llama_jpg_filepath);
$this
->assertTrue(file_exists($llama_jpg_filepath));
// In root: 1) non-existing file, 2) shipped file, 3) managed file.
$gen = $this
->createFileUrlGenerator('', $config);
$this
->assertSame('//cdn.example.com/core/misc/does-not-exist.js', $gen
->generate('core/misc/does-not-exist.js'));
$drupal_js_mtime = filemtime($this->root . '/core/misc/drupal.js');
$drupal_js_security_token = Crypt::hmacBase64($drupal_js_mtime . ':relative:' . UrlHelper::encodePath('/core/misc/drupal.js'), static::$privateKey . Settings::getHashSalt());
$this
->assertSame('//cdn.example.com/cdn/ff/' . $drupal_js_security_token . '/' . $drupal_js_mtime . '/:relative:/core/misc/drupal.js', $gen
->generate('core/misc/drupal.js'));
// Since the public stream wrapper is not available in the unit test,
// and we use file_exists() in the target method, we are using the
// file:// scheme that ships with PHP. This does require
// injecting a leading into the path that we compare against, to match
// the method.
$llama_jpg_security_token = Crypt::hmacBase64($llama_jpg_mtime . 'file' . UrlHelper::encodePath('/' . $llama_jpg_filepath), static::$privateKey . Settings::getHashSalt());
$this
->assertSame('//cdn.example.com/cdn/ff/' . $llama_jpg_security_token . '/' . $llama_jpg_mtime . '/file/' . UrlHelper::encodePath($llama_jpg_filepath), $gen
->generate('file://' . $llama_jpg_filepath));
// In subdir: 1) non-existing file, 2) shipped file, 3) managed file.
$gen = $this
->createFileUrlGenerator('/subdir', $config);
$this
->assertSame('//cdn.example.com/subdir/core/misc/does-not-exist.js', $gen
->generate('core/misc/does-not-exist.js'));
$this
->assertSame('//cdn.example.com/subdir/cdn/ff/' . $drupal_js_security_token . '/' . $drupal_js_mtime . '/:relative:/core/misc/drupal.js', $gen
->generate('core/misc/drupal.js'));
$this
->assertSame('//cdn.example.com/subdir/cdn/ff/' . $llama_jpg_security_token . '/' . $llama_jpg_mtime . '/file/' . UrlHelper::encodePath($llama_jpg_filepath), $gen
->generate('file://' . $llama_jpg_filepath));
unlink($llama_jpg_filepath);
}
/**
* Creates a FileUrlGenerator with mostly dummies.
*
* @param string $base_path
* The base path to let Request::getBasePath() return.
* @param array $raw_config
* The raw config for the cdn.settings.yml config.
*
* @return \Drupal\cdn\File\FileUrlGenerator
* The FileUrlGenerator to test.
*/
protected function createFileUrlGenerator($base_path, array $raw_config) {
$request = $this
->prophesize(Request::class);
$request
->getBasePath()
->willReturn($base_path);
$request
->getSchemeAndHttpHost()
->willReturn('http://example.com');
$request_stack = $this
->prophesize(RequestStack::class);
$request_stack
->getCurrentRequest()
->willReturn($request
->reveal());
// @todo make this more elegant: the current URI is normally stored on the
// PublicStream instance, but while it is prophesized, that does not seem
// possible.
$current_uri = '';
$public_stream_wrapper = $this
->prophesize(PublicStream::class);
$public_stream_wrapper
->getExternalUrl()
->will(function () use ($base_path, &$current_uri) {
return 'http://example.com' . $base_path . '/sites/default/files/' . UrlHelper::encodePath(substr($current_uri, 9));
});
$file_stream_wrapper = $this
->prophesize(LocalStream::class);
$root = $this->root;
$file_stream_wrapper
->getExternalUrl()
->will(function () use ($root, $base_path, &$current_uri) {
// The file:// stream wrapper is only used for testing FF.
return 'http://example.com/inaccessible';
});
$stream_wrapper_manager = $this
->prophesize(StreamWrapperManagerInterface::class);
$stream_wrapper_manager
->getWrappers(StreamWrapperInterface::LOCAL_NORMAL)
->willReturn([
'public' => TRUE,
]);
$stream_wrapper_manager
->getViaUri(Argument::that(function ($uri) {
return substr($uri, 0, 9) === 'public://';
}))
->will(function ($args) use (&$public_stream_wrapper, &$current_uri) {
$s = $public_stream_wrapper
->reveal();
$current_uri = $args[0];
return $s;
});
$stream_wrapper_manager
->getViaUri(Argument::that(function ($uri) {
return substr($uri, 0, 7) === 'file://';
}))
->will(function ($args) use (&$file_stream_wrapper, &$current_uri) {
$s = $file_stream_wrapper
->reveal();
$current_uri = $args[0];
return $s;
});
$private_key = $this
->prophesize(PrivateKey::class);
$private_key
->get()
->willReturn(static::$privateKey);
return new FileUrlGenerator($this->root, $stream_wrapper_manager
->reveal(), $request_stack
->reveal(), $private_key
->reveal(), new CdnSettings($this
->getConfigFactoryStub([
'cdn.settings' => $raw_config,
]), $stream_wrapper_manager
->reveal()));
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
FileUrlGeneratorTest:: |
protected static | property | The private key to use in tests. | |
FileUrlGeneratorTest:: |
protected | function | Creates a FileUrlGenerator with mostly dummies. | |
FileUrlGeneratorTest:: |
protected | function |
Overrides UnitTestCase:: |
|
FileUrlGeneratorTest:: |
public | function | @covers ::generate @dataProvider urlProvider | |
FileUrlGeneratorTest:: |
public | function | @covers ::generate | |
FileUrlGeneratorTest:: |
public | function | ||
PhpunitCompatibilityTrait:: |
public | function | Returns a mock object for the specified class using the available method. | |
PhpunitCompatibilityTrait:: |
public | function | Compatibility layer for PHPUnit 6 to support PHPUnit 4 code. | |
UnitTestCase:: |
protected | property | The random generator. | |
UnitTestCase:: |
protected | property | The app root. | 1 |
UnitTestCase:: |
protected | function | Asserts if two arrays are equal by sorting them first. | |
UnitTestCase:: |
protected | function | Mocks a block with a block plugin. | 1 |
UnitTestCase:: |
protected | function | Returns a stub class resolver. | |
UnitTestCase:: |
public | function | Returns a stub config factory that behaves according to the passed array. | |
UnitTestCase:: |
public | function | Returns a stub config storage that returns the supplied configuration. | |
UnitTestCase:: |
protected | function | Sets up a container with a cache tags invalidator. | |
UnitTestCase:: |
protected | function | Gets the random generator for the utility methods. | |
UnitTestCase:: |
public | function | Returns a stub translation manager that just returns the passed string. | |
UnitTestCase:: |
public | function | Generates a unique random string containing letters and numbers. |