class UpdateRegistryTest
Same name and namespace in other branches
- 11.x core/tests/Drupal/Tests/Core/Update/UpdateRegistryTest.php \Drupal\Tests\Core\Update\UpdateRegistryTest
- 10 core/tests/Drupal/Tests/Core/Update/UpdateRegistryTest.php \Drupal\Tests\Core\Update\UpdateRegistryTest
- 9 core/tests/Drupal/Tests/Core/Update/UpdateRegistryTest.php \Drupal\Tests\Core\Update\UpdateRegistryTest
- 8.9.x core/tests/Drupal/Tests/Core/Update/UpdateRegistryTest.php \Drupal\Tests\Core\Update\UpdateRegistryTest
Tests UpdateRegistry.
Note we load code, so isolate the tests.
Attributes
#[CoversClass(UpdateRegistry::class)]
#[Group('Update')]
#[Group('#slow')]
#[PreserveGlobalState(FALSE)]
#[RunTestsInSeparateProcesses]
Hierarchy
- class \Drupal\Tests\UnitTestCase uses \Drupal\Tests\DrupalTestCaseTrait, \Drupal\Tests\PhpUnitCompatibilityTrait, \Prophecy\PhpUnit\ProphecyTrait, \Drupal\TestTools\Extension\DeprecationBridge\ExpectDeprecationTrait, \Drupal\Tests\RandomGeneratorTrait extends \PHPUnit\Framework\TestCase
- class \Drupal\Tests\Core\Update\UpdateRegistryTest extends \Drupal\Tests\UnitTestCase
Expanded class hierarchy of UpdateRegistryTest
File
-
core/
tests/ Drupal/ Tests/ Core/ Update/ UpdateRegistryTest.php, line 24
Namespace
Drupal\Tests\Core\UpdateView source
class UpdateRegistryTest extends UnitTestCase {
/**
* {@inheritdoc}
*/
protected function setUp() : void {
parent::setUp();
$settings = [];
$settings['extension_discovery_scan_tests'] = TRUE;
new Settings($settings);
}
/**
* Sets up some extensions with some update functions.
*/
protected function setupBasicExtensions() : void {
$info_a = <<<'EOS'
type: module
name: Module A
core_version_requirement: '*'
EOS;
$info_b = <<<'EOS'
type: module
name: Module B
core_version_requirement: '*'
EOS;
$info_c = <<<'EOS'
type: module
name: Module C
core_version_requirement: '*'
EOS;
$info_d = <<<'EOS'
type: theme
name: Theme D
core_version_requirement: '*'
EOS;
$module_a = <<<'EOS'
<?php
/**
* Module A update B.
*/
function module_a_post_update_b() {
}
/**
* Module A update A.
*/
function module_a_post_update_a() {
}
EOS;
$module_b = <<<'EOS'
<?php
/**
* Module B update A.
*/
function module_b_post_update_a() {
}
/**
* Implements hook_removed_post_updates().
*/
function module_b_removed_post_updates(): array {
return [
'module_b_post_update_b' => '8.9.0',
'module_b_post_update_c' => '8.9.0',
];
}
EOS;
$module_c = <<<'EOS'
<?php
/**
* Module C update A.
*/
function module_c_post_update_a() {
}
/**
* Module C update B.
*/
function module_c_post_update_b() {
}
/**
* Implements hook_removed_post_updates().
*/
function module_c_removed_post_updates(): array {
return [
'module_c_post_update_b' => '8.9.0',
'module_c_post_update_c' => '8.9.0',
];
}
EOS;
$theme_d = <<<'EOS'
<?php
/**
* Theme D update B.
*/
function theme_d_post_update_b() {
}
/**
* Theme D update C.
*/
function theme_d_post_update_c() {
}
/**
* Implements hook_removed_post_updates().
*/
function theme_d_removed_post_updates(): array {
return [
'theme_d_post_update_a' => '8.9.0',
];
}
EOS;
vfsStream::setup('drupal');
vfsStream::create([
'sites' => [
'default' => [
'modules' => [
'module_a' => [
'module_a.post_update.php' => $module_a,
'module_a.info.yml' => $info_a,
],
'module_b' => [
'module_b.post_update.php' => $module_b,
'module_b.info.yml' => $info_b,
],
'module_c' => [
'module_c.post_update.php' => $module_c,
'module_c.info.yml' => $info_c,
],
],
'themes' => [
'theme_d' => [
'theme_d.post_update.php' => $theme_d,
'theme_d.info.yml' => $info_d,
],
],
],
],
]);
}
/**
* Tests get pending update functions no existing updates.
*/
public function testGetPendingUpdateFunctionsNoExistingUpdates() : void {
$this->setupBasicExtensions();
$key_value = $this->prophesize(KeyValueStoreInterface::class);
$key_value->get('existing_updates', [])
->willReturn([]);
$key_value = $key_value->reveal();
$theme_handler = $this->prophesize(ThemeHandlerInterface::class);
$theme_handler->listInfo()
->willReturn([
'theme_d' => [
'type' => 'theme',
'pathname' => 'core/themes/theme_d/theme_d.info.yml',
],
]);
$theme_handler = $theme_handler->reveal();
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
'module_a' => [
'type' => 'module',
'pathname' => 'core/modules/module_a/module_a.info.yml',
'filename' => 'module_a.module',
],
'module_b' => [
'type' => 'module',
'pathname' => 'core/modules/module_b/module_b.info.yml',
'filename' => 'module_b.module',
],
], $key_value, $theme_handler, 'post_update');
// Confirm the updates are sorted alphabetically.
$this->assertEquals([
'module_a_post_update_a',
'module_a_post_update_b',
'module_b_post_update_a',
'theme_d_post_update_b',
'theme_d_post_update_c',
], $update_registry->getPendingUpdateFunctions());
}
/**
* Tests get pending update functions with loaded modules but not enabled.
*/
public function testGetPendingUpdateFunctionsWithLoadedModulesButNotEnabled() : void {
$this->setupBasicExtensions();
$key_value = $this->prophesize(KeyValueStoreInterface::class);
$key_value->get('existing_updates', [])
->willReturn([]);
$key_value = $key_value->reveal();
$theme_handler = $this->prophesize(ThemeHandlerInterface::class);
$theme_handler->listInfo()
->willReturn([]);
$theme_handler = $theme_handler->reveal();
// Preload modules to ensure that ::getAvailableUpdateFunctions filters out
// not enabled modules.
include_once 'vfs://drupal/sites/default/modules/module_a/module_a.post_update.php';
include_once 'vfs://drupal/sites/default/modules/module_b/module_b.post_update.php';
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
'module_a' => [
'type' => 'module',
'pathname' => 'core/modules/module_a/module_a.info.yml',
'filename' => 'module_a.module',
],
], $key_value, $theme_handler, 'post_update');
// Confirm the updates are sorted alphabetically.
$this->assertEquals([
'module_a_post_update_a',
'module_a_post_update_b',
], $update_registry->getPendingUpdateFunctions());
}
/**
* Tests get pending update functions existing updates.
*/
public function testGetPendingUpdateFunctionsExistingUpdates() : void {
$this->setupBasicExtensions();
$key_value = $this->prophesize(KeyValueStoreInterface::class);
$key_value->get('existing_updates', [])
->willReturn([
'module_a_post_update_a',
'theme_d_post_update_a',
'theme_d_post_update_b',
]);
$key_value = $key_value->reveal();
$theme_handler = $this->prophesize(ThemeHandlerInterface::class);
$theme_handler->listInfo()
->willReturn([
'theme_d' => [
'type' => 'theme',
'pathname' => 'core/themes/theme_d/theme_d.info.yml',
],
]);
$theme_handler = $theme_handler->reveal();
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
'module_a' => [
'type' => 'module',
'pathname' => 'core/modules/module_a/module_a.info.yml',
'filename' => 'module_a.module',
],
'module_b' => [
'type' => 'module',
'pathname' => 'core/modules/module_b/module_b.info.yml',
'filename' => 'module_b.module',
],
], $key_value, $theme_handler, 'post_update');
// Confirm the updates are sorted alphabetically.
$this->assertEquals(array_values([
'module_a_post_update_b',
'module_b_post_update_a',
'theme_d_post_update_c',
]), array_values($update_registry->getPendingUpdateFunctions()));
}
/**
* Tests get pending update information.
*/
public function testGetPendingUpdateInformation() : void {
$this->setupBasicExtensions();
$key_value = $this->prophesize(KeyValueStoreInterface::class);
$key_value->get('existing_updates', [])
->willReturn([]);
$key_value = $key_value->reveal();
$theme_handler = $this->prophesize(ThemeHandlerInterface::class);
$theme_handler->listInfo()
->willReturn([
'theme_d' => [
'type' => 'theme',
'pathname' => 'core/themes/theme_d/theme_d.info.yml',
],
]);
$theme_handler = $theme_handler->reveal();
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
'module_a' => [
'type' => 'module',
'pathname' => 'core/modules/module_a/module_a.info.yml',
'filename' => 'module_a.module',
],
'module_b' => [
'type' => 'module',
'pathname' => 'core/modules/module_b/module_b.info.yml',
'filename' => 'module_b.module',
],
], $key_value, $theme_handler, 'post_update');
// Confirm the updates are sorted alphabetically.
$expected = [];
$expected['module_a']['pending']['a'] = 'Module A update A.';
$expected['module_a']['pending']['b'] = 'Module A update B.';
$expected['module_a']['start'] = 'a';
$expected['module_b']['pending']['a'] = 'Module B update A.';
$expected['module_b']['start'] = 'a';
$expected['theme_d']['pending']['b'] = 'Theme D update B.';
$expected['theme_d']['pending']['c'] = 'Theme D update C.';
$expected['theme_d']['start'] = 'b';
$this->assertEquals($expected, $update_registry->getPendingUpdateInformation());
}
/**
* Tests get pending update information with existing updates.
*/
public function testGetPendingUpdateInformationWithExistingUpdates() : void {
$this->setupBasicExtensions();
$key_value = $this->prophesize(KeyValueStoreInterface::class);
$key_value->get('existing_updates', [])
->willReturn([
'module_a_post_update_a',
'theme_d_post_update_a',
'theme_d_post_update_b',
]);
$key_value = $key_value->reveal();
$theme_handler = $this->prophesize(ThemeHandlerInterface::class);
$theme_handler->listInfo()
->willReturn([
'theme_d' => [
'type' => 'theme',
'pathname' => 'core/themes/theme_d/theme_d.info.yml',
],
]);
$theme_handler = $theme_handler->reveal();
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
'module_a' => [
'type' => 'module',
'pathname' => 'core/modules/module_a/module_a.info.yml',
'filename' => 'module_a.module',
],
'module_b' => [
'type' => 'module',
'pathname' => 'core/modules/module_b/module_b.info.yml',
'filename' => 'module_b.module',
],
], $key_value, $theme_handler, 'post_update');
// Confirm the updates are sorted alphabetically.
$expected = [];
$expected['module_a']['pending']['b'] = 'Module A update B.';
$expected['module_a']['start'] = 'b';
$expected['module_b']['pending']['a'] = 'Module B update A.';
$expected['module_b']['start'] = 'a';
$expected['theme_d']['pending']['c'] = 'Theme D update C.';
$expected['theme_d']['start'] = 'c';
$this->assertEquals($expected, $update_registry->getPendingUpdateInformation());
}
/**
* Tests get pending update information with removed updates.
*/
public function testGetPendingUpdateInformationWithRemovedUpdates() : void {
$this->setupBasicExtensions();
$key_value = $this->prophesize(KeyValueStoreInterface::class);
$key_value->get('existing_updates', [])
->willReturn([
'module_a_post_update_a',
]);
$key_value = $key_value->reveal();
$theme_handler = $this->prophesize(ThemeHandlerInterface::class);
$theme_handler->listInfo()
->willReturn([]);
$theme_handler = $theme_handler->reveal();
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
'module_c' => [
'type' => 'module',
'pathname' => 'core/modules/module_c/module_c.info.yml',
'filename' => 'module_c.module',
],
], $key_value, $theme_handler, 'post_update');
$this->expectException(RemovedPostUpdateNameException::class);
$update_registry->getPendingUpdateInformation();
}
/**
* Tests get update functions.
*/
public function testGetUpdateFunctions() : void {
$this->setupBasicExtensions();
$key_value = $this->prophesize(KeyValueStoreInterface::class)
->reveal();
$theme_handler = $this->prophesize(ThemeHandlerInterface::class);
$theme_handler->listInfo()
->willReturn([
'theme_d' => [
'type' => 'theme',
'pathname' => 'core/themes/theme_d/theme_d.info.yml',
],
]);
$theme_handler = $theme_handler->reveal();
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
'module_a' => [
'type' => 'module',
'pathname' => 'core/modules/module_a/module_a.info.yml',
'filename' => 'module_a.module',
],
'module_b' => [
'type' => 'module',
'pathname' => 'core/modules/module_b/module_b.info.yml',
'filename' => 'module_b.module',
],
], $key_value, $theme_handler, 'post_update');
$this->assertEquals([
'module_a_post_update_a',
'module_a_post_update_b',
], array_values($update_registry->getUpdateFunctions('module_a')));
$this->assertEquals([
'module_b_post_update_a',
], array_values($update_registry->getUpdateFunctions('module_b')));
$this->assertEquals([
'theme_d_post_update_b',
'theme_d_post_update_c',
], array_values($update_registry->getUpdateFunctions('theme_d')));
}
/**
* Tests register invoked updates without existing updates.
*/
public function testRegisterInvokedUpdatesWithoutExistingUpdates() : void {
$this->setupBasicExtensions();
$key_value = $this->prophesize(KeyValueStoreInterface::class);
$key_value->get('existing_updates', [])
->willReturn([])
->shouldBeCalledTimes(1);
$key_value->set('existing_updates', [
'module_a_post_update_a',
])
->willReturn(NULL)
->shouldBeCalledTimes(1);
$key_value = $key_value->reveal();
$theme_handler = $this->prophesize(ThemeHandlerInterface::class);
$theme_handler->listInfo()
->willReturn([
'theme_d' => [
'type' => 'theme',
'pathname' => 'core/themes/theme_d/theme_d.info.yml',
],
]);
$theme_handler = $theme_handler->reveal();
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
'module_a' => [
'type' => 'module',
'pathname' => 'core/modules/module_a/module_a.info.yml',
'filename' => 'module_a.module',
],
'module_b' => [
'type' => 'module',
'pathname' => 'core/modules/module_b/module_b.info.yml',
'filename' => 'module_b.module',
],
], $key_value, $theme_handler, 'post_update');
$update_registry->registerInvokedUpdates([
'module_a_post_update_a',
]);
}
/**
* Tests register invoked updates with multiple.
*/
public function testRegisterInvokedUpdatesWithMultiple() : void {
$this->setupBasicExtensions();
$key_value = $this->prophesize(KeyValueStoreInterface::class);
$key_value->get('existing_updates', [])
->willReturn([])
->shouldBeCalledTimes(1);
$key_value->set('existing_updates', [
'module_a_post_update_a',
'module_a_post_update_b',
'theme_d_post_update_c',
])
->willReturn(NULL)
->shouldBeCalledTimes(1);
$key_value = $key_value->reveal();
$theme_handler = $this->prophesize(ThemeHandlerInterface::class);
$theme_handler->listInfo()
->willReturn([
'theme_d' => [
'type' => 'theme',
'pathname' => 'core/themes/theme_d/theme_d.info.yml',
],
]);
$theme_handler = $theme_handler->reveal();
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
'module_a' => [
'type' => 'module',
'pathname' => 'core/modules/module_a/module_a.info.yml',
'filename' => 'module_a.module',
],
'module_b' => [
'type' => 'module',
'pathname' => 'core/modules/module_b/module_b.info.yml',
'filename' => 'module_b.module',
],
], $key_value, $theme_handler, 'post_update');
$update_registry->registerInvokedUpdates([
'module_a_post_update_a',
'module_a_post_update_b',
'theme_d_post_update_c',
]);
}
/**
* Tests register invoked updates with existing updates.
*/
public function testRegisterInvokedUpdatesWithExistingUpdates() : void {
$this->setupBasicExtensions();
$key_value = $this->prophesize(KeyValueStoreInterface::class);
$key_value->get('existing_updates', [])
->willReturn([
'module_a_post_update_b',
])
->shouldBeCalledTimes(1);
$key_value->set('existing_updates', [
'module_a_post_update_b',
'module_a_post_update_a',
])
->willReturn(NULL)
->shouldBeCalledTimes(1);
$key_value = $key_value->reveal();
$theme_handler = $this->prophesize(ThemeHandlerInterface::class);
$theme_handler->listInfo()
->willReturn([]);
$theme_handler = $theme_handler->reveal();
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
'module_a' => [
'type' => 'module',
'pathname' => 'core/modules/module_a/module_a.info.yml',
'filename' => 'module_a.module',
],
'module_b' => [
'type' => 'module',
'pathname' => 'core/modules/module_b/module_b.info.yml',
'filename' => 'module_b.module',
],
], $key_value, $theme_handler, 'post_update');
$update_registry->registerInvokedUpdates([
'module_a_post_update_a',
]);
}
/**
* Tests filter out invoked updates by extension.
*/
public function testFilterOutInvokedUpdatesByExtension() : void {
$this->setupBasicExtensions();
$key_value = $this->prophesize(KeyValueStoreInterface::class);
$key_value->get('existing_updates', [])
->willReturn([
'module_a_post_update_b',
'module_a_post_update_a',
'module_b_post_update_a',
'theme_d_post_update_c',
])
->shouldBeCalledTimes(1);
$key_value->set('existing_updates', [
'module_b_post_update_a',
'theme_d_post_update_c',
])
->willReturn(NULL)
->shouldBeCalledTimes(1);
$key_value = $key_value->reveal();
$theme_handler = $this->prophesize(ThemeHandlerInterface::class);
$theme_handler->listInfo()
->willReturn([
'theme_d' => [
'type' => 'theme',
'pathname' => 'core/themes/theme_d/theme_d.info.yml',
],
]);
$theme_handler = $theme_handler->reveal();
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
'module_a' => [
'type' => 'module',
'pathname' => 'core/modules/module_a/module_a.info.yml',
'filename' => 'module_a.module',
],
'module_b' => [
'type' => 'module',
'pathname' => 'core/modules/module_b/module_b.info.yml',
'filename' => 'module_b.module',
],
], $key_value, $theme_handler, 'post_update');
$update_registry->filterOutInvokedUpdatesByExtension('module_a');
}
/**
* Tests get pending custom update functions.
*
* @legacy-covers ::getPendingUpdateFunctions
*/
public function testGetPendingCustomUpdateFunctions() : void {
// Set up a simplified module structure with custom update hooks.
$info_a = <<<'EOS'
type: module
name: Module A
core_version_requirement: '*'
EOS;
$info_d = <<<'EOS'
type: theme
name: Theme D
core_version_requirement: '*'
EOS;
$module_a = <<<'EOS'
<?php
/**
* Module A update A.
*/
function module_a_custom_update_a() {
}
EOS;
$theme_d = <<<'EOS'
<?php
/**
* Theme D update B.
*/
function theme_d_custom_update_a() {
}
EOS;
vfsStream::setup('drupal');
vfsStream::create([
'sites' => [
'default' => [
'modules' => [
'module_a' => [
'module_a.custom_update.php' => $module_a,
'module_a.info.yml' => $info_a,
],
],
'themes' => [
'theme_d' => [
'theme_d.custom_update.php' => $theme_d,
'theme_d.info.yml' => $info_d,
],
],
],
],
]);
$key_value = $this->prophesize(KeyValueStoreInterface::class);
$key_value->get('existing_updates', [])
->willReturn([]);
$key_value = $key_value->reveal();
$theme_handler = $this->prophesize(ThemeHandlerInterface::class);
$theme_handler->listInfo()
->willReturn([
'theme_d' => [
'type' => 'theme',
'pathname' => 'core/themes/theme_d/theme_d.info.yml',
],
]);
$theme_handler = $theme_handler->reveal();
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
'module_a' => [
'type' => 'module',
'pathname' => 'core/modules/module_a/module_a.info.yml',
'filename' => 'module_a.module',
],
], $key_value, $theme_handler, 'custom_update');
// Themes are not supported.
$this->assertEquals([
'module_a_custom_update_a',
], $update_registry->getPendingUpdateFunctions());
}
}
Members
| Title Sort descending | Deprecated | Modifiers | Object type | Summary | Overriden Title |
|---|---|---|---|---|---|
| DrupalTestCaseTrait::checkErrorHandlerOnTearDown | public | function | Checks the test error handler after test execution. | ||
| ExpectDeprecationTrait::expectDeprecation | Deprecated | public | function | Adds an expected deprecation. | |
| ExpectDeprecationTrait::regularExpressionForFormatDescription | private | function | |||
| RandomGeneratorTrait::getRandomGenerator | protected | function | Gets the random generator for the utility methods. | ||
| RandomGeneratorTrait::randomMachineName | protected | function | Generates a unique random string containing letters and numbers. | ||
| RandomGeneratorTrait::randomObject | public | function | Generates a random PHP object. | ||
| RandomGeneratorTrait::randomString | public | function | Generates a pseudo-random string of ASCII characters of codes 32 to 126. | ||
| UnitTestCase::$root | protected | property | The app root. | ||
| UnitTestCase::getClassResolverStub | protected | function | Returns a stub class resolver. | ||
| UnitTestCase::getConfigFactoryStub | public | function | Returns a stub config factory that behaves according to the passed array. | ||
| UnitTestCase::getContainerWithCacheTagsInvalidator | protected | function | Sets up a container with a cache tags invalidator. | ||
| UnitTestCase::getStringTranslationStub | public | function | Returns a stub translation manager that just returns the passed string. | ||
| UnitTestCase::setDebugDumpHandler | public static | function | Registers the dumper CLI handler when the DebugDump extension is enabled. | ||
| UnitTestCase::setupMockIterator | protected | function | Set up a traversable class mock to return specific items when iterated. | ||
| UpdateRegistryTest::setUp | protected | function | Overrides UnitTestCase::setUp | ||
| UpdateRegistryTest::setupBasicExtensions | protected | function | Sets up some extensions with some update functions. | ||
| UpdateRegistryTest::testFilterOutInvokedUpdatesByExtension | public | function | Tests filter out invoked updates by extension. | ||
| UpdateRegistryTest::testGetPendingCustomUpdateFunctions | public | function | Tests get pending custom update functions. | ||
| UpdateRegistryTest::testGetPendingUpdateFunctionsExistingUpdates | public | function | Tests get pending update functions existing updates. | ||
| UpdateRegistryTest::testGetPendingUpdateFunctionsNoExistingUpdates | public | function | Tests get pending update functions no existing updates. | ||
| UpdateRegistryTest::testGetPendingUpdateFunctionsWithLoadedModulesButNotEnabled | public | function | Tests get pending update functions with loaded modules but not enabled. | ||
| UpdateRegistryTest::testGetPendingUpdateInformation | public | function | Tests get pending update information. | ||
| UpdateRegistryTest::testGetPendingUpdateInformationWithExistingUpdates | public | function | Tests get pending update information with existing updates. | ||
| UpdateRegistryTest::testGetPendingUpdateInformationWithRemovedUpdates | public | function | Tests get pending update information with removed updates. | ||
| UpdateRegistryTest::testGetUpdateFunctions | public | function | Tests get update functions. | ||
| UpdateRegistryTest::testRegisterInvokedUpdatesWithExistingUpdates | public | function | Tests register invoked updates with existing updates. | ||
| UpdateRegistryTest::testRegisterInvokedUpdatesWithMultiple | public | function | Tests register invoked updates with multiple. | ||
| UpdateRegistryTest::testRegisterInvokedUpdatesWithoutExistingUpdates | public | function | Tests register invoked updates without existing updates. |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.