clean install

This commit is contained in:
2024-12-10 15:08:16 +01:00
commit e14eb2d8fd
31193 changed files with 3555714 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
<?php
namespace Drupal\subrequests_test\Controller;
use Drupal\Core\Cache\CacheableJsonResponse;
use Drupal\Core\Controller\ControllerBase;
/**
* A controller returning simple responses for testing.
*/
class TestController extends ControllerBase {
/**
* Returns a JSON response that says "Alfa".
*
* @return \Drupal\Core\Cache\CacheableJsonResponse
* The response object.
*/
public function alpha(): CacheableJsonResponse {
return new CacheableJsonResponse('Alfa');
}
/**
* Returns a JSON response that says "Brava!".
*
* @return \Drupal\Core\Cache\CacheableJsonResponse
* The response object.
*/
public function bravo(): CacheableJsonResponse {
return new CacheableJsonResponse('Brava!');
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Drupal\subrequests_test;
use Drupal\Core\PageCache\RequestPolicyInterface;
use Drupal\Core\State\StateInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* A request policy that returns a specific pre-set value.
*/
class TestPolicy implements RequestPolicyInterface {
/**
* The state service.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* Constructs a TestPolicy object.
*
* @param \Drupal\Core\State\StateInterface $state
* State service.
*/
public function __construct(StateInterface $state) {
$this->state = $state;
}
/**
* Sets the value this policy will return.
*
* @param string|null $value
* The value this policy will return. Should be one of the ALLOW or DENY
* constants of \Drupal\Core\PageCache\RequestPolicyInterface, or NULL
* to have no opinion.
*/
public static function setValue(?string $value): void {
\Drupal::state()->set('subrequests_test_request_policy', $value);
}
/**
* {@inheritdoc}
*/
public function check(Request $request) {
return $this->state->get('subrequests_test_request_policy');
}
}

View File

@@ -0,0 +1,11 @@
name: 'Subrequests Test'
type: module
package: Testing
description: Provides routes for functional tests of Subrequests.
dependencies:
- subrequests:subrequests
# Information added by Drupal.org packaging script on 2024-08-06
version: '3.0.12'
project: 'subrequests'
datestamp: 1722952641

View File

@@ -0,0 +1,15 @@
subrequests_test.alpha:
path: '/subrequests-test/alpha'
defaults:
_controller: '\Drupal\subrequests_test\Controller\TestController::alpha'
requirements:
# Allowed for testing.
_access: 'TRUE'
subrequests_test.bravo:
path: '/subrequests-test/bravo'
defaults:
_controller: '\Drupal\subrequests_test\Controller\TestController::bravo'
requirements:
# Allowed for testing.
_access: 'TRUE'

View File

@@ -0,0 +1,6 @@
services:
subrequests_test.request_policy:
class: Drupal\subrequests_test\TestPolicy
arguments: ['@state']
tags:
- { name: page_cache_request_policy }

View File

@@ -0,0 +1,18 @@
<!--?xml version="1.0" encoding="UTF-8"?-->
<phpunit colors="true">
<testsuites>
<testsuite name="subrequests">
<directory>./src/</directory>
</testsuite>
</testsuites>
<!-- Filter for coverage reports. -->
<filter>
<blacklist>
<directory>./vendor</directory>
</blacklist>
<whitelist>
<directory>../src</directory>
</whitelist>
</filter>
</phpunit>

View File

@@ -0,0 +1,110 @@
<?php
namespace Drupal\Tests\subrequests\Functional;
use Drupal\Core\Url;
use Drupal\subrequests_test\TestPolicy;
use Drupal\Tests\BrowserTestBase;
/**
* Tests subrequests with Page Cache enabled.
*
* @group subrequests
*/
class PageCacheTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'page_cache',
'subrequests_test',
'system',
];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* Tests that subrequests work properly with Page Cache enabled.
*/
public function testPageCache(): void {
// Ensure page caching is always allowed in this test.
TestPolicy::setValue(TestPolicy::ALLOW);
$account = $this->drupalCreateUser(['issue subrequests']);
$this->drupalLogin($account);
// Warm the cache for the first sub-request.
$this->drupalGet('/subrequests-test/alpha');
$assert_session = $this->assertSession();
$assert_session->statusCodeEquals(200);
$assert_session->responseContains('Alfa');
// Ensure it was not (somehow) already cached.
$assert_session->responseHeaderEquals('X-Drupal-Cache', 'MISS');
$blueprint = [
[
'requestId' => 'alpha',
'uri' => Url::fromUserInput('/subrequests-test/alpha')->toString(),
'action' => 'view',
],
[
'requestId' => 'bravo',
'uri' => Url::fromUserInput('/subrequests-test/bravo')->toString(),
'action' => 'view',
],
];
$options = [
'query' => [
'query' => json_encode($blueprint, JSON_UNESCAPED_SLASHES),
],
];
$headers = [
'Content-Type' => 'application/json',
];
$this->drupalGet('/subrequests', $options, $headers);
$assert_session->statusCodeEquals(207);
// The request as a whole should be a cache miss.
$assert_session->responseHeaderEquals('X-Drupal-Cache', 'MISS');
// There should be two sub-responses.
$responses = $this->getResponses();
$this->assertCount(2, $responses);
// The first response should say Alfa and be a cache hit.
$this->assertStringContainsString('Alfa', $responses[0]);
$this->assertMatchesRegularExpression('/X-Drupal-Cache:\s+HIT/', $responses[0]);
// The second response should say Brava and be a cache miss.
$this->assertStringContainsString('Brava!', $responses[1]);
$this->assertMatchesRegularExpression('/X-Drupal-Cache:\s+MISS/', $responses[1]);
}
/**
* Returns the individual sub-responses from the most recent master request.
*
* @return string[]
* The responses from the most recent master request, in which the headers
* and body are separated by a single empty line.
*/
private function getResponses(): array {
$session = $this->getSession();
$matches = [];
preg_match('/boundary="([a-zA-Z0-9]+)"/', $session->getResponseHeader('Content-Type'), $matches);
$this->assertArrayHasKey(1, $matches);
$boundary = '--' . $matches[1];
$responses = explode($boundary, $session->getPage()->getContent());
// The first land last sub-responses are just empty strings because the
// response as a whole begins and ends with the boundary string.
$responses = array_slice($responses, 1, -1);
$responses = array_map('trim', $responses);
// Re-key the array before returning it.
return array_values($responses);
}
}

