From 4d23ebdeddbd9d2d69f62c5dc20054db49034bb1 Mon Sep 17 00:00:00 2001 From: phenaproxima <phenaproxima@205645.no-reply.drupal.org> Date: Fri, 30 Sep 2022 18:26:43 +0000 Subject: [PATCH] Issue #3312420 by phenaproxima, TravisCarden: Refactor StagedDBUpdateValidatorTest --- .../StagedDBUpdateValidatorTest.php | 166 --------------- .../Kernel/StagedDBUpdateValidatorTest.php | 144 +++++++++++++ .../StagedDatabaseUpdateValidatorTest.php | 201 ++++++++---------- 3 files changed, 231 insertions(+), 280 deletions(-) delete mode 100644 package_manager/tests/src/Kernel/ReadinessValidation/StagedDBUpdateValidatorTest.php create mode 100644 package_manager/tests/src/Kernel/StagedDBUpdateValidatorTest.php diff --git a/package_manager/tests/src/Kernel/ReadinessValidation/StagedDBUpdateValidatorTest.php b/package_manager/tests/src/Kernel/ReadinessValidation/StagedDBUpdateValidatorTest.php deleted file mode 100644 index 77a67f54ae..0000000000 --- a/package_manager/tests/src/Kernel/ReadinessValidation/StagedDBUpdateValidatorTest.php +++ /dev/null @@ -1,166 +0,0 @@ -<?php - -namespace Drupal\Tests\package_manager\Kernel\ReadinessValidation; - -use Drupal\package_manager\ValidationResult; -use Drupal\Tests\package_manager\Kernel\PackageManagerKernelTestBase; - -/** - * @covers \Drupal\package_manager\Validator\StagedDBUpdateValidator - * - * @group package_manager - */ -class StagedDBUpdateValidatorTest extends PackageManagerKernelTestBase { - - /** - * The suffixes of the files that can contain database updates. - * - * @var string[] - */ - private const SUFFIXES = ['install', 'post_update.php']; - - /** - * {@inheritdoc} - */ - protected function createVirtualProject(?string $source_dir = NULL): void { - parent::createVirtualProject($source_dir); - - $drupal_root = $this->getDrupalRoot(); - $virtual_active_dir = $this->container->get('package_manager.path_locator') - ->getProjectRoot(); - - // Copy the .install and .post_update.php files from all extensions used in - // this test class, in the *actual* Drupal code base that is running this - // test, into the virtual project (i.e., the active directory). - $module_list = $this->container->get('extension.list.module'); - $extensions = []; - $extensions['system'] = $module_list->get('system'); - $extensions['views'] = $module_list->get('views'); - $extensions['package_manager_bypass'] = $module_list->get('package_manager_bypass'); - $theme_list = $this->container->get('extension.list.theme'); - // Theme with updates. - $extensions['olivero'] = $theme_list->get('olivero'); - // Theme without updates. - $extensions['stark'] = $theme_list->get('stark'); - foreach ($extensions as $name => $extension) { - $path = $extension->getPath(); - @mkdir("$virtual_active_dir/$path", 0777, TRUE); - - foreach (static::SUFFIXES as $suffix) { - if ($name === 'olivero') { - @touch("$virtual_active_dir/$path/$name.$suffix"); - continue; - } - // If the source file doesn't exist, silence the warning it raises. - @copy("$drupal_root/$path/$name.$suffix", "$virtual_active_dir/$path/$name.$suffix"); - } - } - } - - /** - * Data provider for testFileChanged(). - * - * @return mixed[] - * The test cases. - */ - public function providerFileChanged(): array { - $scenarios = []; - foreach (static::SUFFIXES as $suffix) { - $scenarios["$suffix kept"] = [$suffix, FALSE]; - $scenarios["$suffix deleted"] = [$suffix, TRUE]; - } - return $scenarios; - } - - /** - * Tests that an error is raised if install or post-update files are changed. - * - * @param string $suffix - * The suffix of the file to change. Can be either 'install' or - * 'post_update.php'. - * @param bool $delete - * Whether or not to delete the file. - * - * @dataProvider providerFileChanged - */ - public function testFileChanged(string $suffix, bool $delete): void { - $stage = $this->createStage(); - $stage->create(); - $dir = $stage->getStageDirectory(); - $this->container->get('theme_installer')->install(['olivero']); - $theme = $this->container->get('theme_handler') - ->getTheme('olivero'); - $module_file = "$dir/core/modules/system/system.$suffix"; - $theme_file = "$dir/{$theme->getPath()}/{$theme->getName()}.$suffix"; - if ($delete) { - unlink($module_file); - unlink($theme_file); - } - else { - file_put_contents($module_file, $this->randomString()); - file_put_contents($theme_file, $this->randomString()); - } - $error = ValidationResult::createWarning(['System', 'Olivero'], t('Possible database updates have been detected in the following extensions.')); - $this->assertStatusCheckResults([$error], $stage); - - } - - /** - * Tests that no errors are raised if staged files have no DB updates. - */ - public function testNoUpdates(): void { - // Since we're testing with a modified version of 'views' and - // 'olivero', these should not be installed. - $this->assertFalse($this->container->get('module_handler')->moduleExists('views')); - $this->assertFalse($this->container->get('theme_handler')->themeExists('olivero')); - - // Create bogus staged versions of Views' and - // Package Manager Theme with Updates .install and .post_update.php - // files. Since these extensions are not installed, the changes should not - // raise any validation errors. - $stage = $this->createStage(); - $stage->create(); - $dir = $stage->getStageDirectory(); - $module_list = $this->container->get('extension.list.module')->getList(); - $theme_list = $this->container->get('extension.list.theme')->getList(); - $module_dir = $dir . '/' . $module_list['views']->getPath(); - $theme_dir = $dir . '/' . $theme_list['olivero']->getPath(); - foreach (static::SUFFIXES as $suffix) { - file_put_contents("$module_dir/views.$suffix", $this->randomString()); - file_put_contents("$theme_dir/olivero.$suffix", $this->randomString()); - } - // There should not have been any errors. - $this->assertStatusCheckResults([], $stage); - } - - /** - * Tests that an error is raised if install or post-update files are added. - */ - public function testUpdatesAddedInStage(): void { - $module = $this->container->get('module_handler') - ->getModule('package_manager_bypass'); - $theme_installer = $this->container->get('theme_installer'); - $theme_installer->install(['stark']); - $theme = $this->container->get('theme_handler') - ->getTheme('stark'); - - $stage = $this->createStage(); - $stage->create(); - $dir = $stage->getStageDirectory(); - foreach (static::SUFFIXES as $suffix) { - $module_file = sprintf('%s/%s/%s.%s', $dir, $module->getPath(), $module->getName(), $suffix); - $theme_file = sprintf('%s/%s/%s.%s', $dir, $theme->getPath(), $theme->getName(), $suffix); - // The files we're creating shouldn't already exist in the staging area - // unless it's a file we actually ship, which is a scenario covered by - // ::testFileChanged(). - $this->assertFileDoesNotExist($module_file); - $this->assertFileDoesNotExist($theme_file); - file_put_contents($module_file, $this->randomString()); - file_put_contents($theme_file, $this->randomString()); - } - $error = ValidationResult::createWarning(['Package Manager Bypass', 'Stark'], t('Possible database updates have been detected in the following extensions.')); - - $this->assertStatusCheckResults([$error], $stage); - } - -} diff --git a/package_manager/tests/src/Kernel/StagedDBUpdateValidatorTest.php b/package_manager/tests/src/Kernel/StagedDBUpdateValidatorTest.php new file mode 100644 index 0000000000..eba232a27e --- /dev/null +++ b/package_manager/tests/src/Kernel/StagedDBUpdateValidatorTest.php @@ -0,0 +1,144 @@ +<?php + +namespace Drupal\Tests\package_manager\Kernel; + +use Drupal\package_manager\ValidationResult; + +/** + * @covers \Drupal\package_manager\Validator\StagedDBUpdateValidator + * + * @group package_manager + */ +class StagedDBUpdateValidatorTest extends PackageManagerKernelTestBase { + + /** + * The extensions that will be used in this test. + * + * System and Stark are installed, so they are used to test what happens when + * database updates are detected in installed extensions. Views and Olivero + * are not installed by this test, so they are used to test what happens when + * uninstalled extensions have database updates. + * + * @var string[] + * + * @see ::setUp() + */ + private $extensions = [ + 'system' => 'core/modules/system', + 'views' => 'core/modules/views', + 'stark' => 'core/themes/stark', + 'olivero' => 'core/themes/olivero', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + + $this->container->get('theme_installer')->install(['stark']); + $this->assertFalse($this->container->get('module_handler')->moduleExists('views')); + $this->assertFalse($this->container->get('theme_handler')->themeExists('olivero')); + + // Ensure that all the extensions we're testing with have database update + // files in the active directory. + $active_dir = $this->container->get('package_manager.path_locator') + ->getProjectRoot(); + + foreach ($this->extensions as $extension_name => $extension_path) { + $extension_path = $active_dir . '/' . $extension_path; + mkdir($extension_path, 0777, TRUE); + + foreach ($this->providerSuffixes() as [$suffix]) { + touch("$extension_path/$extension_name.$suffix"); + } + } + } + + /** + * Data provider for several test methods. + * + * @return \string[][] + * The test cases. + */ + public function providerSuffixes(): array { + return [ + 'hook_update_N' => ['install'], + 'hook_post_update_NAME' => ['post_update.php'], + ]; + } + + /** + * Tests that no errors are raised if the stage has no DB updates. + */ + public function testNoUpdates(): void { + $stage = $this->createStage(); + $stage->create(); + $this->assertStatusCheckResults([], $stage); + } + + /** + * Tests that a warning is raised if DB update files are removed in the stage. + * + * @param string $suffix + * The update file suffix to test (one of `install` or `post_update.php`). + * + * @dataProvider providerSuffixes + */ + public function testFileDeleted(string $suffix): void { + $stage = $this->createStage(); + $stage->create(); + + $stage_dir = $stage->getStageDirectory(); + foreach ($this->extensions as $name => $path) { + unlink("$stage_dir/$path/$name.$suffix"); + } + + $result = ValidationResult::createWarning(['System', 'Stark'], t('Possible database updates have been detected in the following extensions.')); + $this->assertStatusCheckResults([$result], $stage); + } + + /** + * Tests that a warning is raised if DB update files are changed in the stage. + * + * @param string $suffix + * The update file suffix to test (one of `install` or `post_update.php`). + * + * @dataProvider providerSuffixes + */ + public function testFileChanged(string $suffix): void { + $stage = $this->createStage(); + $stage->create(); + + $stage_dir = $stage->getStageDirectory(); + foreach ($this->extensions as $name => $path) { + file_put_contents("$stage_dir/$path/$name.$suffix", $this->randomString()); + } + + $result = ValidationResult::createWarning(['System', 'Stark'], t('Possible database updates have been detected in the following extensions.')); + $this->assertStatusCheckResults([$result], $stage); + } + + /** + * Tests that a warning is raised if DB update files are added in the stage. + * + * @param string $suffix + * The update file suffix to test (one of `install` or `post_update.php`). + * + * @dataProvider providerSuffixes + */ + public function testFileAdded(string $suffix): void { + $stage = $this->createStage(); + $stage->create(); + + $active_dir = $this->container->get('package_manager.path_locator') + ->getProjectRoot(); + foreach ($this->extensions as $name => $path) { + unlink("$active_dir/$path/$name.$suffix"); + } + + $result = ValidationResult::createWarning(['System', 'Stark'], t('Possible database updates have been detected in the following extensions.')); + $this->assertStatusCheckResults([$result], $stage); + } + +} diff --git a/tests/src/Kernel/ReadinessValidation/StagedDatabaseUpdateValidatorTest.php b/tests/src/Kernel/ReadinessValidation/StagedDatabaseUpdateValidatorTest.php index 598be93e95..3e0879f04c 100644 --- a/tests/src/Kernel/ReadinessValidation/StagedDatabaseUpdateValidatorTest.php +++ b/tests/src/Kernel/ReadinessValidation/StagedDatabaseUpdateValidatorTest.php @@ -20,14 +20,26 @@ class StagedDatabaseUpdateValidatorTest extends AutomaticUpdatesKernelTestBase { protected static $modules = ['automatic_updates']; /** - * The suffixes of the files that can contain database updates. + * The extensions that will be used in this test. + * + * System and Stark are installed, so they are used to test what happens when + * database updates are detected in installed extensions. Views and Olivero + * are not installed by this test, so they are used to test what happens when + * uninstalled extensions have database updates. * * @var string[] + * + * @see ::setUp() */ - private const SUFFIXES = ['install', 'post_update.php']; + private $extensions = [ + 'system' => 'core/modules/system', + 'views' => 'core/modules/views', + 'stark' => 'core/themes/stark', + 'olivero' => 'core/themes/olivero', + ]; /** - * The test logger channel. + * The test logger to collected messages logged by the cron updater. * * @var \Psr\Log\Test\TestLogger */ @@ -39,158 +51,119 @@ class StagedDatabaseUpdateValidatorTest extends AutomaticUpdatesKernelTestBase { protected function setUp(): void { parent::setUp(); + $this->container->get('theme_installer')->install(['stark']); + $this->assertFalse($this->container->get('module_handler')->moduleExists('views')); + $this->assertFalse($this->container->get('theme_handler')->themeExists('olivero')); + + // Ensure that all the extensions we're testing with have database update + // files in the active directory. + $active_dir = $this->container->get('package_manager.path_locator') + ->getProjectRoot(); + + foreach ($this->extensions as $extension_name => $extension_path) { + $extension_path = $active_dir . '/' . $extension_path; + mkdir($extension_path, 0777, TRUE); + + foreach ($this->providerSuffixes() as [$suffix]) { + touch("$extension_path/$extension_name.$suffix"); + } + } + $this->logger = new TestLogger(); - $this->container->get('logger.factory') - ->get('automatic_updates') + $this->container->get('logger.channel.automatic_updates') ->addLogger($this->logger); } /** - * {@inheritdoc} + * Data provider for several test methods. + * + * @return \string[][] + * The test cases. */ - protected function createVirtualProject(?string $source_dir = NULL): void { - parent::createVirtualProject($source_dir); - - $drupal_root = $this->getDrupalRoot(); - $virtual_active_dir = $this->container->get('package_manager.path_locator') - ->getProjectRoot(); - - // Copy the .install and .post_update.php files from all extensions used in - // this test class, in the *actual* Drupal code base that is running this - // test, into the virtual project (i.e., the active directory). - $module_list = $this->container->get('extension.list.module'); - $extensions = []; - $extensions['system'] = $module_list->get('system'); - $extensions['views'] = $module_list->get('views'); - $extensions['package_manager_bypass'] = $module_list->get('package_manager_bypass'); - $theme_list = $this->container->get('extension.list.theme'); - $extensions['automatic_updates_theme'] = $theme_list->get('automatic_updates_theme'); - $extensions['automatic_updates_theme_with_updates'] = $theme_list->get('automatic_updates_theme_with_updates'); - foreach ($extensions as $name => $extension) { - $path = $extension->getPath(); - @mkdir("$virtual_active_dir/$path", 0777, TRUE); - - foreach (static::SUFFIXES as $suffix) { - // If the source file doesn't exist, silence the warning it raises. - @copy("$drupal_root/$path/$name.$suffix", "$virtual_active_dir/$path/$name.$suffix"); - } - } + public function providerSuffixes(): array { + return [ + 'hook_update_N' => ['install'], + 'hook_post_update_NAME' => ['post_update.php'], + ]; } /** - * Tests that no errors are raised if staged files have no DB updates. + * Tests that no errors are raised if the stage has no DB updates. */ public function testNoUpdates(): void { - // Since we're testing with a modified version of 'views' and - // 'automatic_updates_theme_with_updates', these should not be installed. - $this->assertFalse($this->container->get('module_handler')->moduleExists('views')); - $this->assertFalse($this->container->get('theme_handler')->themeExists('automatic_updates_theme_with_updates')); - - $listener = function (PreApplyEvent $event): void { - // Create bogus staged versions of Views' and - // Automatic Updates Theme with Updates .install and .post_update.php - // files. Since these extensions are not installed, the changes should not - // raise any validation errors. - $dir = $event->getStage()->getStageDirectory(); - $module_list = $this->container->get('extension.list.module')->getList(); - $theme_list = $this->container->get('extension.list.theme')->getList(); - $module_dir = $dir . '/' . $module_list['views']->getPath(); - $theme_dir = $dir . '/' . $theme_list['automatic_updates_theme_with_updates']->getPath(); - foreach (static::SUFFIXES as $suffix) { - file_put_contents("$module_dir/views.$suffix", $this->randomString()); - file_put_contents("$theme_dir/automatic_updates_theme_with_updates.$suffix", $this->randomString()); - } - }; - $this->container->get('event_dispatcher') - ->addListener(PreApplyEvent::class, $listener, PHP_INT_MAX); - $this->container->get('cron')->run(); - // There should not have been any errors. $this->assertFalse($this->logger->hasRecords(RfcLogLevel::ERROR)); } /** - * Data provider for testFileChanged(). + * Tests that an error is raised if DB update files are removed in the stage. * - * @return mixed[] - * The test cases. + * @param string $suffix + * The update file suffix to test (one of `install` or `post_update.php`). + * + * @dataProvider providerSuffixes */ - public function providerFileChanged(): array { - $scenarios = []; - foreach (static::SUFFIXES as $suffix) { - $scenarios["$suffix kept"] = [$suffix, FALSE]; - $scenarios["$suffix deleted"] = [$suffix, TRUE]; - } - return $scenarios; + public function testFileDeleted(string $suffix): void { + $listener = function (PreApplyEvent $event) use ($suffix): void { + $stage_dir = $event->getStage()->getStageDirectory(); + foreach ($this->extensions as $name => $path) { + unlink("$stage_dir/$path/$name.$suffix"); + } + }; + $this->container->get('event_dispatcher') + ->addListener(PreApplyEvent::class, $listener, PHP_INT_MAX); + + $this->container->get('cron')->run(); + $expected_message = "The update cannot proceed because possible database updates have been detected in the following extensions.\nSystem\nStark\n"; + $this->assertTrue($this->logger->hasRecord($expected_message, RfcLogLevel::ERROR)); } /** - * Tests that an error is raised if install or post-update files are changed. + * Tests that an error is raised if DB update files are changed in the stage. * * @param string $suffix - * The suffix of the file to change. Can be either 'install' or - * 'post_update.php'. - * @param bool $delete - * Whether or not to delete the file. + * The update file suffix to test (one of `install` or `post_update.php`). * - * @dataProvider providerFileChanged + * @dataProvider providerSuffixes */ - public function testFileChanged(string $suffix, bool $delete): void { - $listener = function (PreApplyEvent $event) use ($suffix, $delete): void { - $dir = $event->getStage()->getStageDirectory(); - $theme_installer = $this->container->get('theme_installer'); - $theme_installer->install(['automatic_updates_theme_with_updates']); - $theme = $this->container->get('theme_handler') - ->getTheme('automatic_updates_theme_with_updates'); - $module_file = "$dir/core/modules/system/system.$suffix"; - $theme_file = "$dir/{$theme->getPath()}/{$theme->getName()}.$suffix"; - if ($delete) { - unlink($module_file); - unlink($theme_file); - } - else { - file_put_contents($module_file, $this->randomString()); - file_put_contents($theme_file, $this->randomString()); + public function testFileChanged(string $suffix): void { + $listener = function (PreApplyEvent $event) use ($suffix): void { + $stage_dir = $event->getStage()->getStageDirectory(); + foreach ($this->extensions as $name => $path) { + file_put_contents("$stage_dir/$path/$name.$suffix", $this->randomString()); } }; $this->container->get('event_dispatcher') ->addListener(PreApplyEvent::class, $listener, PHP_INT_MAX); $this->container->get('cron')->run(); - $this->assertTrue($this->logger->hasRecordThatContains("The update cannot proceed because possible database updates have been detected in the following extensions.\nSystem\nAutomatic Updates Theme With Updates", RfcLogLevel::ERROR)); + $expected_message = "The update cannot proceed because possible database updates have been detected in the following extensions.\nSystem\nStark\n"; + $this->assertTrue($this->logger->hasRecord($expected_message, RfcLogLevel::ERROR)); } /** - * Tests that an error is raised if install or post-update files are added. + * Tests that an error is raised if DB update files are added in the stage. + * + * @param string $suffix + * The update file suffix to test (one of `install` or `post_update.php`). + * + * @dataProvider providerSuffixes */ - public function testUpdatesAddedInStage(): void { - $listener = function (PreApplyEvent $event): void { - $module = $this->container->get('module_handler') - ->getModule('package_manager_bypass'); - $theme_installer = $this->container->get('theme_installer'); - $theme_installer->install(['automatic_updates_theme']); - $theme = $this->container->get('theme_handler') - ->getTheme('automatic_updates_theme'); - - $dir = $event->getStage()->getStageDirectory(); - - foreach (static::SUFFIXES as $suffix) { - $module_file = sprintf('%s/%s/%s.%s', $dir, $module->getPath(), $module->getName(), $suffix); - $theme_file = sprintf('%s/%s/%s.%s', $dir, $theme->getPath(), $theme->getName(), $suffix); - // The files we're creating shouldn't already exist in the staging area - // unless it's a file we actually ship, which is a scenario covered by - // ::testFileChanged(). - $this->assertFileDoesNotExist($module_file); - $this->assertFileDoesNotExist($theme_file); - file_put_contents($module_file, $this->randomString()); - file_put_contents($theme_file, $this->randomString()); + public function testFileAdded(string $suffix): void { + $listener = function () use ($suffix): void { + $active_dir = $this->container->get('package_manager.path_locator') + ->getProjectRoot(); + + foreach ($this->extensions as $name => $path) { + unlink("$active_dir/$path/$name.$suffix"); } }; $this->container->get('event_dispatcher') ->addListener(PreApplyEvent::class, $listener, PHP_INT_MAX); $this->container->get('cron')->run(); - $this->assertTrue($this->logger->hasRecordThatContains("The update cannot proceed because possible database updates have been detected in the following extensions.\nPackage Manager Bypass\nAutomatic Updates Theme", RfcLogLevel::ERROR)); + $expected_message = "The update cannot proceed because possible database updates have been detected in the following extensions.\nSystem\nStark\n"; + $this->assertTrue($this->logger->hasRecord($expected_message, RfcLogLevel::ERROR)); } } -- GitLab