Skip to content

Commit c212995

Browse files
committed
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
(cherry picked from commit f4ef94a)
1 parent 230bd6e commit c212995

File tree

9 files changed

+160
-67
lines changed

9 files changed

+160
-67
lines changed

modules/block/tests/src/Functional/Update/BlockConditionMissingSchemaUpdateTest.php

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,6 @@
1414
*/
1515
class BlockConditionMissingSchemaUpdateTest extends UpdatePathTestBase {
1616

17-
/**
18-
* This test does not have a failed update but the configuration has missing
19-
* schema so can not do the full post update testing offered by
20-
* UpdatePathTestBase.
21-
*
22-
* @var bool
23-
*
24-
* @see \Drupal\system\Tests\Update\UpdatePathTestBase::runUpdates()
25-
*/
26-
protected $checkFailedUpdates = FALSE;
27-
2817
/**
2918
* {@inheritdoc}
3019
*/

modules/field/tests/src/Functional/Update/FieldUpdateTest.php

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,6 @@ class FieldUpdateTest extends UpdatePathTestBase {
4848
*/
4949
protected $state;
5050

51-
/**
52-
* The deleted fields repository.
53-
*
54-
* @var \Drupal\Core\Field\DeletedFieldsRepositoryInterface
55-
*/
56-
protected $deletedFieldsRepository;
57-
5851
/**
5952
* {@inheritdoc}
6053
*/
@@ -65,7 +58,6 @@ protected function setUp() {
6558
$this->database = $this->container->get('database');
6659
$this->installedStorageSchema = $this->container->get('keyvalue')->get('entity.storage_schema.sql');
6760
$this->state = $this->container->get('state');
68-
$this->deletedFieldsRepository = $this->container->get('entity_field.deleted_fields_repository');
6961
}
7062

7163
/**
@@ -193,16 +185,18 @@ public function testFieldUpdate8500() {
193185
// Run updates.
194186
$this->runUpdates();
195187

188+
$deleted_fields_repository = \Drupal::service('entity_field.deleted_fields_repository');
189+
196190
// Now that we can use the API, check that the "delete fields" state entries
197191
// have been converted to proper field definition objects.
198-
$deleted_fields = $this->deletedFieldsRepository->getFieldDefinitions();
192+
$deleted_fields = $deleted_fields_repository->getFieldDefinitions();
199193

200194
$this->assertCount(1, $deleted_fields);
201195
$this->assertArrayHasKey($field_uuid, $deleted_fields);
202196
$this->assertTrue($deleted_fields[$field_uuid] instanceof FieldDefinitionInterface);
203197
$this->assertEquals($field_name, $deleted_fields[$field_uuid]->getName());
204198

205-
$deleted_field_storages = $this->deletedFieldsRepository->getFieldStorageDefinitions();
199+
$deleted_field_storages = $deleted_fields_repository->getFieldStorageDefinitions();
206200
$this->assertCount(1, $deleted_field_storages);
207201
$this->assertArrayHasKey($field_storage_uuid, $deleted_field_storages);
208202
$this->assertTrue($deleted_field_storages[$field_storage_uuid] instanceof FieldStorageDefinitionInterface);
@@ -223,10 +217,10 @@ public function testFieldUpdate8500() {
223217
// Run cron and repeat the checks above.
224218
$this->cronRun();
225219

226-
$deleted_fields = $this->deletedFieldsRepository->getFieldDefinitions();
220+
$deleted_fields = $deleted_fields_repository->getFieldDefinitions();
227221
$this->assertCount(0, $deleted_fields);
228222

229-
$deleted_field_storages = $this->deletedFieldsRepository->getFieldStorageDefinitions();
223+
$deleted_field_storages = $deleted_fields_repository->getFieldStorageDefinitions();
230224
$this->assertCount(0, $deleted_field_storages);
231225

232226
// Check that the installed storage schema has been deleted.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
// @codingStandardsIgnoreFile
3+
4+
use Drupal\Core\Database\Database;
5+
6+
$connection = Database::getConnection();
7+
8+
// Set the schema version.
9+
$connection->merge('key_value')
10+
->fields([
11+
'value' => 'i:8000;',
12+
'name' => 'responsive_image',
13+
'collection' => 'system.schema',
14+
])
15+
->condition('collection', 'system.schema')
16+
->condition('name', 'responsive_image')
17+
->execute();
18+
19+
// Update core.extension.
20+
$extensions = $connection->select('config')
21+
->fields('config', ['data'])
22+
->condition('collection', '')
23+
->condition('name', 'core.extension')
24+
->execute()
25+
->fetchField();
26+
$extensions = unserialize($extensions);
27+
$extensions['module']['responsive_image'] = 8000;
28+
$connection->update('config')
29+
->fields([
30+
'data' => serialize($extensions),
31+
'collection' => '',
32+
'name' => 'core.extension',
33+
])
34+
->condition('collection', '')
35+
->condition('name', 'core.extension')
36+
->execute();
37+
38+
$connection->merge('key_value')
39+
->condition('collection', 'entity.definitions.installed')
40+
->condition('name', 'responsive_image_style.entity_type')
41+
->fields([
42+
'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;}',
43+
'name' => 'responsive_image_style.entity_type',
44+
'collection' => 'entity.definitions.installed',
45+
])
46+
->execute();

modules/responsive_image/tests/src/Functional/Update/ResponsiveImageUpdateTest.php

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,10 @@ class ResponsiveImageUpdateTest extends UpdatePathTestBase {
2020
public function setDatabaseDumpFiles() {
2121
$this->databaseDumpFiles = [
2222
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8-rc1.bare.standard.php.gz',
23+
__DIR__ . '/../../../fixtures/update/drupal-8.responsive_image-enabled.php',
2324
];
2425
}
2526

26-
/**
27-
* {@inheritdoc}
28-
*/
29-
protected function setUp() {
30-
parent::setUp();
31-
32-
/** @var \Drupal\Core\State\StateInterface $state */
33-
$state = $this->container->get('state');
34-
35-
// Enable responsive_image module without using the module installer to
36-
// avoid installation of configuration shipped in module.
37-
$system_module_files = $state->get('system.module.files', []);
38-
$system_module_files += ['responsive_image' => 'core/modules/responsive_image/responsive_image.info.yml'];
39-
$state->set('system.module.files', $system_module_files);
40-
$this->config('core.extension')->set('module.responsive_image', 0)->save();
41-
$this->container->get('module_handler')->addModule('responsive_image', 'core/modules/responsive_image');
42-
}
43-
4427
/**
4528
* Tests post-update responsive_image_post_update_dependency().
4629
*

modules/system/tests/modules/update_test_schema/update_test_schema.install

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,19 @@ if ($schema_version >= 8001) {
4848
}
4949

5050
}
51+
52+
if ($schema_version >= 8003) {
53+
54+
/**
55+
* Schema version 8003.
56+
*/
57+
function update_test_schema_update_8003() {
58+
// Uninstall a module with no dependencies installed by the Standard
59+
// profile.
60+
\Drupal::service('module_installer')->uninstall(['page_cache']);
61+
// Install a test module that is not installed in any of the database
62+
// dumps.
63+
\Drupal::service('module_installer')->install(['module_test']);
64+
}
65+
66+
}

modules/system/tests/src/Functional/Update/EntityUpdateAddRevisionDefaultTest.php

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,6 @@ class EntityUpdateAddRevisionDefaultTest extends UpdatePathTestBase {
2525
*/
2626
protected $entityManager;
2727

28-
/**
29-
* The last installed schema repository service.
30-
*
31-
* @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface
32-
*/
33-
protected $lastInstalledSchemaRepository;
34-
3528
/**
3629
* The state service.
3730
*
@@ -45,8 +38,8 @@ class EntityUpdateAddRevisionDefaultTest extends UpdatePathTestBase {
4538
protected function setUp() {
4639
parent::setUp();
4740

41+
// Do not use this property after calling ::runUpdates().
4842
$this->entityManager = \Drupal::entityManager();
49-
$this->lastInstalledSchemaRepository = \Drupal::service('entity.last_installed_schema.repository');
5043
$this->state = \Drupal::state();
5144
}
5245

@@ -71,20 +64,20 @@ public function testAddingTheRevisionDefaultField() {
7164

7265
// Check that the test entity type does not have the 'revision_default'
7366
// field before running the updates.
74-
$field_storage_definitions = $this->lastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions('entity_test_update');
67+
$field_storage_definitions = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledFieldStorageDefinitions('entity_test_update');
7568
$this->assertFalse(isset($field_storage_definitions['revision_default']));
7669

7770
$this->runUpdates();
7871

7972
// Check that the 'revision_default' field has been added by
8073
// system_update_8501().
81-
$field_storage_definitions = $this->lastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions('entity_test_update');
74+
$field_storage_definitions = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledFieldStorageDefinitions('entity_test_update');
8275
$this->assertTrue(isset($field_storage_definitions['revision_default']));
8376

8477
// Check that the correct initial value was set when the field was
8578
// installed.
8679
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
87-
$entity = $this->entityManager->getStorage('entity_test_update')->load(1);
80+
$entity = \Drupal::entityTypeManager()->getStorage('entity_test_update')->load(1);
8881
$this->assertTrue($entity->wasDefaultRevision());
8982
}
9083

modules/system/tests/src/Functional/Update/EntityUpdateAddRevisionTranslationAffectedTest.php

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,6 @@ class EntityUpdateAddRevisionTranslationAffectedTest extends UpdatePathTestBase
2525
*/
2626
protected $entityManager;
2727

28-
/**
29-
* The last installed schema repository service.
30-
*
31-
* @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface
32-
*/
33-
protected $lastInstalledSchemaRepository;
34-
3528
/**
3629
* The state service.
3730
*
@@ -45,8 +38,8 @@ class EntityUpdateAddRevisionTranslationAffectedTest extends UpdatePathTestBase
4538
protected function setUp() {
4639
parent::setUp();
4740

41+
// Do not use this property after calling ::runUpdates().
4842
$this->entityManager = \Drupal::entityManager();
49-
$this->lastInstalledSchemaRepository = \Drupal::service('entity.last_installed_schema.repository');
5043
$this->state = \Drupal::state();
5144
}
5245

@@ -71,19 +64,19 @@ public function testAddingTheRevisionTranslationAffectedField() {
7164

7265
// Check that the test entity type does not have the
7366
// 'revision_translation_affected' field before running the updates.
74-
$field_storage_definitions = $this->lastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions('entity_test_update');
67+
$field_storage_definitions = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledFieldStorageDefinitions('entity_test_update');
7568
$this->assertFalse(isset($field_storage_definitions['revision_translation_affected']));
7669

7770
$this->runUpdates();
7871

7972
// Check that the 'revision_translation_affected' field has been added by
8073
// system_update_8402().
81-
$field_storage_definitions = $this->lastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions('entity_test_update');
74+
$field_storage_definitions = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledFieldStorageDefinitions('entity_test_update');
8275
$this->assertTrue(isset($field_storage_definitions['revision_translation_affected']));
8376

8477
// Check that the correct initial value was set when the field was
8578
// installed.
86-
$entity = $this->entityManager->getStorage('entity_test_update')->load(1);
79+
$entity = \Drupal::entityTypeManager()->getStorage('entity_test_update')->load(1);
8780
$this->assertTrue($entity->revision_translation_affected->value);
8881
}
8982

tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -319,17 +319,45 @@ protected function runUpdates() {
319319
}
320320
}
321321
}
322-
// Reset the static cache of drupal_get_installed_schema_version() so that
323-
// more complex update path testing works.
324-
drupal_static_reset('drupal_get_installed_schema_version');
322+
323+
// Ensure that the container is updated if any modules are installed or
324+
// uninstalled during the update.
325+
/** @var \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */
326+
$module_handler = $this->container->get('module_handler');
327+
$config_module_list = $this->config('core.extension')->get('module');
328+
$module_handler_list = $module_handler->getModuleList();
329+
$modules_installed = FALSE;
330+
// Modules that are in configuration but not the module handler have been
331+
// installed.
332+
foreach (array_keys(array_diff_key($config_module_list, $module_handler_list)) as $module) {
333+
$module_handler->addModule($module, drupal_get_path('module', $module));
334+
$modules_installed = TRUE;
335+
}
336+
$modules_uninstalled = FALSE;
337+
$module_handler_list = $module_handler->getModuleList();
338+
// Modules that are in the module handler but not configuration have been
339+
// uninstalled.
340+
foreach (array_keys(array_diff_key($module_handler_list, $config_module_list)) as $module) {
341+
$modules_uninstalled = TRUE;
342+
unset($module_handler_list[$module]);
343+
}
344+
if ($modules_installed || $modules_uninstalled) {
345+
// Note that resetAll() does not reset the kernel module list so we
346+
// have to do that manually.
347+
$this->kernel->updateModules($module_handler_list, $module_handler_list);
348+
}
349+
350+
// If we have successfully clicked 'Apply pending updates' then we need to
351+
// clear the caches in the update test runner as this has occurred as part
352+
// of the updates.
353+
$this->resetAll();
325354

326355
// The config schema can be incorrect while the update functions are being
327356
// executed. But once the update has been completed, it needs to be valid
328357
// again. Assert the schema of all configuration objects now.
329358
$names = $this->container->get('config.storage')->listAll();
330359
/** @var \Drupal\Core\Config\TypedConfigManagerInterface $typed_config */
331360
$typed_config = $this->container->get('config.typed');
332-
$typed_config->clearCachedDefinitions();
333361
foreach ($names as $name) {
334362
$config = $this->config($name);
335363
$this->assertConfigSchema($typed_config, $name, $config->get());

tests/Drupal/FunctionalTests/Update/UpdatePathTestBaseTest.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ protected function setDatabaseDumpFiles() {
3232
* Tests that the database was properly loaded.
3333
*/
3434
public function testDatabaseLoaded() {
35+
// Set a value in the cache to prove caches are cleared.
36+
\Drupal::service('cache.default')->set(__CLASS__, 'Test');
37+
3538
foreach (['user', 'node', 'system', 'update_test_schema'] as $module) {
3639
$this->assertEqual(drupal_get_installed_schema_version($module), 8000, new FormattableMarkup('Module @module schema is 8000', ['@module' => $module]));
3740
}
@@ -69,6 +72,8 @@ public function testDatabaseLoaded() {
6972
$this->assertEqual('on', $database->query("SHOW standard_conforming_strings")->fetchField());
7073
$this->assertEqual('escape', $database->query("SHOW bytea_output")->fetchField());
7174
}
75+
// Ensure the test runners cache has been cleared.
76+
$this->assertFalse(\Drupal::service('cache.default')->get(__CLASS__));
7277
}
7378

7479
/**
@@ -95,4 +100,50 @@ public function testUpdateHookN() {
95100
$this->assertTrue(db_index_exists('update_test_schema_table', 'test'), 'Version 8001 of the update_test_schema module is installed.');
96101
}
97102

103+
/**
104+
* Tests that test running environment is updated when module list changes.
105+
*
106+
* @see update_test_schema_update_8003()
107+
*/
108+
public function testModuleListChange() {
109+
// Set a value in the cache to prove caches are cleared.
110+
\Drupal::service('cache.default')->set(__CLASS__, 'Test');
111+
112+
// Ensure that modules are installed and uninstalled as expected prior to
113+
// running updates.
114+
$extension_config = $this->config('core.extension')->get();
115+
$this->assertArrayHasKey('page_cache', $extension_config['module']);
116+
$this->assertArrayNotHasKey('module_test', $extension_config['module']);
117+
118+
$module_list = \Drupal::moduleHandler()->getModuleList();
119+
$this->assertArrayHasKey('page_cache', $module_list);
120+
$this->assertArrayNotHasKey('module_test', $module_list);
121+
122+
$namespaces = \Drupal::getContainer()->getParameter('container.namespaces');
123+
$this->assertArrayHasKey('Drupal\page_cache', $namespaces);
124+
$this->assertArrayNotHasKey('Drupal\module_test', $namespaces);
125+
126+
// Increment the schema version so that update_test_schema_update_8003()
127+
// runs.
128+
\Drupal::state()->set('update_test_schema_version', 8003);
129+
$this->runUpdates();
130+
131+
// Ensure that test running environment has been updated with the changes to
132+
// the module list.
133+
$extension_config = $this->config('core.extension')->get();
134+
$this->assertArrayNotHasKey('page_cache', $extension_config['module']);
135+
$this->assertArrayHasKey('module_test', $extension_config['module']);
136+
137+
$module_list = \Drupal::moduleHandler()->getModuleList();
138+
$this->assertArrayNotHasKey('page_cache', $module_list);
139+
$this->assertArrayHasKey('module_test', $module_list);
140+
141+
$namespaces = \Drupal::getContainer()->getParameter('container.namespaces');
142+
$this->assertArrayNotHasKey('Drupal\page_cache', $namespaces);
143+
$this->assertArrayHasKey('Drupal\module_test', $namespaces);
144+
145+
// Ensure the test runners cache has been cleared.
146+
$this->assertFalse(\Drupal::service('cache.default')->get(__CLASS__));
147+
}
148+
98149
}

0 commit comments

Comments
 (0)