View File

@@ -0,0 +1,76 @@
<?php
namespace Drupal\Tests\subrequests\Unit\Blueprint;
use Drupal\Core\Cache\CacheableResponse;
use Drupal\subrequests\Blueprint\BlueprintManager;
use Drupal\subrequests\Normalizer\JsonBlueprintDenormalizer;
use Drupal\subrequests\Normalizer\JsonSubrequestDenormalizer;
use Drupal\subrequests\Normalizer\MultiresponseJsonNormalizer;
use Drupal\subrequests\Normalizer\MultiresponseNormalizer;
use Drupal\subrequests\SubrequestsTree;
use Drupal\Tests\UnitTestCase;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\Encoder\JsonDecode;
use Symfony\Component\Serializer\Serializer;
/**
* @coversDefaultClass \Drupal\subrequests\Blueprint\BlueprintManager
* @group subrequests
*/
class BlueprintManagerTest extends UnitTestCase {
/**
* Blueprint manager.
*
* @var \Drupal\subrequests\Blueprint\BlueprintManager
*/
protected $sut;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$serializer = new Serializer(
[
new JsonBlueprintDenormalizer($this->createMock(LoggerInterface::class)),
new JsonSubrequestDenormalizer(),
new MultiresponseJsonNormalizer(),
new MultiresponseNormalizer(),
],
[new JsonDecode()]
);
$this->sut = new BlueprintManager($serializer);
}
/**
* Test for parse method.
*
* @covers ::parse
*/
public function testParse() {
$parsed = $this->sut->parse('[]', Request::create('foo'));
$this->assertInstanceOf(SubrequestsTree::class, $parsed);
$this->assertSame('/foo', $parsed->getMasterRequest()->getPathInfo());
}
/**
* Test for combineResponses method.
*
* @covers ::combineResponses
*/
public function testCombineResponses() {
$responses = [
new Response('foo', 200, ['lorem' => 'ipsum', 'Content-Type' => 'sparrow', 'head' => 'Ha!']),
new Response('Booh!', 201, ['dolor' => 'sid', 'Content-Type' => 'sparrow']),
];
$combined = $this->sut->combineResponses($responses, 'multipart-related');
$this->assertInstanceOf(CacheableResponse::class, $combined);
$this->assertStringContainsString('type=sparrow', $combined->headers->get('Content-Type'));
$this->assertStringContainsString('Booh!', $combined->getContent());
}
}

