diff --git a/automatic_updates_extensions/tests/modules/automatic_updates_extensions_test_api/automatic_updates_extensions_test_api.info.yml b/automatic_updates_extensions/tests/modules/automatic_updates_extensions_test_api/automatic_updates_extensions_test_api.info.yml index 81a15e3ea75a4d46e75392c73d1ffe786b46b377..354140b9a514670a370bf1f012e0e753f608f0bb 100644 --- a/automatic_updates_extensions/tests/modules/automatic_updates_extensions_test_api/automatic_updates_extensions_test_api.info.yml +++ b/automatic_updates_extensions/tests/modules/automatic_updates_extensions_test_api/automatic_updates_extensions_test_api.info.yml @@ -4,3 +4,4 @@ type: module package: Testing dependencies: - automatic_updates:automatic_updates_extensions + - automatic_updates:package_manager_test_api diff --git a/automatic_updates_extensions/tests/modules/automatic_updates_extensions_test_api/automatic_updates_extensions_test_api.routing.yml b/automatic_updates_extensions/tests/modules/automatic_updates_extensions_test_api/automatic_updates_extensions_test_api.routing.yml index c74bb67edc0dcb48ec5c5a7d628669e08a4c95ca..0c8f41c72c6752549ec9407a94fa7eaa62933714 100644 --- a/automatic_updates_extensions/tests/modules/automatic_updates_extensions_test_api/automatic_updates_extensions_test_api.routing.yml +++ b/automatic_updates_extensions/tests/modules/automatic_updates_extensions_test_api/automatic_updates_extensions_test_api.routing.yml @@ -4,3 +4,9 @@ automatic_updates_extensions_test_api: _controller: 'Drupal\automatic_updates_extensions_test_api\ApiController::run' requirements: _access: 'TRUE' +automatic_updates_extensions_test_api.finish: + path: '/automatic-updates-extensions-test-api/finish/{id}' + defaults: + _controller: 'Drupal\automatic_updates_extensions_test_api\ApiController::finish' + requirements: + _access: 'TRUE' diff --git a/automatic_updates_extensions/tests/modules/automatic_updates_extensions_test_api/src/ApiController.php b/automatic_updates_extensions/tests/modules/automatic_updates_extensions_test_api/src/ApiController.php index 0a58fedca8e80f1af872ab9f04f256a4d4d8d29e..1a8b520068e8e900b76f812d0795daefea10d443 100644 --- a/automatic_updates_extensions/tests/modules/automatic_updates_extensions_test_api/src/ApiController.php +++ b/automatic_updates_extensions/tests/modules/automatic_updates_extensions_test_api/src/ApiController.php @@ -2,45 +2,19 @@ namespace Drupal\automatic_updates_extensions_test_api; -use Drupal\automatic_updates_extensions\ExtensionUpdater; -use Drupal\Core\Controller\ControllerBase; -use Drupal\package_manager\PathLocator; use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; +use Drupal\package_manager_test_api\ApiController as PackageManagerApiController; /** * Provides API endpoints to interact with a staging area in functional tests. */ -class ApiController extends ControllerBase { - - - /** - * The extension updater. - * - * @var \Drupal\automatic_updates_extensions\ExtensionUpdater - */ - private $extensionUpdater; +class ApiController extends PackageManagerApiController { /** - * The path locator service. - * - * @var \Drupal\package_manager\PathLocator - */ - private $pathLocator; - - /** - * Constructs an ApiController object. - * - * @param \Drupal\automatic_updates_extensions\ExtensionUpdater $extension_updater - * The updater. - * @param \Drupal\package_manager\PathLocator $path_locator - * The path locator service. + * {@inheritdoc} */ - public function __construct(ExtensionUpdater $extension_updater, PathLocator $path_locator) { - $this->extensionUpdater = $extension_updater; - $this->pathLocator = $path_locator; - } + protected $finishedRoute = 'automatic_updates_extensions_test_api.finish'; /** * {@inheritdoc} @@ -53,36 +27,13 @@ class ApiController extends ControllerBase { } /** - * Runs a complete stage life cycle. - * - * Creates a staging area, requires packages into it, applies changes to the - * active directory, and destroys the stage. - * - * @param \Symfony\Component\HttpFoundation\Request $request - * The request. The runtime and dev dependencies are expected to be in - * either the query string or request body, under the 'runtime' and 'dev' - * keys, respectively. There may also be a 'files_to_return' key, which - * contains an array of file paths, relative to the project root, whose - * contents should be returned in the response. - * - * @return \Symfony\Component\HttpFoundation\JsonResponse - * A JSON response containing an associative array of the contents of the - * files listed in the 'files_to_return' request key. The array will be - * keyed by path, relative to the project root. + * {@inheritdoc} */ - public function run(Request $request): JsonResponse { - $this->extensionUpdater->begin($request->get('projects', [])); - $this->extensionUpdater->stage(); - $this->extensionUpdater->apply(); - $this->extensionUpdater->postApply(); - $this->extensionUpdater->destroy(); - - $dir = $this->pathLocator->getProjectRoot(); - $file_contents = []; - foreach ($request->get('files_to_return', []) as $path) { - $file_contents[$path] = file_get_contents($dir . '/' . $path); - } - return new JsonResponse($file_contents); + protected function createAndApplyStage(Request $request): string { + $id = $this->stage->begin($request->get('projects', [])); + $this->stage->stage(); + $this->stage->apply(); + return $id; } } diff --git a/package_manager/tests/modules/package_manager_test_api/src/ApiController.php b/package_manager/tests/modules/package_manager_test_api/src/ApiController.php index 35269cc57eeef1255d34be8241c0cde539407ec9..9904d9f3a089c73c827324424e7421b1a62ff4a1 100644 --- a/package_manager/tests/modules/package_manager_test_api/src/ApiController.php +++ b/package_manager/tests/modules/package_manager_test_api/src/ApiController.php @@ -16,12 +16,19 @@ use Symfony\Component\HttpFoundation\Request; */ class ApiController extends ControllerBase { + /** + * The route to redirect to after the stage has been applied. + * + * @var string + */ + protected $finishedRoute = 'package_manager_test_api.finish'; + /** * The stage. * * @var \Drupal\package_manager\Stage */ - private $stage; + protected $stage; /** * The path locator service. @@ -83,14 +90,8 @@ class ApiController extends ControllerBase { * @see ::finish() */ public function run(Request $request): RedirectResponse { - $id = $this->stage->create(); - $this->stage->require( - $request->get('runtime', []), - $request->get('dev', []) - ); - $this->stage->apply(); - - $redirect_url = Url::fromRoute('package_manager_test_api.finish') + $id = $this->createAndApplyStage($request); + $redirect_url = Url::fromRoute($this->finishedRoute) ->setRouteParameter('id', $id) ->setOption('query', [ 'files_to_return' => $request->get('files_to_return', []), @@ -128,4 +129,29 @@ class ApiController extends ControllerBase { return new JsonResponse($file_contents); } + /** + * Creates a stage, requires packages into it, and applies the changes. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request. The runtime and dev dependencies are expected to be in + * either the query string or request body, under the 'runtime' and 'dev' + * keys, respectively. There may also be a 'files_to_return' key, which + * contains an array of file paths, relative to the project root, whose + * contents should be returned in the response. + * + * @return string + * Unique ID for the stage, which can be used to claim the stage before + * performing other operations on it. Calling code should store this ID for + * as long as the stage needs to exist. + */ + protected function createAndApplyStage(Request $request) : string { + $id = $this->stage->create(); + $this->stage->require( + $request->get('runtime', []), + $request->get('dev', []) + ); + $this->stage->apply(); + return $id; + } + } diff --git a/package_manager/tests/src/Build/TemplateProjectTestBase.php b/package_manager/tests/src/Build/TemplateProjectTestBase.php index 172a7de6055fa4055dc437bf0baa0e58be3a39a9..836ef51b8be2d669dda29733d705b503d8802cde 100644 --- a/package_manager/tests/src/Build/TemplateProjectTestBase.php +++ b/package_manager/tests/src/Build/TemplateProjectTestBase.php @@ -164,7 +164,7 @@ END; * @param array $xml_map * The update XML map, as used by update_test.settings. * - * @see \Drupal\automatic_updates_test\TestController::metadata() + * @see \Drupal\package_manager_test_release_history\TestController::metadata() */ protected function setReleaseMetadata(array $xml_map): void { foreach ($xml_map as $metadata_file) { diff --git a/tests/modules/automatic_updates_test/automatic_updates_test.routing.yml b/tests/modules/automatic_updates_test/automatic_updates_test.routing.yml deleted file mode 100644 index c7bc51971b7fb458f771371f6c2e54dbf93110d5..0000000000000000000000000000000000000000 --- a/tests/modules/automatic_updates_test/automatic_updates_test.routing.yml +++ /dev/null @@ -1,8 +0,0 @@ -automatic_updates_test.update: - path: '/automatic-update-test/update/{to_version}' - defaults: - _controller: '\Drupal\automatic_updates_test\TestController::update' - requirements: - _access: 'TRUE' - options: - _maintenance_access: TRUE diff --git a/tests/modules/automatic_updates_test/src/TestController.php b/tests/modules/automatic_updates_test/src/TestController.php deleted file mode 100644 index 192aceb520439444b3aaded513afe9c381b98d3b..0000000000000000000000000000000000000000 --- a/tests/modules/automatic_updates_test/src/TestController.php +++ /dev/null @@ -1,62 +0,0 @@ -<?php - -namespace Drupal\automatic_updates_test; - -use Drupal\automatic_updates\Exception\UpdateException; -use Drupal\Core\Controller\ControllerBase; -use Drupal\Core\Render\HtmlResponse; -use Symfony\Component\HttpFoundation\Response; - -class TestController extends ControllerBase { - - /** - * Performs an in-place update to a given version of Drupal core. - * - * This executes the update immediately, in one request, without using the - * batch system or cron as wrappers. - * - * @param string $to_version - * The version of core to update to. - * - * @return \Symfony\Component\HttpFoundation\Response - * The response object. - */ - public function update(string $to_version): Response { - - /** @var \Drupal\automatic_updates\Updater $updater */ - $updater = \Drupal::service('automatic_updates.updater'); - try { - $updater->begin(['drupal' => $to_version]); - $updater->stage(); - $updater->apply(); - $updater->postApply(); - $updater->destroy(); - - // The code base has been updated, but as far as the PHP runtime is - // concerned, \Drupal::VERSION refers to the old version, until the next - // request. So check if the updated version is in Drupal.php and return - // a clear indication of whether it's there or not. - $drupal_php = file_get_contents(\Drupal::root() . '/core/lib/Drupal.php'); - if (str_contains($drupal_php, "const VERSION = '$to_version';")) { - $content = "$to_version found in Drupal.php"; - } - else { - $content = "$to_version not found in Drupal.php"; - } - $status = 200; - } - catch (UpdateException $e) { - $messages = []; - foreach ($e->getResults() as $result) { - if ($summary = $result->getSummary()) { - $messages[] = $summary; - } - $messages = array_merge($messages, $result->getMessages()); - } - $content = implode('<br />', $messages); - $status = 500; - } - return new HtmlResponse($content, $status); - } - -} diff --git a/tests/modules/automatic_updates_test_api/automatic_updates_test_api.info.yml b/tests/modules/automatic_updates_test_api/automatic_updates_test_api.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..9b0871e7c166dc1792f262ebe06807a2f27785f1 --- /dev/null +++ b/tests/modules/automatic_updates_test_api/automatic_updates_test_api.info.yml @@ -0,0 +1,6 @@ +name: 'Automatic Updates Test API' +description: 'Provides API endpoints for doing stage operations in functional tests.' +type: module +package: Testing +dependencies: + - automatic_updates:package_manager_test_api diff --git a/tests/modules/automatic_updates_test_api/automatic_updates_test_api.routing.yml b/tests/modules/automatic_updates_test_api/automatic_updates_test_api.routing.yml new file mode 100644 index 0000000000000000000000000000000000000000..821c91b431953ba82f05765d2f9891034d6a5a51 --- /dev/null +++ b/tests/modules/automatic_updates_test_api/automatic_updates_test_api.routing.yml @@ -0,0 +1,14 @@ +automatic_updates_test_api.update: + path: '/automatic-updates-test-api' + defaults: + _controller: 'Drupal\automatic_updates_test_api\ApiController::run' + requirements: + _access: 'TRUE' + options: + _maintenance_access: TRUE +automatic_updates_test_api.finish: + path: '/automatic-updates-test-api/finish/{id}' + defaults: + _controller: 'Drupal\automatic_updates_test_api\ApiController::finish' + requirements: + _access: 'TRUE' diff --git a/tests/modules/automatic_updates_test_api/src/ApiController.php b/tests/modules/automatic_updates_test_api/src/ApiController.php new file mode 100644 index 0000000000000000000000000000000000000000..855accd4d410681e577f829c4646c0b52ac15e53 --- /dev/null +++ b/tests/modules/automatic_updates_test_api/src/ApiController.php @@ -0,0 +1,36 @@ +<?php + +namespace Drupal\automatic_updates_test_api; + +use Drupal\package_manager_test_api\ApiController as PackageManagerApiController; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\Request; + +class ApiController extends PackageManagerApiController { + + /** + * {@inheritdoc} + */ + protected $finishedRoute = 'automatic_updates_test_api.finish'; + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('automatic_updates.updater'), + $container->get('package_manager.path_locator') + ); + } + + /** + * {@inheritdoc} + */ + protected function createAndApplyStage(Request $request): string { + $id = $this->stage->begin($request->get('projects', [])); + $this->stage->stage(); + $this->stage->apply(); + return $id; + } + +} diff --git a/tests/src/Build/CoreUpdateTest.php b/tests/src/Build/CoreUpdateTest.php index 55f1ebcfbc300865518aec16fc6d8b9416986672..3af3e281f1ca2ac49a721eca1884e07abd5f54d6 100644 --- a/tests/src/Build/CoreUpdateTest.php +++ b/tests/src/Build/CoreUpdateTest.php @@ -63,20 +63,28 @@ class CoreUpdateTest extends UpdateTestBase { */ public function testApi(): void { $this->createTestProject('RecommendedProject'); - - $mink = $this->getMink(); - $assert_session = $mink->assertSession(); - + $query = http_build_query([ + 'projects' => [ + 'drupal' => '9.8.1', + ], + 'files_to_return' => [ + 'web/core/lib/Drupal.php', + ], + ]); // Ensure that the update is prevented if the web root and/or vendor // directories are not writable. - $this->assertReadOnlyFileSystemError('/automatic-update-test/update/9.8.1'); + $this->assertReadOnlyFileSystemError("/automatic-updates-test-api?$query"); + $mink = $this->getMink(); $session = $mink->getSession(); $session->reload(); - $this->assertSame('9.8.1 found in Drupal.php', trim($session->getPage()->getContent())); + $mink->assertSession()->statusCodeEquals(200); + $file_contents = $session->getPage()->getContent(); + $file_contents = json_decode($file_contents, TRUE, 512, JSON_THROW_ON_ERROR); + $this->assertStringContainsString("const VERSION = '9.8.1';", $file_contents['web/core/lib/Drupal.php']); // Even though the response is what we expect, assert the status code as // well, to be extra-certain that there was no kind of server-side error. - $assert_session->statusCodeEquals(200); + $this->assertUpdateSuccessful('9.8.1'); } diff --git a/tests/src/Build/UpdateTestBase.php b/tests/src/Build/UpdateTestBase.php index effacbb73f885abf6ec3c2fa2211a382796a317e..a8156a49d9c06cca20ded599d0bbb580ffc07f24 100644 --- a/tests/src/Build/UpdateTestBase.php +++ b/tests/src/Build/UpdateTestBase.php @@ -19,7 +19,7 @@ abstract class UpdateTestBase extends TemplateProjectTestBase { // Install Automatic Updates, and other modules needed for testing. $this->installModules([ 'automatic_updates', - 'automatic_updates_test', + 'automatic_updates_test_api', 'automatic_updates_test_cron', ]); }