Loading core/lib/Drupal/Core/CoreServiceProvider.php +7 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ use Drupal\Core\Render\MainContent\MainContentRenderersPass; use Drupal\Core\Site\Settings; use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** Loading Loading @@ -142,6 +143,12 @@ protected function registerTest(ContainerBuilder $container) { $container ->register('test.http_client.middleware', 'Drupal\Core\Test\HttpClientMiddleware\TestHttpClientMiddleware') ->addTag('http_client_middleware'); // Add the wait terminate middleware which acquires a lock to signal request // termination to the test runner. $container ->register('test.http_middleware.wait_terminate_middleware', 'Drupal\Core\Test\StackMiddleware\TestWaitTerminateMiddleware') ->setArguments([new Reference('state'), new Reference('lock')]) ->addTag('http_middleware', ['priority' => -1024]); } } core/lib/Drupal/Core/Test/HttpClientMiddleware/TestHttpClientMiddleware.php +7 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,13 @@ public function __invoke() { if (!drupal_valid_test_ua()) { return $response; } if (!empty($response->getHeader('X-Drupal-Wait-Terminate')[0])) { $lock = \Drupal::lock(); if (!$lock->acquire('test_wait_terminate')) { $lock->wait('test_wait_terminate'); } $lock->release('test_wait_terminate'); } $headers = $response->getHeaders(); foreach ($headers as $header_name => $header_values) { if (preg_match('/^X-Drupal-Assertion-[0-9]+$/', $header_name, $matches)) { Loading core/lib/Drupal/Core/Test/StackMiddleware/TestWaitTerminateMiddleware.php 0 → 100644 +50 −0 Original line number Diff line number Diff line <?php namespace Drupal\Core\Test\StackMiddleware; use Drupal\Core\Lock\LockBackendInterface; use Drupal\Core\State\StateInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Acquire a lock to signal request termination to the test runner. */ class TestWaitTerminateMiddleware implements HttpKernelInterface { /** * Constructs a test wait terminate stack middleware object. * * @param \Symfony\Component\HttpKernel\HttpKernelInterface $httpKernel * The decorated kernel. * @param \Drupal\Core\State\StateInterface $state * The state server. * @param \Drupal\Core\Lock\LockBackendInterface $lock * The lock backend. */ public function __construct( protected HttpKernelInterface $httpKernel, protected StateInterface $state, protected LockBackendInterface $lock ) { } /** * {@inheritdoc} */ public function handle(Request $request, $type = self::MAIN_REQUEST, $catch = TRUE): Response { $result = $this->httpKernel->handle($request, $type, $catch); if ($this->state->get('drupal.test_wait_terminate')) { // Set a header on the response to instruct the test runner that it must // await the lock. Note that the lock acquired here is automatically // released from within a shutdown function. $this->lock->acquire('test_wait_terminate'); $result->headers->set('X-Drupal-Wait-Terminate', '1'); } return $result; } } core/modules/jsonapi/tests/src/Functional/NodeTest.php +4 −4 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ use Drupal\node\Entity\Node; use Drupal\node\Entity\NodeType; use Drupal\Tests\jsonapi\Traits\CommonCollectionFilterAccessTestPatternsTrait; use Drupal\Tests\WaitTerminateTestTrait; use Drupal\user\Entity\User; use GuzzleHttp\RequestOptions; Loading @@ -22,6 +23,7 @@ class NodeTest extends ResourceTestBase { use CommonCollectionFilterAccessTestPatternsTrait; use WaitTerminateTestTrait; /** * {@inheritdoc} Loading Loading @@ -315,6 +317,8 @@ public function testPatchPath() { * {@inheritdoc} */ public function testGetIndividual() { $this->setWaitForTerminate(); parent::testGetIndividual(); $this->assertCacheableNormalizations(); Loading Loading @@ -393,15 +397,11 @@ protected function assertCacheableNormalizations(): void { $request_options = $this->getAuthenticationRequestOptions(); $request_options[RequestOptions::QUERY] = ['fields' => ['node--camelids' => 'title']]; $this->request('GET', $url, $request_options); // Cacheable normalizations are written after the response is flushed to // the client; give the server a chance to complete this work. sleep(1); // Ensure the normalization cache is being incrementally built. After // requesting the title, only the title is in the cache. $this->assertNormalizedFieldsAreCached(['title']); $request_options[RequestOptions::QUERY] = ['fields' => ['node--camelids' => 'field_rest_test']]; $this->request('GET', $url, $request_options); sleep(1); // After requesting an additional field, then that field is in the cache and // the old one is still there. $this->assertNormalizedFieldsAreCached(['title', 'field_rest_test']); Loading core/modules/language/tests/src/Functional/ConfigurableLanguageManagerTest.php +5 −12 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ use Drupal\node\Entity\Node; use Drupal\node\Entity\NodeType; use Drupal\Tests\BrowserTestBase; use Drupal\Tests\WaitTerminateTestTrait; /** * Tests Language Negotiation. Loading @@ -21,6 +22,8 @@ */ class ConfigurableLanguageManagerTest extends BrowserTestBase { use WaitTerminateTestTrait; /** * {@inheritdoc} */ Loading @@ -45,6 +48,8 @@ class ConfigurableLanguageManagerTest extends BrowserTestBase { protected function setUp(): void { parent::setUp(); $this->setWaitForTerminate(); /** @var \Drupal\user\UserInterface $user */ $user = $this->createUser([], '', TRUE); $this->drupalLogin($user); Loading Loading @@ -266,16 +271,4 @@ public function testUserProfileTranslationWithPreferredAdminLanguage() { $assert_session->pageTextNotContains($field_label_es); } /** * {@inheritdoc} */ protected function drupalGet($path, array $options = [], array $headers = []) { $response = parent::drupalGet($path, $options, $headers); // The \Drupal\locale\LocaleTranslation service clears caches after the // response is flushed to the client; wait for Drupal to perform its // termination work before continuing. sleep(1); return $response; } } Loading
core/lib/Drupal/Core/CoreServiceProvider.php +7 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ use Drupal\Core\Render\MainContent\MainContentRenderersPass; use Drupal\Core\Site\Settings; use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** Loading Loading @@ -142,6 +143,12 @@ protected function registerTest(ContainerBuilder $container) { $container ->register('test.http_client.middleware', 'Drupal\Core\Test\HttpClientMiddleware\TestHttpClientMiddleware') ->addTag('http_client_middleware'); // Add the wait terminate middleware which acquires a lock to signal request // termination to the test runner. $container ->register('test.http_middleware.wait_terminate_middleware', 'Drupal\Core\Test\StackMiddleware\TestWaitTerminateMiddleware') ->setArguments([new Reference('state'), new Reference('lock')]) ->addTag('http_middleware', ['priority' => -1024]); } }
core/lib/Drupal/Core/Test/HttpClientMiddleware/TestHttpClientMiddleware.php +7 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,13 @@ public function __invoke() { if (!drupal_valid_test_ua()) { return $response; } if (!empty($response->getHeader('X-Drupal-Wait-Terminate')[0])) { $lock = \Drupal::lock(); if (!$lock->acquire('test_wait_terminate')) { $lock->wait('test_wait_terminate'); } $lock->release('test_wait_terminate'); } $headers = $response->getHeaders(); foreach ($headers as $header_name => $header_values) { if (preg_match('/^X-Drupal-Assertion-[0-9]+$/', $header_name, $matches)) { Loading
core/lib/Drupal/Core/Test/StackMiddleware/TestWaitTerminateMiddleware.php 0 → 100644 +50 −0 Original line number Diff line number Diff line <?php namespace Drupal\Core\Test\StackMiddleware; use Drupal\Core\Lock\LockBackendInterface; use Drupal\Core\State\StateInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Acquire a lock to signal request termination to the test runner. */ class TestWaitTerminateMiddleware implements HttpKernelInterface { /** * Constructs a test wait terminate stack middleware object. * * @param \Symfony\Component\HttpKernel\HttpKernelInterface $httpKernel * The decorated kernel. * @param \Drupal\Core\State\StateInterface $state * The state server. * @param \Drupal\Core\Lock\LockBackendInterface $lock * The lock backend. */ public function __construct( protected HttpKernelInterface $httpKernel, protected StateInterface $state, protected LockBackendInterface $lock ) { } /** * {@inheritdoc} */ public function handle(Request $request, $type = self::MAIN_REQUEST, $catch = TRUE): Response { $result = $this->httpKernel->handle($request, $type, $catch); if ($this->state->get('drupal.test_wait_terminate')) { // Set a header on the response to instruct the test runner that it must // await the lock. Note that the lock acquired here is automatically // released from within a shutdown function. $this->lock->acquire('test_wait_terminate'); $result->headers->set('X-Drupal-Wait-Terminate', '1'); } return $result; } }
core/modules/jsonapi/tests/src/Functional/NodeTest.php +4 −4 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ use Drupal\node\Entity\Node; use Drupal\node\Entity\NodeType; use Drupal\Tests\jsonapi\Traits\CommonCollectionFilterAccessTestPatternsTrait; use Drupal\Tests\WaitTerminateTestTrait; use Drupal\user\Entity\User; use GuzzleHttp\RequestOptions; Loading @@ -22,6 +23,7 @@ class NodeTest extends ResourceTestBase { use CommonCollectionFilterAccessTestPatternsTrait; use WaitTerminateTestTrait; /** * {@inheritdoc} Loading Loading @@ -315,6 +317,8 @@ public function testPatchPath() { * {@inheritdoc} */ public function testGetIndividual() { $this->setWaitForTerminate(); parent::testGetIndividual(); $this->assertCacheableNormalizations(); Loading Loading @@ -393,15 +397,11 @@ protected function assertCacheableNormalizations(): void { $request_options = $this->getAuthenticationRequestOptions(); $request_options[RequestOptions::QUERY] = ['fields' => ['node--camelids' => 'title']]; $this->request('GET', $url, $request_options); // Cacheable normalizations are written after the response is flushed to // the client; give the server a chance to complete this work. sleep(1); // Ensure the normalization cache is being incrementally built. After // requesting the title, only the title is in the cache. $this->assertNormalizedFieldsAreCached(['title']); $request_options[RequestOptions::QUERY] = ['fields' => ['node--camelids' => 'field_rest_test']]; $this->request('GET', $url, $request_options); sleep(1); // After requesting an additional field, then that field is in the cache and // the old one is still there. $this->assertNormalizedFieldsAreCached(['title', 'field_rest_test']); Loading
core/modules/language/tests/src/Functional/ConfigurableLanguageManagerTest.php +5 −12 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ use Drupal\node\Entity\Node; use Drupal\node\Entity\NodeType; use Drupal\Tests\BrowserTestBase; use Drupal\Tests\WaitTerminateTestTrait; /** * Tests Language Negotiation. Loading @@ -21,6 +22,8 @@ */ class ConfigurableLanguageManagerTest extends BrowserTestBase { use WaitTerminateTestTrait; /** * {@inheritdoc} */ Loading @@ -45,6 +48,8 @@ class ConfigurableLanguageManagerTest extends BrowserTestBase { protected function setUp(): void { parent::setUp(); $this->setWaitForTerminate(); /** @var \Drupal\user\UserInterface $user */ $user = $this->createUser([], '', TRUE); $this->drupalLogin($user); Loading Loading @@ -266,16 +271,4 @@ public function testUserProfileTranslationWithPreferredAdminLanguage() { $assert_session->pageTextNotContains($field_label_es); } /** * {@inheritdoc} */ protected function drupalGet($path, array $options = [], array $headers = []) { $response = parent::drupalGet($path, $options, $headers); // The \Drupal\locale\LocaleTranslation service clears caches after the // response is flushed to the client; wait for Drupal to perform its // termination work before continuing. sleep(1); return $response; } }