View File

@@ -0,0 +1,161 @@
<?php
namespace Drupal\Tests\subrequests\Unit;
use Drupal\subrequests\JsonPathReplacer;
use Drupal\subrequests\Subrequest;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Response;
/**
* @coversDefaultClass \Drupal\subrequests\JsonPathReplacer
* @group subrequests
*/
class JsonPathReplacerTest extends UnitTestCase {
/**
* Json path replacer service.
*
* @var \Drupal\subrequests\JsonPathReplacer
*/
protected $sut;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->sut = new JsonPathReplacer();
}
/**
* Test for replaceBatch method.
*
* @covers ::replaceBatch
*/
public function testReplaceBatch() {
$batch = $responses = [];
$batch[] = new Subrequest([
'uri' => '/ipsum/{{foo.body@$.things[*]}}/{{bar.body@$.things[*]}}/{{foo.body@$.stuff}}',
'action' => 'sing',
'requestId' => 'oop',
'headers' => [],
'_resolved' => FALSE,
'body' => ['answer' => '{{foo.body@$.stuff}}'],
'waitFor' => ['foo'],
]);
$batch[] = new Subrequest([
'uri' => '/dolor/{{foo.body@$.stuff}}',
'action' => 'create',
'requestId' => 'oof',
'headers' => [],
'_resolved' => FALSE,
'body' => 'bar',
'waitFor' => ['foo'],
]);
$response = new Response('{"things":["what","keep","talking"],"stuff":42}');
$response->headers->set('Content-ID', '<foo>');
$responses[] = $response;
$response = new Response('{"things":["the","plane","is"],"stuff":"delayed"}');
$response->headers->set('Content-ID', '<bar>');
$responses[] = $response;
$actual = $this->sut->replaceBatch($batch, $responses);
$this->assertCount(10, $actual);
$paths = array_map(function (Subrequest $subrequest) {
return [$subrequest->uri, $subrequest->body];
}, $actual);
$expected_paths = [
['/ipsum/what/the/42', ['answer' => '42']],
['/ipsum/what/plane/42', ['answer' => '42']],
['/ipsum/what/is/42', ['answer' => '42']],
['/ipsum/keep/the/42', ['answer' => '42']],
['/ipsum/keep/plane/42', ['answer' => '42']],
['/ipsum/keep/is/42', ['answer' => '42']],
['/ipsum/talking/the/42', ['answer' => '42']],
['/ipsum/talking/plane/42', ['answer' => '42']],
['/ipsum/talking/is/42', ['answer' => '42']],
['/dolor/42', 'bar'],
];
$this->assertEquals($expected_paths, $paths);
$this->assertEquals(['answer' => 42], $actual[0]->body);
}
/**
* Test for replaceBatchSplit method.
*
* @covers ::replaceBatch
*/
public function testReplaceBatchSplit() {
$batch = $responses = [];
$batch[] = new Subrequest([
'uri' => 'test://{{foo.body@$.things[*].id}}/{{foo.body@$.things[*].id}}',
'action' => 'sing',
'requestId' => 'oop',
'headers' => [],
'_resolved' => FALSE,
'body' => ['answer' => '{{foo.body@$.stuff}}'],
'waitFor' => ['foo'],
]);
$response = new Response('{"things":[{"id":"what"},{"id":"keep"},{"id":"talking"}],"stuff":42}');
$response->headers->set('Content-ID', '<foo#0>');
$responses[] = $response;
$response = new Response('{"things":[{"id":"the"},{"id":"plane"}],"stuff":"delayed"}');
$response->headers->set('Content-ID', '<foo#1>');
$responses[] = $response;
$actual = $this->sut->replaceBatch($batch, $responses);
$this->assertCount(10, $actual);
$paths = array_map(function (Subrequest $subrequest) {
return [$subrequest->uri, $subrequest->body];
}, $actual);
$expected_paths = [
['test://what/what', ['answer' => '42']],
['test://what/what', ['answer' => 'delayed']],
['test://keep/keep', ['answer' => '42']],
['test://keep/keep', ['answer' => 'delayed']],
['test://talking/talking', ['answer' => '42']],
['test://talking/talking', ['answer' => 'delayed']],
['test://the/the', ['answer' => '42']],
['test://the/the', ['answer' => 'delayed']],
['test://plane/plane', ['answer' => '42']],
['test://plane/plane', ['answer' => 'delayed']],
];
$this->assertEquals($expected_paths, $paths);
}
/**
* Test for replaceBatchTypes method.
*
* @covers ::replaceBatch
*/
public function testReplaceBatchTypes() {
$batch = $responses = [];
$batch[] = new Subrequest([
'uri' => '/test/types',
'action' => 'create',
'requestId' => 'xyz',
'headers' => [],
'_resolved' => FALSE,
'body' => [
'You are number' => '{{foo.body@$.Number}}',
'Where am I' => '{{foo.body@$.Location}}',
'World of number two' => '{{foo.body@$.Two}}',
'Question' => 'Who is number {{foo.body@$.Who}}?',
'Michael' => '{{foo.body@$.Feigenbaum}}',
],
'waitFor' => ['foo'],
]);
$response = new Response('{"Number":6, "Location":"In the village", "Two":false, "Who":1, "Feigenbaum":4.6692}');
$response->headers->set('Content-ID', '<foo>');
$responses[] = $response;
$actual = $this->sut->replaceBatch($batch, $responses);
$this->assertIsInt($actual[0]->body['You are number']);
$this->assertIsString($actual[0]->body['Where am I']);
$this->assertIsBool($actual[0]->body['World of number two']);
$this->assertIsString($actual[0]->body['Question']);
$this->assertIsFloat($actual[0]->body['Michael']);
}
}

