Skip to content
Snippets Groups Projects
Commit de577fda authored by Adam G-H's avatar Adam G-H
Browse files

Issue #3246673 by phenaproxima, tedbow: Move PendingUpdatesValidator into Package Manager

parent 40028a69
No related branches found
No related tags found
No related merge requests found
Showing
with 199 additions and 122 deletions
...@@ -59,11 +59,9 @@ services: ...@@ -59,11 +59,9 @@ services:
tags: tags:
- { name: event_subscriber } - { name: event_subscriber }
automatic_updates.pending_updates_validator: automatic_updates.pending_updates_validator:
class: Drupal\automatic_updates\Validator\PendingUpdatesValidator class: Drupal\automatic_updates\Validator\PackageManagerReadinessCheck
arguments: arguments:
- '%app.root%' - '@package_manager.validator.pending_updates'
- '@update.post_update_registry'
- '@string_translation'
tags: tags:
- { name: event_subscriber } - { name: event_subscriber }
automatic_updates.validator.file_system_permissions: automatic_updates.validator.file_system_permissions:
......
...@@ -100,3 +100,11 @@ services: ...@@ -100,3 +100,11 @@ services:
- '@string_translation' - '@string_translation'
tags: tags:
- { name: event_subscriber } - { name: event_subscriber }
package_manager.validator.pending_updates:
class: Drupal\package_manager\EventSubscriber\PendingUpdatesValidator
arguments:
- '%app.root%'
- '@update.post_update_registry'
- '@string_translation'
tags:
- { name: event_subscriber }
<?php <?php
namespace Drupal\automatic_updates\Validator; namespace Drupal\package_manager\EventSubscriber;
use Drupal\automatic_updates\Event\ReadinessCheckEvent;
use Drupal\package_manager\Event\PreCreateEvent; use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\Event\StageEvent; use Drupal\package_manager\Event\StageEvent;
use Drupal\package_manager\ValidationResult; use Drupal\package_manager\ValidationResult;
...@@ -10,12 +9,11 @@ use Drupal\Core\StringTranslation\StringTranslationTrait; ...@@ -10,12 +9,11 @@ use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface; use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Update\UpdateRegistry; use Drupal\Core\Update\UpdateRegistry;
use Drupal\Core\Url; use Drupal\Core\Url;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/** /**
* Validates that there are no pending database updates. * Validates that there are no pending database updates.
*/ */
class PendingUpdatesValidator implements EventSubscriberInterface { class PendingUpdatesValidator implements StageValidatorInterface {
use StringTranslationTrait; use StringTranslationTrait;
...@@ -50,12 +48,9 @@ class PendingUpdatesValidator implements EventSubscriberInterface { ...@@ -50,12 +48,9 @@ class PendingUpdatesValidator implements EventSubscriberInterface {
} }
/** /**
* Validates that there are no pending database updates. * {@inheritdoc}
*
* @param \Drupal\package_manager\Event\StageEvent $event
* The event object.
*/ */
public function checkPendingUpdates(StageEvent $event): void { public function validateStage(StageEvent $event): void {
require_once $this->appRoot . '/core/includes/install.inc'; require_once $this->appRoot . '/core/includes/install.inc';
require_once $this->appRoot . '/core/includes/update.inc'; require_once $this->appRoot . '/core/includes/update.inc';
...@@ -77,8 +72,7 @@ class PendingUpdatesValidator implements EventSubscriberInterface { ...@@ -77,8 +72,7 @@ class PendingUpdatesValidator implements EventSubscriberInterface {
*/ */
public static function getSubscribedEvents() { public static function getSubscribedEvents() {
return [ return [
PreCreateEvent::class => 'checkPendingUpdates', PreCreateEvent::class => 'validateStage',
ReadinessCheckEvent::class => 'checkPendingUpdates',
]; ];
} }
......
...@@ -6,7 +6,9 @@ ...@@ -6,7 +6,9 @@
*/ */
/** /**
* Here is a fake update. * Here is a fake update hook.
*
* The schema version is the maximum possible value for a 32-bit integer.
*/ */
function automatic_updates_update_50000() { function package_manager_update_2147483647() {
} }
...@@ -2,11 +2,9 @@ ...@@ -2,11 +2,9 @@
namespace Drupal\Tests\package_manager\Kernel; namespace Drupal\Tests\package_manager\Kernel;
use Drupal\KernelTests\KernelTestBase;
use Drupal\package_manager\Event\PreCreateEvent; use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\EventSubscriber\ComposerExecutableValidator; use Drupal\package_manager\EventSubscriber\ComposerExecutableValidator;
use Drupal\package_manager\ValidationResult; use Drupal\package_manager\ValidationResult;
use Drupal\Tests\package_manager\Traits\ValidationTestTrait;
use PhpTuf\ComposerStager\Exception\IOException; use PhpTuf\ComposerStager\Exception\IOException;
use PhpTuf\ComposerStager\Infrastructure\Process\ExecutableFinderInterface; use PhpTuf\ComposerStager\Infrastructure\Process\ExecutableFinderInterface;
use Prophecy\Argument; use Prophecy\Argument;
...@@ -16,29 +14,7 @@ use Prophecy\Argument; ...@@ -16,29 +14,7 @@ use Prophecy\Argument;
* *
* @group package_manager * @group package_manager
*/ */
class ComposerExecutableValidatorTest extends KernelTestBase { class ComposerExecutableValidatorTest extends PackageManagerKernelTestBase {
use ValidationTestTrait;
/**
* {@inheritdoc}
*/
protected static $modules = ['package_manager'];
/**
* Runs the validator under test, and asserts its results match expectations.
*
* @param \Drupal\package_manager\ValidationResult[] $expected_results
* The expected validation results.
*/
private function assertResults(array $expected_results): void {
$stage = $this->prophesize('\Drupal\package_manager\Stage');
$event = new PreCreateEvent($stage->reveal());
$this->container->get('package_manager.validator.composer_executable')
->validateStage($event);
$this->assertValidationResultsEqual($expected_results, $event->getResults());
}
/** /**
* Tests that an error is raised if the Composer executable isn't found. * Tests that an error is raised if the Composer executable isn't found.
...@@ -58,7 +34,7 @@ class ComposerExecutableValidatorTest extends KernelTestBase { ...@@ -58,7 +34,7 @@ class ComposerExecutableValidatorTest extends KernelTestBase {
$error = ValidationResult::createError([ $error = ValidationResult::createError([
$exception->getMessage(), $exception->getMessage(),
]); ]);
$this->assertResults([$error]); $this->assertResults([$error], PreCreateEvent::class);
} }
/** /**
...@@ -155,7 +131,7 @@ class ComposerExecutableValidatorTest extends KernelTestBase { ...@@ -155,7 +131,7 @@ class ComposerExecutableValidatorTest extends KernelTestBase {
// If the validator can't find a recognized, supported version of Composer, // If the validator can't find a recognized, supported version of Composer,
// it should produce errors. // it should produce errors.
$this->assertResults($expected_results); $this->assertResults($expected_results, PreCreateEvent::class);
} }
} }
...@@ -2,26 +2,17 @@ ...@@ -2,26 +2,17 @@
namespace Drupal\Tests\package_manager\Kernel; namespace Drupal\Tests\package_manager\Kernel;
use Drupal\KernelTests\KernelTestBase;
use Drupal\package_manager\Event\PreCreateEvent; use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\EventSubscriber\DiskSpaceValidator; use Drupal\package_manager\EventSubscriber\DiskSpaceValidator;
use Drupal\package_manager\ValidationResult; use Drupal\package_manager\ValidationResult;
use Drupal\Component\Utility\Bytes; use Drupal\Component\Utility\Bytes;
use Drupal\Tests\package_manager\Traits\ValidationTestTrait;
/** /**
* @covers \Drupal\package_manager\EventSubscriber\DiskSpaceValidator * @covers \Drupal\package_manager\EventSubscriber\DiskSpaceValidator
* *
* @group package_manager * @group package_manager
*/ */
class DiskSpaceValidatorTest extends KernelTestBase { class DiskSpaceValidatorTest extends PackageManagerKernelTestBase {
use ValidationTestTrait;
/**
* {@inheritdoc}
*/
protected static $modules = ['package_manager'];
/** /**
* Data provider for ::testDiskSpaceValidation(). * Data provider for ::testDiskSpaceValidation().
...@@ -201,11 +192,7 @@ class DiskSpaceValidatorTest extends KernelTestBase { ...@@ -201,11 +192,7 @@ class DiskSpaceValidatorTest extends KernelTestBase {
$validator->sharedDisk = $shared_disk; $validator->sharedDisk = $shared_disk;
$validator->freeSpace = array_map([Bytes::class, 'toNumber'], $free_space); $validator->freeSpace = array_map([Bytes::class, 'toNumber'], $free_space);
$stage = $this->prophesize('\Drupal\package_manager\Stage'); $this->assertResults($expected_results, PreCreateEvent::class);
$event = new PreCreateEvent($stage->reveal());
$validator->validateStage($event);
$this->assertValidationResultsEqual($expected_results, $event->getResults());
} }
} }
<?php
namespace Drupal\Tests\package_manager\Kernel;
use Drupal\KernelTests\KernelTestBase;
use Drupal\package_manager\Event\StageEvent;
use Drupal\package_manager\Stage;
use Drupal\package_manager\StageException;
use Drupal\Tests\package_manager\Traits\ValidationTestTrait;
/**
* Base class for kernel tests of Package Manager's functionality.
*/
abstract class PackageManagerKernelTestBase extends KernelTestBase {
use ValidationTestTrait;
/**
* {@inheritdoc}
*/
protected static $modules = [
'package_manager',
'package_manager_bypass',
];
/**
* Asserts validation results are returned from a stage life cycle event.
*
* @param \Drupal\package_manager\ValidationResult[] $expected_results
* The expected validation results.
* @param string $event_class
* The class of the event which should return the results.
*/
protected function assertResults(array $expected_results, string $event_class): void {
$stage = new TestStage(
$this->container->get('package_manager.path_locator'),
$this->container->get('package_manager.beginner'),
$this->container->get('package_manager.stager'),
$this->container->get('package_manager.committer'),
$this->container->get('package_manager.cleaner'),
$this->container->get('event_dispatcher'),
);
try {
$stage->create();
$stage->require(['drupal/core:9.8.1']);
$stage->apply();
$stage->destroy();
}
catch (StageException $e) {
$this->assertValidationResultsEqual($expected_results, $e->getResults());
// TestStage::dispatch() attaches the event object to the exception so
// that we can analyze it.
$this->assertInstanceOf($event_class, $e->event);
}
// If no errors are raised, we won't have asserted anything and the test
// will be marked as risky. To prevent that, assert an eternal truth.
$this->assertTrue(TRUE);
}
}
/**
* Defines a stage specifically for testing purposes.
*/
class TestStage extends Stage {
/**
* {@inheritdoc}
*/
protected function dispatch(StageEvent $event): void {
try {
parent::dispatch($event);
}
catch (StageException $e) {
// Attach the event object to the exception so that test code can verify
// that the exception was thrown when a specific event was dispatched.
$e->event = $event;
throw $e;
}
}
}
<?php
namespace Drupal\Tests\package_manager\Kernel;
use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\ValidationResult;
/**
* @covers \Drupal\package_manager\EventSubscriber\PendingUpdatesValidator
*
* @group package_manager
*/
class PendingUpdatesValidatorTest extends PackageManagerKernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['system'];
/**
* Registers all of the System module's post-update functions.
*
* Since kernel tests don't normally install modules and register their
* updates, this method makes sure that the validator is tested from a clean,
* fully up-to-date state.
*/
private function registerPostUpdateFunctions(): void {
$updates = $this->container->get('update.post_update_registry')
->getPendingUpdateFunctions();
$this->container->get('keyvalue')
->get('post_update')
->set('existing_updates', $updates);
}
/**
* Tests that no error is raised if there are no pending updates.
*/
public function testNoPendingUpdates(): void {
$this->registerPostUpdateFunctions();
$this->assertResults([], PreCreateEvent::class);
}
/**
* Tests that an error is raised if there are pending schema updates.
*
* @depends testNoPendingUpdates
*/
public function testPendingUpdateHook(): void {
// Register the System module's post-update functions, so that any detected
// pending updates are guaranteed to be schema updates.
$this->registerPostUpdateFunctions();
// Set the installed schema version of Package Manager to its default value
// and import an empty update hook which is numbered much higher than will
// ever exist in the real world.
$this->container->get('keyvalue')
->get('system.schema')
->set('package_manager', \Drupal::CORE_MINIMUM_SCHEMA_VERSION);
require_once __DIR__ . '/../../fixtures/db_update.php';
$result = ValidationResult::createError([
'Some modules have database schema updates to install. You should run the <a href="/update.php">database update script</a> immediately.',
]);
$this->assertResults([$result], PreCreateEvent::class);
}
/**
* Tests that an error is raised if there are pending post-updates.
*/
public function testPendingPostUpdate(): void {
// The System module's post-update functions have not been registered, so
// the update registry will think they're pending.
$result = ValidationResult::createError([
'Some modules have database schema updates to install. You should run the <a href="/update.php">database update script</a> immediately.',
]);
$this->assertResults([$result], PreCreateEvent::class);
}
}
<?php
/**
* @file
* Contains a fake post-update function for testing.
*/
/**
* Here is a fake post-update.
*/
function automatic_updates_post_update_test() {
}
...@@ -16,6 +16,7 @@ use Prophecy\Argument; ...@@ -16,6 +16,7 @@ use Prophecy\Argument;
* *
* @see \Drupal\Tests\package_manager\Kernel\ComposerExecutableValidatorTest * @see \Drupal\Tests\package_manager\Kernel\ComposerExecutableValidatorTest
* @see \Drupal\Tests\package_manager\Kernel\DiskSpaceValidatorTest * @see \Drupal\Tests\package_manager\Kernel\DiskSpaceValidatorTest
* @see \Drupal\Tests\package_manager\Kernel\PendingUpdatesValidatorTest
*/ */
class PackageManagerReadinessChecksTest extends AutomaticUpdatesKernelTestBase { class PackageManagerReadinessChecksTest extends AutomaticUpdatesKernelTestBase {
...@@ -37,6 +38,7 @@ class PackageManagerReadinessChecksTest extends AutomaticUpdatesKernelTestBase { ...@@ -37,6 +38,7 @@ class PackageManagerReadinessChecksTest extends AutomaticUpdatesKernelTestBase {
return [ return [
['package_manager.validator.composer_executable'], ['package_manager.validator.composer_executable'],
['package_manager.validator.disk_space'], ['package_manager.validator.disk_space'],
['package_manager.validator.pending_updates'],
]; ];
} }
......
<?php
namespace Drupal\Tests\automatic_updates\Kernel\ReadinessValidation;
use Drupal\package_manager\ValidationResult;
use Drupal\Tests\automatic_updates\Kernel\AutomaticUpdatesKernelTestBase;
/**
* @covers \Drupal\automatic_updates\Validator\PendingUpdatesValidator
*
* @group automatic_updates
*/
class PendingUpdatesValidatorTest extends AutomaticUpdatesKernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'automatic_updates',
'package_manager',
];
/**
* Tests that no error is raised if there are no pending updates.
*/
public function testNoPendingUpdates(): void {
$this->assertCheckerResultsFromManager([], TRUE);
}
/**
* Tests that an error is raised if there are pending schema updates.
*/
public function testPendingUpdateHook(): void {
require __DIR__ . '/../../../fixtures/db_update.php';
$this->container->get('keyvalue')
->get('system.schema')
->set('automatic_updates', \Drupal::CORE_MINIMUM_SCHEMA_VERSION);
$result = ValidationResult::createError(['Some modules have database schema updates to install. You should run the <a href="/update.php">database update script</a> immediately.']);
$this->assertCheckerResultsFromManager([$result], TRUE);
}
/**
* Tests that an error is raised if there are pending post-updates.
*/
public function testPendingPostUpdate(): void {
require __DIR__ . '/../../../fixtures/post_update.php';
$result = ValidationResult::createError(['Some modules have database schema updates to install. You should run the <a href="/update.php">database update script</a> immediately.']);
$this->assertCheckerResultsFromManager([$result], TRUE);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment