From e1dac5fbf5f2fe8c3e7f90762bf2e7963d7bc1dc Mon Sep 17 00:00:00 2001 From: phenaproxima <phenaproxima@205645.no-reply.drupal.org> Date: Thu, 26 May 2022 16:26:23 +0000 Subject: [PATCH] Issue #3281397 by phenaproxima: VersionPolicyValidator should throw an exception if it can't determine the target version of Drupal --- src/Validator/VersionPolicyValidator.php | 27 ++++++-- .../Kernel/AutomaticUpdatesKernelTestBase.php | 7 ++ .../VersionPolicyValidatorTest.php | 64 +++++++++++++++++++ 3 files changed, 91 insertions(+), 7 deletions(-) diff --git a/src/Validator/VersionPolicyValidator.php b/src/Validator/VersionPolicyValidator.php index 37c26e68d5..e20086c370 100644 --- a/src/Validator/VersionPolicyValidator.php +++ b/src/Validator/VersionPolicyValidator.php @@ -172,10 +172,15 @@ final class VersionPolicyValidator implements EventSubscriberInterface { * The event object. * * @return string|null - * The target version of Drupal core, or NULL if it could not be determined. + * The target version of Drupal core, or NULL if it could not be determined + * during a readiness check. * - * @todo Throw an exception in certain (maybe all) situations if we cannot - * figure out the target version in https://www.drupal.org/i/3280180. + * @throws \LogicException + * Thrown if the target version cannot be determined due to unexpected + * conditions. This can happen if, during a stage life cycle event (i.e., + * NOT a readiness check), the event or updater does not have a list of + * desired package versions, or the list of package versions does not + * include any Drupal core packages. */ private function getTargetVersion(StageEvent $event): ?string { $updater = $event->getStage(); @@ -187,16 +192,24 @@ final class VersionPolicyValidator implements EventSubscriberInterface { $package_versions = $updater->getPackageVersions()['production']; } + $unknown_target = new \LogicException('The target version of Drupal core could not be determined.'); + if ($package_versions) { $core_package_name = key($updater->getActiveComposer()->getCorePackages()); - return $package_versions[$core_package_name]; + + if ($core_package_name && array_key_exists($core_package_name, $package_versions)) { + return $package_versions[$core_package_name]; + } + else { + throw $unknown_target; + } } elseif ($event instanceof ReadinessCheckEvent) { + // It's okay if this returns NULL; it means there's nothing to update to. return $this->getTargetVersionFromAvailableReleases($updater); } - else { - return NULL; - } + // If we got here, something has gone very wrong. + throw $unknown_target; } /** diff --git a/tests/src/Kernel/AutomaticUpdatesKernelTestBase.php b/tests/src/Kernel/AutomaticUpdatesKernelTestBase.php index 3788fb4bb4..8900b78412 100644 --- a/tests/src/Kernel/AutomaticUpdatesKernelTestBase.php +++ b/tests/src/Kernel/AutomaticUpdatesKernelTestBase.php @@ -152,6 +152,13 @@ class TestUpdater extends Updater { use TestStageTrait; + /** + * {@inheritdoc} + */ + public function setMetadata(string $key, $data): void { + parent::setMetadata($key, $data); + } + } /** diff --git a/tests/src/Kernel/ReadinessValidation/VersionPolicyValidatorTest.php b/tests/src/Kernel/ReadinessValidation/VersionPolicyValidatorTest.php index 97bcf17920..d8cd1aa8ca 100644 --- a/tests/src/Kernel/ReadinessValidation/VersionPolicyValidatorTest.php +++ b/tests/src/Kernel/ReadinessValidation/VersionPolicyValidatorTest.php @@ -3,6 +3,8 @@ namespace Drupal\Tests\automatic_updates\Kernel\ReadinessValidation; use Drupal\automatic_updates\CronUpdater; +use Drupal\package_manager\Event\PreCreateEvent; +use Drupal\package_manager\Exception\StageException; use Drupal\package_manager\Exception\StageValidationException; use Drupal\package_manager\ValidationResult; use Drupal\Tests\automatic_updates\Kernel\AutomaticUpdatesKernelTestBase; @@ -462,4 +464,66 @@ class VersionPolicyValidatorTest extends AutomaticUpdatesKernelTestBase { return ValidationResult::createError($messages, $summary); } + /** + * Tests that an error is raised if there are no stored package versions. + * + * This is a contrived situation that should never happen in real life, but + * just in case it does, we need to be sure that it's an error condition. + */ + public function testNoStagedPackageVersions(): void { + // Remove the stored package versions from the updater's metadata. + $listener = function (PreCreateEvent $event): void { + /** @var \Drupal\Tests\automatic_updates\Kernel\TestUpdater $updater */ + $updater = $event->getStage(); + $updater->setMetadata('packages', [ + 'production' => [], + ]); + }; + $this->assertTargetVersionNotDiscoverable($listener); + } + + /** + * Tests that an error is raised if no core packages are installed. + * + * This is a contrived situation that should never happen in real life, but + * just in case it does, we need to be sure that it's an error condition. + */ + public function testNoCorePackagesInstalled(): void { + // Clear the list of packages in the active directory's installed.json. + $listener = function (PreCreateEvent $event): void { + // We should have staged package versions. + /** @var \Drupal\automatic_updates\Updater $updater */ + $updater = $event->getStage(); + $this->assertNotEmpty($updater->getPackageVersions()); + + $active_dir = $this->container->get('package_manager.path_locator') + ->getProjectRoot(); + $installed = $active_dir . '/vendor/composer/installed.json'; + $this->assertFileIsWritable($installed); + file_put_contents($installed, '{"packages": []}'); + }; + $this->assertTargetVersionNotDiscoverable($listener); + } + + /** + * Asserts that an error is raised if the target version of Drupal is unknown. + * + * @param \Closure $listener + * A pre-create event listener to run before all validators. This should put + * the virtual project and/or updater into a state which will cause + * \Drupal\automatic_updates\Validator\VersionPolicyValidator::getTargetVersion() + * to throw an exception because the target version of Drupal core is not + * known. + */ + private function assertTargetVersionNotDiscoverable(\Closure $listener): void { + $this->createTestProject(); + $this->container->get('event_dispatcher') + ->addListener(PreCreateEvent::class, $listener, PHP_INT_MAX); + + $this->expectException(StageException::class); + $this->expectExceptionMessage('The target version of Drupal core could not be determined.'); + $this->container->get('automatic_updates.updater') + ->begin(['drupal' => '9.8.1']); + } + } -- GitLab