View File

@@ -0,0 +1,104 @@
<?php
namespace Drupal\Tests\subrequests\Normalizer;
use Drupal\subrequests\Normalizer\JsonBlueprintDenormalizer;
use Drupal\subrequests\Subrequest;
use Drupal\subrequests\SubrequestsTree;
use Drupal\Tests\UnitTestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Psr\Log\LoggerInterface;
/**
* @coversDefaultClass \Drupal\subrequests\Normalizer\JsonBlueprintDenormalizer
* @group subrequests
*/
class JsonBlueprintDenormalizerTest extends UnitTestCase {
use ProphecyTrait;
/**
* Json blueprint denormalizer service.
*
* @var \Drupal\subrequests\Normalizer\JsonBlueprintDenormalizer
*/
protected $sut;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$logger = $this->prophesize(LoggerInterface::class);
$this->sut = new JsonBlueprintDenormalizer($logger->reveal());
}
/**
* Test for supportsDenormalization method.
*
* @dataProvider dataProviderSupportsNormalization
* @covers ::supportsDenormalization
*/
public function testSupportsDenormalization($data, $type, $format, $is_supported) {
$actual = $this->sut->supportsDenormalization($data, $type, $format);
$this->assertSame($is_supported, $actual);
}
/**
* Data provider for testSupportsDenormalization.
*/
public static function dataProviderSupportsNormalization(): array {
return [
[['a', 'b'], SubrequestsTree::class, 'json', TRUE],
['fail', SubrequestsTree::class, 'json', FALSE],
[['a', 'b'], SubrequestsTree::class, 'fail', FALSE],
[['fail' => 'a', 'b'], SubrequestsTree::class, 'json', FALSE],
];
}
/**
* Test for denormalize method.
*/
public function testDenormalize() {
$subrequests[] = [
'uri' => 'lorem',
'action' => 'view',
'requestId' => 'foo',
'body' => '"bar"',
'headers' => [],
];
$subrequests[] = [
'uri' => 'ipsum',
'action' => 'sing',
'requestId' => 'oop',
'body' => '[]',
'waitFor' => ['foo'],
];
$subrequests[] = [
// lorem?{{ipsum}}.
'uri' => 'lorem%3F%7B%7Bipsum%7D%7D',
'action' => 'create',
'requestId' => 'oof',
'body' => '"bar"',
'waitFor' => ['foo'],
];
$actual = $this->sut->denormalize($subrequests, SubrequestsTree::class, 'json', []);
$tree = new SubrequestsTree();
$tree->stack([new Subrequest(['waitFor' => ['<ROOT>'], '_resolved' => FALSE, 'body' => 'bar'] + $subrequests[0])]);
$tree->stack([
new Subrequest(['headers' => [], '_resolved' => FALSE, 'body' => []] + $subrequests[1]),
// Make sure the URL is decoded so we can perform apply regular
// expressions to it.
new Subrequest(
[
'headers' => [],
'_resolved' => FALSE,
'body' => 'bar',
'uri' => 'lorem?{{ipsum}}',
] + $subrequests[2]
),
]);
$this->assertEquals($tree, $actual);
}
}

