Newer
Older
<?php
namespace Drupal\Tests\automatic_updates\Kernel\ReadinessValidation;
use Drupal\automatic_updates\CronUpdater;
use Drupal\automatic_updates\Event\ReadinessCheckEvent;
use Drupal\automatic_updates\Updater;
use Drupal\automatic_updates_test\ReadinessChecker\TestChecker1;
use Drupal\automatic_updates_test2\ReadinessChecker\TestChecker2;
use Drupal\system\SystemManager;

Kunal Sachdev
committed
use Drupal\Tests\automatic_updates\Kernel\AutomaticUpdatesKernelTestBase;
/**
* @coversDefaultClass \Drupal\automatic_updates\Validation\ReadinessValidationManager
*
* @group automatic_updates
*/

Kunal Sachdev
committed
class ReadinessValidationManagerTest extends AutomaticUpdatesKernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'automatic_updates_test',
'package_manager',

Adam G-H
committed
'package_manager_bypass',
'user',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('user');
$this->installSchema('user', ['users_data']);
$this->createTestValidationResults();
}
/**
* @covers ::getResults
*/
public function testGetResults(): void {

Kunal Sachdev
committed
$this->enableModules(['automatic_updates', 'automatic_updates_test2']);
$this->assertCheckerResultsFromManager([], TRUE);
$expected_results = [
array_pop($this->testResults['checker_1']),
array_pop($this->testResults['checker_2']),
];
TestChecker1::setTestResult($expected_results[0], ReadinessCheckEvent::class);
TestChecker2::setTestResult($expected_results[1], ReadinessCheckEvent::class);
$expected_results_all = array_merge($expected_results[0], $expected_results[1]);
$this->assertCheckerResultsFromManager($expected_results_all, TRUE);
// Define a constant flag that will cause the readiness checker
// service priority to be altered.
define('PACKAGE_MANAGER_TEST_VALIDATOR_PRIORITY', 1);
// Rebuild the container to trigger the service to be altered.
$kernel = $this->container->get('kernel');
$this->container = $kernel->rebuildContainer();
// The stored results should be returned, even though the validators' order
// has been changed and the container has been rebuilt.
$this->assertValidationResultsEqual($expected_results_all, $this->getResultsFromManager());
// Confirm that after calling run() the expected results order has changed.
$expected_results_all_reversed = array_reverse($expected_results_all);
$this->assertCheckerResultsFromManager($expected_results_all_reversed, TRUE);
$expected_results = [
$this->testResults['checker_1']['2 errors 2 warnings'],
$this->testResults['checker_2']['2 errors 2 warnings'],
];
TestChecker1::setTestResult($expected_results[0], ReadinessCheckEvent::class);
TestChecker2::setTestResult($expected_results[1], ReadinessCheckEvent::class);
$expected_results_all = array_merge($expected_results[1], $expected_results[0]);
$this->assertCheckerResultsFromManager($expected_results_all, TRUE);
// Confirm that filtering by severity works.
$warnings_only_results = [
$expected_results[1]['2:warnings'],
$expected_results[0]['1:warnings'],
];
$this->assertCheckerResultsFromManager($warnings_only_results, FALSE, SystemManager::REQUIREMENT_WARNING);
$errors_only_results = [
$expected_results[1]['2:errors'],
$expected_results[0]['1:errors'],
];
$this->assertCheckerResultsFromManager($errors_only_results, FALSE, SystemManager::REQUIREMENT_ERROR);
}
/**
* Tests that the manager is run after modules are installed.
*/
public function testRunOnInstall(): void {
$expected_results = [array_pop($this->testResults['checker_1'])];
TestChecker1::setTestResult($expected_results[0], ReadinessCheckEvent::class);
// Confirm that messages from an existing module are displayed when
// 'automatic_updates' is installed.
$this->container->get('module_installer')->install(['automatic_updates']);
$this->assertCheckerResultsFromManager($expected_results[0]);
// Confirm that the checkers are run when a module that provides a readiness
// checker is installed.
$expected_results = [
array_pop($this->testResults['checker_1']),
array_pop($this->testResults['checker_2']),
];
TestChecker1::setTestResult($expected_results[0], ReadinessCheckEvent::class);
TestChecker2::setTestResult($expected_results[1], ReadinessCheckEvent::class);
$this->container->get('module_installer')->install(['automatic_updates_test2']);
$expected_results_all = array_merge($expected_results[0], $expected_results[1]);
$this->assertCheckerResultsFromManager($expected_results_all);
// Confirm that the checkers are run when a module that does not provide a
// readiness checker is installed.
$expected_results = [
array_pop($this->testResults['checker_1']),
array_pop($this->testResults['checker_2']),
];
TestChecker1::setTestResult($expected_results[0], ReadinessCheckEvent::class);
TestChecker2::setTestResult($expected_results[1], ReadinessCheckEvent::class);
$expected_results_all = array_merge($expected_results[0], $expected_results[1]);
$this->container->get('module_installer')->install(['help']);
$this->assertCheckerResultsFromManager($expected_results_all);
}
/**
* Tests that the manager is run after modules are uninstalled.
*/
public function testRunOnUninstall(): void {
$expected_results = [
array_pop($this->testResults['checker_1']),
array_pop($this->testResults['checker_2']),
];
TestChecker1::setTestResult($expected_results[0], ReadinessCheckEvent::class);
TestChecker2::setTestResult($expected_results[1], ReadinessCheckEvent::class);
// Confirm that messages from existing modules are displayed when
// 'automatic_updates' is installed.
$this->container->get('module_installer')->install(['automatic_updates', 'automatic_updates_test2', 'help']);
$expected_results_all = array_merge($expected_results[0], $expected_results[1]);
$this->assertCheckerResultsFromManager($expected_results_all);
// Confirm that the checkers are run when a module that provides a readiness
// checker is uninstalled.
$expected_results = [
array_pop($this->testResults['checker_1']),
];
TestChecker1::setTestResult($expected_results[0], ReadinessCheckEvent::class);
TestChecker2::setTestResult(array_pop($this->testResults['checker_2']), ReadinessCheckEvent::class);
$this->container->get('module_installer')->uninstall(['automatic_updates_test2']);
$this->assertCheckerResultsFromManager($expected_results[0]);
// Confirm that the checkers are run when a module that does not provide a
// readiness checker is uninstalled.
$expected_results = [
array_pop($this->testResults['checker_1']),
];
TestChecker1::setTestResult($expected_results[0], ReadinessCheckEvent::class);
$this->container->get('module_installer')->uninstall(['help']);
$this->assertCheckerResultsFromManager($expected_results[0]);
}
/**
* @covers ::runIfNoStoredResults
* @covers ::clearStoredResults
*/
public function testRunIfNeeded(): void {
$expected_results = array_pop($this->testResults['checker_1']);
TestChecker1::setTestResult($expected_results, ReadinessCheckEvent::class);
$this->container->get('module_installer')->install(['automatic_updates', 'automatic_updates_test2']);
$this->assertCheckerResultsFromManager($expected_results);
$unexpected_results = array_pop($this->testResults['checker_1']);
TestChecker1::setTestResult($unexpected_results, ReadinessCheckEvent::class);
$manager = $this->container->get('automatic_updates.readiness_validation_manager');
// Confirm that the new results will not be returned because the checkers
// will not be run.
$manager->runIfNoStoredResults();
$this->assertCheckerResultsFromManager($expected_results);
// Confirm that the new results will be returned because the checkers will
// be run if the stored results are deleted.
$manager->clearStoredResults();
$expected_results = $unexpected_results;
$manager->runIfNoStoredResults();
$this->assertCheckerResultsFromManager($expected_results);
// Confirm that the results are the same after rebuilding the container.
$unexpected_results = array_pop($this->testResults['checker_1']);
TestChecker1::setTestResult($unexpected_results, ReadinessCheckEvent::class);
/** @var \Drupal\Core\DrupalKernel $kernel */
$kernel = $this->container->get('kernel');
$this->container = $kernel->rebuildContainer();
$this->assertCheckerResultsFromManager($expected_results);
}
/**
* Tests the Automatic Updates cron setting changes which stage class is used.
*/
public function testCronSetting(): void {
$this->enableModules(['automatic_updates']);
$stage_class = NULL;
$listener = function (ReadinessCheckEvent $event) use (&$stage_class): void {
$stage_class = get_class($event->getStage());
};
$event_dispatcher = $this->container->get('event_dispatcher');
$event_dispatcher->addListener(ReadinessCheckEvent::class, $listener);
$this->container->get('automatic_updates.readiness_validation_manager')->run();
// By default, updates will be enabled on cron.
$this->assertSame(CronUpdater::class, $stage_class);
$this->config('automatic_updates.settings')
->set('cron', CronUpdater::DISABLED)
->save();
$this->container->get('automatic_updates.readiness_validation_manager')->run();
$this->assertSame(Updater::class, $stage_class);
}

