From f4ef94ae70bb153fd08bca116c56c2b1e26e0c3c Mon Sep 17 00:00:00 2001 From: Lee Rowlands <lee.rowlands@previousnext.com.au> Date: Fri, 1 Mar 2019 06:44:06 +1000 Subject: [PATCH] Issue #2975081 by alexpott, amateescu, larowlan, mtodor, catch: UpdatePathTestBase fails to re-initialize the test site (rebuild container, clear caches) after running the database updates --- .../BlockConditionMissingSchemaUpdateTest.php | 11 ---- .../src/Functional/Update/FieldUpdateTest.php | 18 +++---- .../drupal-8.responsive_image-enabled.php | 46 +++++++++++++++++ .../Update/ResponsiveImageUpdateTest.php | 19 +------ .../update_test_schema.install | 16 ++++++ .../EntityUpdateAddRevisionDefaultTest.php | 15 ++---- ...dateAddRevisionTranslationAffectedTest.php | 15 ++---- .../Update/UpdatePathTestBase.php | 36 +++++++++++-- .../Update/UpdatePathTestBaseTest.php | 51 +++++++++++++++++++ 9 files changed, 160 insertions(+), 67 deletions(-) create mode 100644 core/modules/responsive_image/tests/fixtures/update/drupal-8.responsive_image-enabled.php diff --git a/core/modules/block/tests/src/Functional/Update/BlockConditionMissingSchemaUpdateTest.php b/core/modules/block/tests/src/Functional/Update/BlockConditionMissingSchemaUpdateTest.php index 79c3beaacf1f..751dd54170a6 100644 --- a/core/modules/block/tests/src/Functional/Update/BlockConditionMissingSchemaUpdateTest.php +++ b/core/modules/block/tests/src/Functional/Update/BlockConditionMissingSchemaUpdateTest.php @@ -14,17 +14,6 @@ */ class BlockConditionMissingSchemaUpdateTest extends UpdatePathTestBase { - /** - * This test does not have a failed update but the configuration has missing - * schema so can not do the full post update testing offered by - * UpdatePathTestBase. - * - * @var bool - * - * @see \Drupal\system\Tests\Update\UpdatePathTestBase::runUpdates() - */ - protected $checkFailedUpdates = FALSE; - /** * {@inheritdoc} */ diff --git a/core/modules/field/tests/src/Functional/Update/FieldUpdateTest.php b/core/modules/field/tests/src/Functional/Update/FieldUpdateTest.php index 67c72dc58765..bec6e96546ac 100644 --- a/core/modules/field/tests/src/Functional/Update/FieldUpdateTest.php +++ b/core/modules/field/tests/src/Functional/Update/FieldUpdateTest.php @@ -48,13 +48,6 @@ class FieldUpdateTest extends UpdatePathTestBase { */ protected $state; - /** - * The deleted fields repository. - * - * @var \Drupal\Core\Field\DeletedFieldsRepositoryInterface - */ - protected $deletedFieldsRepository; - /** * {@inheritdoc} */ @@ -65,7 +58,6 @@ protected function setUp() { $this->database = $this->container->get('database'); $this->installedStorageSchema = $this->container->get('keyvalue')->get('entity.storage_schema.sql'); $this->state = $this->container->get('state'); - $this->deletedFieldsRepository = $this->container->get('entity_field.deleted_fields_repository'); } /** @@ -193,16 +185,18 @@ public function testFieldUpdate8500() { // Run updates. $this->runUpdates(); + $deleted_fields_repository = \Drupal::service('entity_field.deleted_fields_repository'); + // Now that we can use the API, check that the "delete fields" state entries // have been converted to proper field definition objects. - $deleted_fields = $this->deletedFieldsRepository->getFieldDefinitions(); + $deleted_fields = $deleted_fields_repository->getFieldDefinitions(); $this->assertCount(1, $deleted_fields); $this->assertArrayHasKey($field_uuid, $deleted_fields); $this->assertTrue($deleted_fields[$field_uuid] instanceof FieldDefinitionInterface); $this->assertEquals($field_name, $deleted_fields[$field_uuid]->getName()); - $deleted_field_storages = $this->deletedFieldsRepository->getFieldStorageDefinitions(); + $deleted_field_storages = $deleted_fields_repository->getFieldStorageDefinitions(); $this->assertCount(1, $deleted_field_storages); $this->assertArrayHasKey($field_storage_uuid, $deleted_field_storages); $this->assertTrue($deleted_field_storages[$field_storage_uuid] instanceof FieldStorageDefinitionInterface); @@ -223,10 +217,10 @@ public function testFieldUpdate8500() { // Run cron and repeat the checks above. $this->cronRun(); - $deleted_fields = $this->deletedFieldsRepository->getFieldDefinitions(); + $deleted_fields = $deleted_fields_repository->getFieldDefinitions(); $this->assertCount(0, $deleted_fields); - $deleted_field_storages = $this->deletedFieldsRepository->getFieldStorageDefinitions(); + $deleted_field_storages = $deleted_fields_repository->getFieldStorageDefinitions(); $this->assertCount(0, $deleted_field_storages); // Check that the installed storage schema has been deleted. diff --git a/core/modules/responsive_image/tests/fixtures/update/drupal-8.responsive_image-enabled.php b/core/modules/responsive_image/tests/fixtures/update/drupal-8.responsive_image-enabled.php new file mode 100644 index 000000000000..a23eea791396 --- /dev/null +++ b/core/modules/responsive_image/tests/fixtures/update/drupal-8.responsive_image-enabled.php @@ -0,0 +1,46 @@ +<?php +// @codingStandardsIgnoreFile + +use Drupal\Core\Database\Database; + +$connection = Database::getConnection(); + +// Set the schema version. +$connection->merge('key_value') + ->fields([ + 'value' => 'i:8000;', + 'name' => 'responsive_image', + 'collection' => 'system.schema', + ]) + ->condition('collection', 'system.schema') + ->condition('name', 'responsive_image') + ->execute(); + +// Update core.extension. +$extensions = $connection->select('config') + ->fields('config', ['data']) + ->condition('collection', '') + ->condition('name', 'core.extension') + ->execute() + ->fetchField(); +$extensions = unserialize($extensions); +$extensions['module']['responsive_image'] = 8000; +$connection->update('config') + ->fields([ + 'data' => serialize($extensions), + 'collection' => '', + 'name' => 'core.extension', + ]) + ->condition('collection', '') + ->condition('name', 'core.extension') + ->execute(); + +$connection->merge('key_value') + ->condition('collection', 'entity.definitions.installed') + ->condition('name', 'responsive_image_style.entity_type') + ->fields([ + 'value' => 'O:42:"Drupal\Core\Config\Entity\ConfigEntityType":44:{s:16:" * config_prefix";s:6:"styles";s:15:" * static_cache";b:0;s:14:" * lookup_keys";a:1:{i:0;s:4:"uuid";}s:16:" * config_export";a:5:{i:0;s:2:"id";i:1;s:5:"label";i:2;s:20:"image_style_mappings";i:3;s:16:"breakpoint_group";i:4;s:20:"fallback_image_style";}s:21:" * mergedConfigExport";a:0:{}s:15:" * render_cache";b:1;s:19:" * persistent_cache";b:1;s:14:" * entity_keys";a:8:{s:2:"id";s:2:"id";s:5:"label";s:5:"label";s:8:"revision";s:0:"";s:6:"bundle";s:0:"";s:8:"langcode";s:8:"langcode";s:16:"default_langcode";s:16:"default_langcode";s:29:"revision_translation_affected";s:29:"revision_translation_affected";s:4:"uuid";s:4:"uuid";}s:5:" * id";s:22:"responsive_image_style";s:16:" * originalClass";s:51:"Drupal\responsive_image\Entity\ResponsiveImageStyle";s:11:" * handlers";a:4:{s:12:"list_builder";s:55:"Drupal\responsive_image\ResponsiveImageStyleListBuilder";s:4:"form";a:4:{s:4:"edit";s:48:"Drupal\responsive_image\ResponsiveImageStyleForm";s:3:"add";s:48:"Drupal\responsive_image\ResponsiveImageStyleForm";s:6:"delete";s:35:"Drupal\Core\Entity\EntityDeleteForm";s:9:"duplicate";s:48:"Drupal\responsive_image\ResponsiveImageStyleForm";}s:6:"access";s:45:"Drupal\Core\Entity\EntityAccessControlHandler";s:7:"storage";s:45:"Drupal\Core\Config\Entity\ConfigEntityStorage";}s:19:" * admin_permission";s:28:"administer responsive images";s:25:" * permission_granularity";s:11:"entity_type";s:8:" * links";a:4:{s:9:"edit-form";s:67:"/admin/config/media/responsive-image-style/{responsive_image_style}";s:14:"duplicate-form";s:77:"/admin/config/media/responsive-image-style/{responsive_image_style}/duplicate";s:11:"delete-form";s:74:"/admin/config/media/responsive-image-style/{responsive_image_style}/delete";s:10:"collection";s:42:"/admin/config/media/responsive-image-style";}s:17:" * label_callback";N;s:21:" * bundle_entity_type";N;s:12:" * bundle_of";N;s:15:" * bundle_label";N;s:13:" * base_table";N;s:22:" * revision_data_table";N;s:17:" * revision_table";N;s:13:" * data_table";N;s:11:" * internal";b:0;s:15:" * translatable";b:0;s:19:" * show_revision_ui";b:0;s:8:" * label";O:48:"Drupal\Core\StringTranslation\TranslatableMarkup":3:{s:9:" * string";s:22:"Responsive image style";s:12:" * arguments";a:0:{}s:10:" * options";a:0:{}}s:19:" * label_collection";O:48:"Drupal\Core\StringTranslation\TranslatableMarkup":3:{s:9:" * string";s:23:"Responsive image styles";s:12:" * arguments";a:0:{}s:10:" * options";a:0:{}}s:17:" * label_singular";O:48:"Drupal\Core\StringTranslation\TranslatableMarkup":3:{s:9:" * string";s:22:"responsive image style";s:12:" * arguments";a:0:{}s:10:" * options";a:0:{}}s:15:" * label_plural";O:48:"Drupal\Core\StringTranslation\TranslatableMarkup":3:{s:9:" * string";s:23:"responsive image styles";s:12:" * arguments";a:0:{}s:10:" * options";a:0:{}}s:14:" * label_count";a:3:{s:8:"singular";s:29:"@count responsive image style";s:6:"plural";s:30:"@count responsive image styles";s:7:"context";N;}s:15:" * uri_callback";N;s:8:" * group";s:13:"configuration";s:14:" * group_label";O:48:"Drupal\Core\StringTranslation\TranslatableMarkup":3:{s:9:" * string";s:13:"Configuration";s:12:" * arguments";a:0:{}s:10:" * options";a:1:{s:7:"context";s:17:"Entity type group";}}s:22:" * field_ui_base_route";N;s:26:" * common_reference_target";b:0;s:22:" * list_cache_contexts";a:0:{}s:18:" * list_cache_tags";a:1:{i:0;s:34:"config:responsive_image_style_list";}s:14:" * constraints";a:0:{}s:13:" * additional";a:0:{}s:8:" * class";s:51:"Drupal\responsive_image\Entity\ResponsiveImageStyle";s:11:" * provider";s:16:"responsive_image";s:14:" * _serviceIds";a:0:{}s:18:" * _entityStorages";a:0:{}s:20:" * stringTranslation";N;}', + 'name' => 'responsive_image_style.entity_type', + 'collection' => 'entity.definitions.installed', + ]) + ->execute(); diff --git a/core/modules/responsive_image/tests/src/Functional/Update/ResponsiveImageUpdateTest.php b/core/modules/responsive_image/tests/src/Functional/Update/ResponsiveImageUpdateTest.php index 32b89d4256d0..e14f58d696a6 100644 --- a/core/modules/responsive_image/tests/src/Functional/Update/ResponsiveImageUpdateTest.php +++ b/core/modules/responsive_image/tests/src/Functional/Update/ResponsiveImageUpdateTest.php @@ -20,27 +20,10 @@ class ResponsiveImageUpdateTest extends UpdatePathTestBase { public function setDatabaseDumpFiles() { $this->databaseDumpFiles = [ __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8-rc1.bare.standard.php.gz', + __DIR__ . '/../../../fixtures/update/drupal-8.responsive_image-enabled.php', ]; } - /** - * {@inheritdoc} - */ - protected function setUp() { - parent::setUp(); - - /** @var \Drupal\Core\State\StateInterface $state */ - $state = $this->container->get('state'); - - // Enable responsive_image module without using the module installer to - // avoid installation of configuration shipped in module. - $system_module_files = $state->get('system.module.files', []); - $system_module_files += ['responsive_image' => 'core/modules/responsive_image/responsive_image.info.yml']; - $state->set('system.module.files', $system_module_files); - $this->config('core.extension')->set('module.responsive_image', 0)->save(); - $this->container->get('module_handler')->addModule('responsive_image', 'core/modules/responsive_image'); - } - /** * Tests post-update responsive_image_post_update_dependency(). * diff --git a/core/modules/system/tests/modules/update_test_schema/update_test_schema.install b/core/modules/system/tests/modules/update_test_schema/update_test_schema.install index 2d86fdec033b..c4a7cfc0ad5a 100644 --- a/core/modules/system/tests/modules/update_test_schema/update_test_schema.install +++ b/core/modules/system/tests/modules/update_test_schema/update_test_schema.install @@ -86,3 +86,19 @@ function update_test_schema_update_8002() { } } + +if ($schema_version >= 8003) { + + /** + * Schema version 8003. + */ + function update_test_schema_update_8003() { + // Uninstall a module with no dependencies installed by the Standard + // profile. + \Drupal::service('module_installer')->uninstall(['page_cache']); + // Install a test module that is not installed in any of the database + // dumps. + \Drupal::service('module_installer')->install(['module_test']); + } + +} diff --git a/core/modules/system/tests/src/Functional/Update/EntityUpdateAddRevisionDefaultTest.php b/core/modules/system/tests/src/Functional/Update/EntityUpdateAddRevisionDefaultTest.php index aa8ba00461b1..26f5c2c9bf5d 100644 --- a/core/modules/system/tests/src/Functional/Update/EntityUpdateAddRevisionDefaultTest.php +++ b/core/modules/system/tests/src/Functional/Update/EntityUpdateAddRevisionDefaultTest.php @@ -25,13 +25,6 @@ class EntityUpdateAddRevisionDefaultTest extends UpdatePathTestBase { */ protected $entityManager; - /** - * The last installed schema repository service. - * - * @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface - */ - protected $lastInstalledSchemaRepository; - /** * The state service. * @@ -45,8 +38,8 @@ class EntityUpdateAddRevisionDefaultTest extends UpdatePathTestBase { protected function setUp() { parent::setUp(); + // Do not use this property after calling ::runUpdates(). $this->entityManager = \Drupal::entityManager(); - $this->lastInstalledSchemaRepository = \Drupal::service('entity.last_installed_schema.repository'); $this->state = \Drupal::state(); } @@ -71,20 +64,20 @@ public function testAddingTheRevisionDefaultField() { // Check that the test entity type does not have the 'revision_default' // field before running the updates. - $field_storage_definitions = $this->lastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions('entity_test_update'); + $field_storage_definitions = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledFieldStorageDefinitions('entity_test_update'); $this->assertFalse(isset($field_storage_definitions['revision_default'])); $this->runUpdates(); // Check that the 'revision_default' field has been added by // system_update_8501(). - $field_storage_definitions = $this->lastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions('entity_test_update'); + $field_storage_definitions = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledFieldStorageDefinitions('entity_test_update'); $this->assertTrue(isset($field_storage_definitions['revision_default'])); // Check that the correct initial value was set when the field was // installed. /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */ - $entity = $this->entityManager->getStorage('entity_test_update')->load(1); + $entity = \Drupal::entityTypeManager()->getStorage('entity_test_update')->load(1); $this->assertTrue($entity->wasDefaultRevision()); } diff --git a/core/modules/system/tests/src/Functional/Update/EntityUpdateAddRevisionTranslationAffectedTest.php b/core/modules/system/tests/src/Functional/Update/EntityUpdateAddRevisionTranslationAffectedTest.php index 6553fcb06eb3..b6c4fd03777d 100644 --- a/core/modules/system/tests/src/Functional/Update/EntityUpdateAddRevisionTranslationAffectedTest.php +++ b/core/modules/system/tests/src/Functional/Update/EntityUpdateAddRevisionTranslationAffectedTest.php @@ -25,13 +25,6 @@ class EntityUpdateAddRevisionTranslationAffectedTest extends UpdatePathTestBase */ protected $entityManager; - /** - * The last installed schema repository service. - * - * @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface - */ - protected $lastInstalledSchemaRepository; - /** * The state service. * @@ -45,8 +38,8 @@ class EntityUpdateAddRevisionTranslationAffectedTest extends UpdatePathTestBase protected function setUp() { parent::setUp(); + // Do not use this property after calling ::runUpdates(). $this->entityManager = \Drupal::entityManager(); - $this->lastInstalledSchemaRepository = \Drupal::service('entity.last_installed_schema.repository'); $this->state = \Drupal::state(); } @@ -71,19 +64,19 @@ public function testAddingTheRevisionTranslationAffectedField() { // Check that the test entity type does not have the // 'revision_translation_affected' field before running the updates. - $field_storage_definitions = $this->lastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions('entity_test_update'); + $field_storage_definitions = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledFieldStorageDefinitions('entity_test_update'); $this->assertFalse(isset($field_storage_definitions['revision_translation_affected'])); $this->runUpdates(); // Check that the 'revision_translation_affected' field has been added by // system_update_8402(). - $field_storage_definitions = $this->lastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions('entity_test_update'); + $field_storage_definitions = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledFieldStorageDefinitions('entity_test_update'); $this->assertTrue(isset($field_storage_definitions['revision_translation_affected'])); // Check that the correct initial value was set when the field was // installed. - $entity = $this->entityManager->getStorage('entity_test_update')->load(1); + $entity = \Drupal::entityTypeManager()->getStorage('entity_test_update')->load(1); $this->assertTrue($entity->revision_translation_affected->value); } diff --git a/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php index f8b144bfac0c..5855effb41c5 100644 --- a/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php +++ b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php @@ -321,9 +321,38 @@ protected function runUpdates() { } } } - // Reset the static cache of drupal_get_installed_schema_version() so that - // more complex update path testing works. - drupal_static_reset('drupal_get_installed_schema_version'); + + // Ensure that the container is updated if any modules are installed or + // uninstalled during the update. + /** @var \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */ + $module_handler = $this->container->get('module_handler'); + $config_module_list = $this->config('core.extension')->get('module'); + $module_handler_list = $module_handler->getModuleList(); + $modules_installed = FALSE; + // Modules that are in configuration but not the module handler have been + // installed. + foreach (array_keys(array_diff_key($config_module_list, $module_handler_list)) as $module) { + $module_handler->addModule($module, drupal_get_path('module', $module)); + $modules_installed = TRUE; + } + $modules_uninstalled = FALSE; + $module_handler_list = $module_handler->getModuleList(); + // Modules that are in the module handler but not configuration have been + // uninstalled. + foreach (array_keys(array_diff_key($module_handler_list, $config_module_list)) as $module) { + $modules_uninstalled = TRUE; + unset($module_handler_list[$module]); + } + if ($modules_installed || $modules_uninstalled) { + // Note that resetAll() does not reset the kernel module list so we + // have to do that manually. + $this->kernel->updateModules($module_handler_list, $module_handler_list); + } + + // If we have successfully clicked 'Apply pending updates' then we need to + // clear the caches in the update test runner as this has occurred as part + // of the updates. + $this->resetAll(); // The config schema can be incorrect while the update functions are being // executed. But once the update has been completed, it needs to be valid @@ -331,7 +360,6 @@ protected function runUpdates() { $names = $this->container->get('config.storage')->listAll(); /** @var \Drupal\Core\Config\TypedConfigManagerInterface $typed_config */ $typed_config = $this->container->get('config.typed'); - $typed_config->clearCachedDefinitions(); foreach ($names as $name) { $config = $this->config($name); $this->assertConfigSchema($typed_config, $name, $config->get()); diff --git a/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBaseTest.php b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBaseTest.php index 535d271d2e8d..1d7462d7571d 100644 --- a/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBaseTest.php +++ b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBaseTest.php @@ -33,6 +33,9 @@ protected function setDatabaseDumpFiles() { * Tests that the database was properly loaded. */ public function testDatabaseLoaded() { + // Set a value in the cache to prove caches are cleared. + \Drupal::service('cache.default')->set(__CLASS__, 'Test'); + foreach (['user', 'node', 'system', 'update_test_schema'] as $module) { $this->assertEqual(drupal_get_installed_schema_version($module), 8000, new FormattableMarkup('Module @module schema is 8000', ['@module' => $module])); } @@ -70,6 +73,8 @@ public function testDatabaseLoaded() { $this->assertEqual('on', $database->query("SHOW standard_conforming_strings")->fetchField()); $this->assertEqual('escape', $database->query("SHOW bytea_output")->fetchField()); } + // Ensure the test runners cache has been cleared. + $this->assertFalse(\Drupal::service('cache.default')->get(__CLASS__)); } /** @@ -131,4 +136,50 @@ public function testPathAliasProcessing() { $this->assertSession()->linkByHrefExists('/admin-structure-alias'); } + /** + * Tests that test running environment is updated when module list changes. + * + * @see update_test_schema_update_8003() + */ + public function testModuleListChange() { + // Set a value in the cache to prove caches are cleared. + \Drupal::service('cache.default')->set(__CLASS__, 'Test'); + + // Ensure that modules are installed and uninstalled as expected prior to + // running updates. + $extension_config = $this->config('core.extension')->get(); + $this->assertArrayHasKey('page_cache', $extension_config['module']); + $this->assertArrayNotHasKey('module_test', $extension_config['module']); + + $module_list = \Drupal::moduleHandler()->getModuleList(); + $this->assertArrayHasKey('page_cache', $module_list); + $this->assertArrayNotHasKey('module_test', $module_list); + + $namespaces = \Drupal::getContainer()->getParameter('container.namespaces'); + $this->assertArrayHasKey('Drupal\page_cache', $namespaces); + $this->assertArrayNotHasKey('Drupal\module_test', $namespaces); + + // Increment the schema version so that update_test_schema_update_8003() + // runs. + \Drupal::state()->set('update_test_schema_version', 8003); + $this->runUpdates(); + + // Ensure that test running environment has been updated with the changes to + // the module list. + $extension_config = $this->config('core.extension')->get(); + $this->assertArrayNotHasKey('page_cache', $extension_config['module']); + $this->assertArrayHasKey('module_test', $extension_config['module']); + + $module_list = \Drupal::moduleHandler()->getModuleList(); + $this->assertArrayNotHasKey('page_cache', $module_list); + $this->assertArrayHasKey('module_test', $module_list); + + $namespaces = \Drupal::getContainer()->getParameter('container.namespaces'); + $this->assertArrayNotHasKey('Drupal\page_cache', $namespaces); + $this->assertArrayHasKey('Drupal\module_test', $namespaces); + + // Ensure the test runners cache has been cleared. + $this->assertFalse(\Drupal::service('cache.default')->get(__CLASS__)); + } + } -- GitLab