View File

@@ -0,0 +1,90 @@
<?php
namespace Drupal\Tests\subrequests\Normalizer;
use Drupal\Component\Serialization\Json;
use Drupal\subrequests\Normalizer\JsonSubrequestDenormalizer;
use Drupal\subrequests\Subrequest;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\Session;
/**
* @coversDefaultClass \Drupal\subrequests\Normalizer\JsonSubrequestDenormalizer
* @group subrequests
*/
class JsonSubrequestDenormalizerTest extends UnitTestCase {
/**
* Json subrequest denormalizer.
*
* @var \Drupal\subrequests\Normalizer\JsonSubrequestDenormalizer
*/
protected $sut;
/**
* {@inheritdoc}
*/
public function setUp(): void {
parent::setUp();
$this->sut = new JsonSubrequestDenormalizer();
}
/**
* Test for denormalize method.
*
* @covers ::denormalize
*/
public function testDenormalize() {
$class = Request::class;
$data = new Subrequest([
'requestId' => 'oof',
'body' => ['bar' => 'foo'],
'headers' => ['Authorization' => 'Basic ' . base64_encode('lorem:ipsum')],
'waitFor' => ['lorem'],
'_resolved' => FALSE,
'uri' => 'oop',
'action' => 'create',
]);
$request = Request::create('');
$request->setSession(new Session());
$actual = $this->sut->denormalize($data, $class, NULL, ['master_request' => $request]);
$this->assertSame('POST', $actual->getMethod());
$this->assertEquals(['bar' => 'foo'], Json::decode($actual->getContent()));
$this->assertSame('<oof>', $actual->headers->get('Content-ID'));
$this->assertSame('lorem', $actual->headers->get('PHP_AUTH_USER'));
$this->assertSame('ipsum', $actual->headers->get('PHP_AUTH_PW'));
}
/**
* Test for supportsDenormalization method.
*
* @dataProvider dataProviderSupportsNormalization
* @covers ::supportsDenormalization
*/
public function testSupportsDenormalization($data, $type, $format, $is_supported) {
$actual = $this->sut->supportsDenormalization($data, $type, $format);
$this->assertSame($is_supported, $actual);
}
/**
* Data provider for testSupportsDenormalization.
*/
public static function dataProviderSupportsNormalization(): array {
$subrequest = new Subrequest([
'requestId' => 'oof',
'body' => ['bar' => 'foo'],
'headers' => [],
'waitFor' => ['lorem'],
'_resolved' => FALSE,
'uri' => 'oop',
'action' => 'create',
]);
return [
[$subrequest, Request::class, NULL, TRUE],
['fail', Request::class, NULL, FALSE],
[$subrequest, 'fail', NULL, FALSE],
];
}
}

View File