Adam G-H
committed
/**
* Tests that stored validation results are deleted after an update.
*/
public function testStoredResultsDeletedPostApply(): void {
$this->container->get('module_installer')
->install(['automatic_updates']);
// Ensure there's a simulated core release to update to.

Kunal Sachdev
committed
$this->setReleaseMetadata(__DIR__ . '/../../../fixtures/release-history/drupal.9.8.2.xml');

Adam G-H
committed
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
// The readiness checker should raise a warning, so that the update is not
// blocked or aborted.
$results = $this->testResults['checker_1']['1 warning'];
TestChecker1::setTestResult($results, ReadinessCheckEvent::class);
// Ensure that the validation manager collects the warning.
/** @var \Drupal\automatic_updates\Validation\ReadinessValidationManager $manager */
$manager = $this->container->get('automatic_updates.readiness_validation_manager')
->run();
TestChecker1::setTestResult(NULL, ReadinessCheckEvent::class);
// Even though the checker no longer returns any results, the previous
// results should be stored.
$this->assertValidationResultsEqual($results, $manager->getResults());
// Don't validate staged projects because actual staging operations are
// bypassed by package_manager_bypass, which will make this validator
// complain that there is no actual Composer data for it to inspect.
$validator = $this->container->get('automatic_updates.staged_projects_validator');
$this->container->get('event_dispatcher')->removeSubscriber($validator);
/** @var \Drupal\automatic_updates\Updater $updater */
$updater = $this->container->get('automatic_updates.updater');
$updater->begin(['drupal' => '9.8.1']);
$updater->stage();
$updater->apply();
$updater->destroy();
// The readiness validation manager shouldn't have any stored results.
$this->assertEmpty($manager->getResults());
}