@@ -0,0 +1,80 @@
<?php
namespace Drupal\Tests\subrequests\Normalizer;
use Drupal\Component\Serialization\Json;
use Drupal\subrequests\Normalizer\MultiresponseJsonNormalizer;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Response;
/**
* @coversDefaultClass \Drupal\subrequests\Normalizer\MultiresponseJsonNormalizer
* @group subrequests
*/
class MultiresponseJsonNormalizerTest extends UnitTestCase {
/**
* Json multi response normalizer.
*
* @var \Drupal\subrequests\Normalizer\MultiresponseJsonNormalizer
*/
protected $sut;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->sut = new MultiresponseJsonNormalizer();
}
/**
* Test for supportsNormalization method.
*
* @dataProvider dataProviderSupportsNormalization
* @covers ::supportsNormalization
*/
public function testSupportsNormalization($data, $format, $is_supported) {
$actual = $this->sut->supportsNormalization($data, $format);
$this->assertSame($is_supported, $actual);
}
/**
* Data provider for testSupportsNormalization.
*/
public static function dataProviderSupportsNormalization(): array {
return [
[[new Response('')], 'json', TRUE],
[[], 'json', FALSE],
[[new Response('')], 'fail', FALSE],
[NULL, 'json', FALSE],
[[new Response(''), NULL], 'json', FALSE],
];
}
/**
* Test for normalize method.
*
* @covers ::normalize
*/
public function testNormalize() {
$sub_content_type = $this->getRandomGenerator()->string();
$data = [
new Response('Foo!', 200, ['Content-ID' => '<f>']),
new Response('Bar', 200, ['Content-ID' => '<b>']),
];
$actual = $this->sut->normalize($data, NULL, ['sub-content-type' => $sub_content_type]);
$this->assertSame(
'application/json',
$actual['headers']['Content-Type']
);
$this->assertSame(
$sub_content_type,
$actual['headers']['X-Sub-Content-Type']
);
$parsed = Json::decode($actual['content']);
$this->assertSame('Foo!', $parsed['f']['body']);
$this->assertSame('Bar', $parsed['b']['body']);
}
}

View File

@@ -0,0 +1,72 @@
<?php
namespace Drupal\Tests\subrequests\Normalizer;
use Drupal\subrequests\Normalizer\MultiresponseNormalizer;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Response;
/**
* @coversDefaultClass \Drupal\subrequests\Normalizer\MultiresponseNormalizer
* @group subrequests
*/
class MultiresponseNormalizerTest extends UnitTestCase {
/**
* Multi response normalizer service.
*
* @var \Drupal\subrequests\Normalizer\MultiresponseNormalizer
*/
protected $sut;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->sut = new MultiresponseNormalizer();
}
/**
* Test for supportsNormalization method.
*
* @dataProvider dataProviderSupportsNormalization
* @covers ::supportsNormalization
*/
public function testSupportsNormalization($data, $format, $is_supported) {
$actual = $this->sut->supportsNormalization($data, $format);
$this->assertSame($is_supported, $actual);
}
/**
* Data provider for testSupportsNormalization.
*/
public static function dataProviderSupportsNormalization(): array {
return [
[[new Response('')], 'multipart-related', TRUE],
[[], 'multipart-related', FALSE],
[[new Response('')], 'fail', FALSE],
[NULL, 'multipart-related', FALSE],
[[new Response(''), NULL], 'multipart-related', FALSE],
];
}
/**
* Test for normalize method.
*
* @covers ::normalize
*/
public function testNormalize() {
$sub_content_type = $this->getRandomGenerator()->string();
$data = [new Response('Foo!'), new Response('Bar')];
$actual = $this->sut->normalize($data, NULL, ['sub-content-type' => $sub_content_type]);
$parts = explode('; ', $actual['headers']['Content-Type']);
parse_str($parts[1], $parts);
$delimiter = substr($parts['boundary'], 1, strlen($parts['boundary']) - 2);
$this->assertStringStartsWith('--' . $delimiter, $actual['content']);
$this->assertStringEndsWith('--' . $delimiter . '--', $actual['content']);
$this->assertMatchesRegularExpression("/\r\nFoo!\r\n/", $actual['content']);
$this->assertMatchesRegularExpression("/\r\nBar\r\n/", $actual['content']);
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace Drupal\Tests\subrequests\Unit;
use Drupal\subrequests\JsonPathReplacer;
use Drupal\subrequests\Normalizer\JsonSubrequestDenormalizer;
use Drupal\subrequests\Subrequest;
use Drupal\subrequests\SubrequestsManager;
use Drupal\subrequests\SubrequestsTree;
use Drupal\Tests\UnitTestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Serializer\Encoder\JsonDecode;
use Symfony\Component\Serializer\Serializer;
/**
* @coversDefaultClass \Drupal\subrequests\SubrequestsManager
* @group subrequests
*/
class SubrequestsManagerTest extends UnitTestCase {
use ProphecyTrait;
/**
* Subrequest manager.
*
* @var \Drupal\subrequests\SubrequestsManager
*/
protected $sut;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$http_kernel = $this->prophesize(HttpKernelInterface::class);
$http_kernel
->handle(Argument::type(Request::class), HttpKernelInterface::MAIN_REQUEST)
->will(function ($args) {
return new Response($args[0]->getPathInfo());
});
$serializer = new Serializer(
[new JsonSubrequestDenormalizer()],
[new JsonDecode()]
);
$this->sut = new SubrequestsManager(
$http_kernel->reveal(),
$serializer,
new JsonPathReplacer()
);
}
/**
* Test for request method.
*
* @covers ::request
*/
public function testRequest() {
// Create and populate a tree.
$tree = new SubrequestsTree();
$subrequests[] = new Subrequest([
'uri' => 'lorem',
'action' => 'view',
'requestId' => 'foo',
'headers' => [],
'waitFor' => ['<ROOT>'],
'_resolved' => FALSE,
'body' => 'bar',
]);
$subrequests[] = new Subrequest([
'uri' => 'ipsum',
'action' => 'sing',
'requestId' => 'oop',
'headers' => [],
'_resolved' => FALSE,
'body' => [],
'waitFor' => ['foo'],
]);
$subrequests[] = new Subrequest([
'uri' => 'dolor',
'action' => 'create',
'requestId' => 'oof',
'headers' => [],
'_resolved' => FALSE,
'body' => 'bar',
'waitFor' => ['foo'],
]);
$tree->stack([$subrequests[0]]);
$tree->stack([$subrequests[1], $subrequests[2]]);
$master_request = new Request();
$master_request->setSession($this->createMock(SessionInterface::class));
$tree->setMasterRequest($master_request);
$actual = $this->sut->request($tree);
$this->assertSame('<foo>', $actual[0]->headers->get('Content-ID'));
$this->assertSame('<oop>', $actual[1]->headers->get('Content-ID'));
$this->assertSame('<oof>', $actual[2]->headers->get('Content-ID'));
$this->assertSame('/lorem', $actual[0]->getContent());
$this->assertSame('/ipsum', $actual[1]->getContent());
$this->assertSame('/dolor', $actual[2]->getContent());
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace Drupal\Tests\subrequests\Unit;
use Drupal\subrequests\Subrequest;
use Drupal\subrequests\SubrequestsTree;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\subrequests\SubrequestsTree
* @group subrequests
*/
class SubrequestsTreeTest extends UnitTestCase {
/**
* Test for stack method.
*
* @dataProvider dataProviderStack
* @covers ::stack
* @covers ::getLowestLevel
* @covers ::getNumLevels
*/
public function testStack($input, $expected_count) {
$sut = new SubrequestsTree();
$sut->stack($input);
$this->assertSame(1, $sut->getNumLevels());
$this->assertCount($expected_count, $sut->getLowestLevel());
}
/**
* Data provider for testSupportsNormalization.
*/
public static function dataProviderStack(): array {
$defaults = [
'requestId' => 1,
'body' => '',
'headers' => [],
'waitFor' => [1],
'_resolved' => FALSE,
'uri' => '',
'action' => '',
];
return [
[[new Subrequest($defaults), 12, new Subrequest($defaults)], 2],
[[12], 0],
];
}
}