From 3ae3e525b003fec2a2d98b3005ee685a86c49498 Mon Sep 17 00:00:00 2001 From: Alex Pott Date: Thu, 11 Jul 2019 08:16:32 +0100 Subject: [PATCH] =?UTF-8?q?Issue=20#3047812=20by=20bircher,=20Krzysztof=20?= =?UTF-8?q?Doma=C5=84ski,=20alexpott,=20ricardoamaro,=20larowlan,=20boriss?= =?UTF-8?q?on=5F,=20mpotter:=20Add=20a=20Config=20Transformation=20event?= =?UTF-8?q?=20dispatching=20during=20config=20import=20and=20export?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config_environment.module | 9 + .../config_environment.routing.yml | 31 ++++ .../config_environment.services.yml | 13 ++ .../src/Controller/ConfigController.php | 47 ++++++ .../src/Core/Config/ConfigEvents.php | 79 +++++++++ .../src/Core/Config/ExportStorageManager.php | 115 +++++++++++++ .../Core/Config/ImportStorageTransformer.php | 82 +++++++++ .../src/Core/Config/ManagedStorage.php | 157 ++++++++++++++++++ .../Core/Config/StorageManagerInterface.php | 24 +++ .../src/Core/Config/StorageTransformEvent.php | 52 ++++++ .../src/Form/ConfigSync.php | 48 ++++++ .../config_transformer_test.info.yml | 10 ++ .../config_transformer_test.services.yml | 6 + .../src/EventSubscriber.php | 102 ++++++++++++ .../TransformedConfigExportImportUITest.php | 100 +++++++++++ .../Core/Config/ExportStorageManagerTest.php | 62 +++++++ .../Config/ImportStorageTransformerTest.php | 63 +++++++ .../Config/Storage/ManagedStorageTest.php | 77 +++++++++ 18 files changed, 1077 insertions(+) create mode 100644 core/modules/config_environment/config_environment.routing.yml create mode 100644 core/modules/config_environment/config_environment.services.yml create mode 100644 core/modules/config_environment/src/Controller/ConfigController.php create mode 100644 core/modules/config_environment/src/Core/Config/ConfigEvents.php create mode 100644 core/modules/config_environment/src/Core/Config/ExportStorageManager.php create mode 100644 core/modules/config_environment/src/Core/Config/ImportStorageTransformer.php create mode 100644 core/modules/config_environment/src/Core/Config/ManagedStorage.php create mode 100644 core/modules/config_environment/src/Core/Config/StorageManagerInterface.php create mode 100644 core/modules/config_environment/src/Core/Config/StorageTransformEvent.php create mode 100644 core/modules/config_environment/src/Form/ConfigSync.php create mode 100644 core/modules/config_environment/tests/config_transformer_test/config_transformer_test.info.yml create mode 100644 core/modules/config_environment/tests/config_transformer_test/config_transformer_test.services.yml create mode 100644 core/modules/config_environment/tests/config_transformer_test/src/EventSubscriber.php create mode 100644 core/modules/config_environment/tests/src/Functional/TransformedConfigExportImportUITest.php create mode 100644 core/modules/config_environment/tests/src/Kernel/Core/Config/ExportStorageManagerTest.php create mode 100644 core/modules/config_environment/tests/src/Kernel/Core/Config/ImportStorageTransformerTest.php create mode 100644 core/modules/config_environment/tests/src/Kernel/Core/Config/Storage/ManagedStorageTest.php diff --git a/core/modules/config_environment/config_environment.module b/core/modules/config_environment/config_environment.module index b54b3dc632f1..4737f74dba99 100644 --- a/core/modules/config_environment/config_environment.module +++ b/core/modules/config_environment/config_environment.module @@ -5,6 +5,15 @@ * Allows site administrators to modify environment configuration. */ +// Set class aliases for the classes that will go into core when we are in beta. +// See the experimental modules policy https://www.drupal.org/core/experimental +// @todo: remove class aliases in #2991683 +@class_alias('Drupal\config_environment\Core\Config\StorageTransformEvent', 'Drupal\Core\Config\StorageTransformEvent'); +@class_alias('Drupal\config_environment\Core\Config\ManagedStorage', 'Drupal\Core\Config\ManagedStorage'); +@class_alias('Drupal\config_environment\Core\Config\StorageManagerInterface', 'Drupal\Core\Config\StorageManagerInterface'); +@class_alias('Drupal\config_environment\Core\Config\ExportStorageManager', 'Drupal\Core\Config\ExportStorageManager'); +@class_alias('Drupal\config_environment\Core\Config\ImportStorageTransformer', 'Drupal\Core\Config\ImportStorageTransformer'); + use Drupal\Core\Routing\RouteMatchInterface; /** diff --git a/core/modules/config_environment/config_environment.routing.yml b/core/modules/config_environment/config_environment.routing.yml new file mode 100644 index 000000000000..7c9edeac2126 --- /dev/null +++ b/core/modules/config_environment/config_environment.routing.yml @@ -0,0 +1,31 @@ +# @todo: Stop taking over config module routes in #2991683 +config.sync: + path: '/admin/config/development/configuration' + defaults: + _form: '\Drupal\config_environment\Form\ConfigSync' + _title: 'Synchronize' + requirements: + _permission: 'synchronize configuration' + +config.diff: + path: '/admin/config/development/configuration/sync/diff/{source_name}/{target_name}' + defaults: + _controller: '\Drupal\config_environment\Controller\ConfigController::diff' + target_name: NULL + requirements: + _permission: 'synchronize configuration' + +config.diff_collection: + path: '/admin/config/development/configuration/sync/diff_collection/{collection}/{source_name}/{target_name}' + defaults: + _controller: '\Drupal\config_environment\Controller\ConfigController::diff' + target_name: NULL + requirements: + _permission: 'synchronize configuration' + +config.export_download: + path: '/admin/config/development/configuration/full/export-download' + defaults: + _controller: '\Drupal\config_environment\Controller\ConfigController::downloadExport' + requirements: + _permission: 'export configuration' diff --git a/core/modules/config_environment/config_environment.services.yml b/core/modules/config_environment/config_environment.services.yml new file mode 100644 index 000000000000..6243c14ee1c5 --- /dev/null +++ b/core/modules/config_environment/config_environment.services.yml @@ -0,0 +1,13 @@ +services: + # @todo: Move this back to core services in #2991683 + config.import_transformer: + class: Drupal\config_environment\Core\Config\ImportStorageTransformer + arguments: ['@event_dispatcher', '@database'] + config.storage.export: + class: Drupal\config_environment\Core\Config\ManagedStorage + arguments: ['@config.storage.export.manager'] + config.storage.export.manager: + class: Drupal\config_environment\Core\Config\ExportStorageManager + arguments: ['@config.storage', '@state', '@database', '@event_dispatcher'] + tags: + - { name: event_subscriber } diff --git a/core/modules/config_environment/src/Controller/ConfigController.php b/core/modules/config_environment/src/Controller/ConfigController.php new file mode 100644 index 000000000000..92cb3fa9a612 --- /dev/null +++ b/core/modules/config_environment/src/Controller/ConfigController.php @@ -0,0 +1,47 @@ +importTransformer = $container->get('config.import_transformer'); + $controller->syncStorage = $container->get('config.storage.sync'); + + return $controller; + } + + /** + * {@inheritdoc} + */ + public function diff($source_name, $target_name = NULL, $collection = NULL) { + $this->sourceStorage = $this->importTransformer->transform($this->syncStorage); + + return parent::diff($source_name, $target_name, $collection); + } + +} diff --git a/core/modules/config_environment/src/Core/Config/ConfigEvents.php b/core/modules/config_environment/src/Core/Config/ConfigEvents.php new file mode 100644 index 000000000000..bc91eec462bd --- /dev/null +++ b/core/modules/config_environment/src/Core/Config/ConfigEvents.php @@ -0,0 +1,79 @@ +getStorage(); + * @endcode + * + * This event is also fired when just viewing the difference of configuration + * to be imported independently of whether the import takes place or not. + * Use the \Drupal\Core\Config\ConfigEvents::IMPORT event to subscribe to the + * import having taken place. + * + * @Event + * + * @see \Drupal\Core\Config\StorageTransformEvent + * @see \Drupal\Core\Config\ConfigEvents::STORAGE_TRANSFORM_EXPORT + * + * @var string + */ + const STORAGE_TRANSFORM_IMPORT = 'config.transform.import'; + + /** + * Name of the event fired when the export storage is used. + * + * This event allows subscribers to modify the configuration which is about to + * be exported. The event listener method receives a + * \Drupal\Core\Config\StorageTransformEvent instance. This event contains a + * config storage which subscribers can interact with and which will finally + * be used to export the configuration from. + * + * @code + * $storage = $event->getStorage(); + * @endcode + * + * Typically subscribers will want to perform the reverse operation on the + * storage than for \Drupal\Core\Config\ConfigEvents::STORAGE_TRANSFORM_IMPORT + * to make sure successive exports and imports yield no difference. + * + * @Event + * + * @see \Drupal\Core\Config\StorageTransformEvent + * @see \Drupal\Core\Config\ConfigEvents::STORAGE_TRANSFORM_IMPORT + * + * @var string + */ + const STORAGE_TRANSFORM_EXPORT = 'config.transform.export'; + +} diff --git a/core/modules/config_environment/src/Core/Config/ExportStorageManager.php b/core/modules/config_environment/src/Core/Config/ExportStorageManager.php new file mode 100644 index 000000000000..3385b84d39ca --- /dev/null +++ b/core/modules/config_environment/src/Core/Config/ExportStorageManager.php @@ -0,0 +1,115 @@ +active = $active; + $this->state = $state; + $this->eventDispatcher = $event_dispatcher; + // The point of this service is to provide the storage and dispatch the + // event when needed, so the storage itself can not be a service. + $this->storage = new DatabaseStorage($connection, 'config_export'); + } + + /** + * {@inheritdoc} + */ + public function getStorage() { + if ($this->state->get(self::NEEDS_REBUILD_KEY, TRUE)) { + self::replaceStorageContents($this->active, $this->storage); + // @todo: Use ConfigEvents::STORAGE_TRANSFORM_EXPORT in #2991683 + $this->eventDispatcher->dispatch('config.transform.export', new StorageTransformEvent($this->storage)); + $this->state->set(self::NEEDS_REBUILD_KEY, FALSE); + } + + return new ReadOnlyStorage($this->storage); + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + $events[ConfigEvents::SAVE][] = ['onConfigChange', 0]; + $events[ConfigEvents::DELETE][] = ['onConfigChange', 0]; + $events[ConfigEvents::RENAME][] = ['onConfigChange', 0]; + return $events; + } + + /** + * Set the flag in state that the export storage is out of date. + */ + public function onConfigChange() { + if (!$this->state->get(self::NEEDS_REBUILD_KEY, FALSE)) { + $this->state->set(self::NEEDS_REBUILD_KEY, TRUE); + } + } + +} diff --git a/core/modules/config_environment/src/Core/Config/ImportStorageTransformer.php b/core/modules/config_environment/src/Core/Config/ImportStorageTransformer.php new file mode 100644 index 000000000000..639e982b741b --- /dev/null +++ b/core/modules/config_environment/src/Core/Config/ImportStorageTransformer.php @@ -0,0 +1,82 @@ +eventDispatcher = $event_dispatcher; + $this->connection = $connection; + } + + /** + * Transform the storage to be imported from. + * + * An import transformation is done before the config importer uses the + * storage to synchronize the configuration. The transformation is also + * done for displaying differences to review imports. + * Importing in this context means the active drupal configuration is changed + * with the ConfigImporter which may or may not be as part of the config + * synchronization. + * + * @param \Drupal\Core\Config\StorageInterface $storage + * The storage to transform for importing from it. + * + * @return \Drupal\Core\Config\StorageInterface + * The transformed storage ready to be imported from. + */ + public function transform(StorageInterface $storage) { + // We use a database storage to reduce the memory requirement. + $mutable = new DatabaseStorage($this->connection, 'config_import'); + + // Copy the sync configuration to the created mutable storage. + self::replaceStorageContents($storage, $mutable); + + // Dispatch the event so that event listeners can alter the configuration. + // @todo: Use ConfigEvents::STORAGE_TRANSFORM_IMPORT in #2991683 + $this->eventDispatcher->dispatch('config.transform.import', new StorageTransformEvent($mutable)); + + // Return the storage with the altered configuration. + return $mutable; + } + +} diff --git a/core/modules/config_environment/src/Core/Config/ManagedStorage.php b/core/modules/config_environment/src/Core/Config/ManagedStorage.php new file mode 100644 index 000000000000..24f7eb52f98f --- /dev/null +++ b/core/modules/config_environment/src/Core/Config/ManagedStorage.php @@ -0,0 +1,157 @@ +manager = $manager; + } + + /** + * {@inheritdoc} + */ + public function exists($name) { + return $this->getStorage()->exists($name); + } + + /** + * {@inheritdoc} + */ + public function read($name) { + return $this->getStorage()->read($name); + } + + /** + * {@inheritdoc} + */ + public function readMultiple(array $names) { + return $this->getStorage()->readMultiple($names); + } + + /** + * {@inheritdoc} + */ + public function write($name, array $data) { + return $this->getStorage()->write($name, $data); + } + + /** + * {@inheritdoc} + */ + public function delete($name) { + return $this->getStorage()->delete($name); + } + + /** + * {@inheritdoc} + */ + public function rename($name, $new_name) { + return $this->getStorage()->rename($name, $new_name); + } + + /** + * {@inheritdoc} + */ + public function encode($data) { + return $this->getStorage()->encode($data); + } + + /** + * {@inheritdoc} + */ + public function decode($raw) { + return $this->getStorage()->decode($raw); + } + + /** + * {@inheritdoc} + */ + public function listAll($prefix = '') { + return $this->getStorage()->listAll($prefix); + } + + /** + * {@inheritdoc} + */ + public function deleteAll($prefix = '') { + return $this->getStorage()->deleteAll($prefix); + } + + /** + * {@inheritdoc} + */ + public function createCollection($collection) { + // We return the collection directly. + // This means that the collection will not be an instance of ManagedStorage + // But this doesn't matter because the storage is retrieved from the + // manager only the first time it is accessed. + return $this->getStorage()->createCollection($collection); + } + + /** + * {@inheritdoc} + */ + public function getAllCollectionNames() { + return $this->getStorage()->getAllCollectionNames(); + } + + /** + * {@inheritdoc} + */ + public function getCollectionName() { + return $this->getStorage()->getCollectionName(); + } + + /** + * Get the decorated storage from the manager if necessary. + * + * @return \Drupal\Core\Config\StorageInterface + * The config storage. + */ + protected function getStorage() { + // Get the storage from the manager the first time it is needed. + if (!isset($this->storage)) { + $this->storage = $this->manager->getStorage(); + } + + return $this->storage; + } + +} diff --git a/core/modules/config_environment/src/Core/Config/StorageManagerInterface.php b/core/modules/config_environment/src/Core/Config/StorageManagerInterface.php new file mode 100644 index 000000000000..042d29de82cc --- /dev/null +++ b/core/modules/config_environment/src/Core/Config/StorageManagerInterface.php @@ -0,0 +1,24 @@ +storage = $storage; + } + + /** + * Returns the mutable storage ready to be read from and written to. + * + * @return \Drupal\Core\Config\StorageInterface + * The config storage. + */ + public function getStorage() { + return $this->storage; + } + +} diff --git a/core/modules/config_environment/src/Form/ConfigSync.php b/core/modules/config_environment/src/Form/ConfigSync.php new file mode 100644 index 000000000000..47b04c0ad5cc --- /dev/null +++ b/core/modules/config_environment/src/Form/ConfigSync.php @@ -0,0 +1,48 @@ +importTransformer = $container->get('config.import_transformer'); + $form->originalSyncStorage = $form->syncStorage; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state) { + $this->syncStorage = $this->importTransformer->transform($this->originalSyncStorage); + + return parent::buildForm($form, $form_state); + } + +} diff --git a/core/modules/config_environment/tests/config_transformer_test/config_transformer_test.info.yml b/core/modules/config_environment/tests/config_transformer_test/config_transformer_test.info.yml new file mode 100644 index 000000000000..3fbdd561a0a8 --- /dev/null +++ b/core/modules/config_environment/tests/config_transformer_test/config_transformer_test.info.yml @@ -0,0 +1,10 @@ +# @todo: Move this test module under the config module in #2991683. +name: 'Configuration Storage Transformer Test' +type: module +package: Testing +version: VERSION +core: 8.x +dependencies: + - drupal:config +# @todo: remove dependency on config_environment in #2991683. + - drupal:config_environment diff --git a/core/modules/config_environment/tests/config_transformer_test/config_transformer_test.services.yml b/core/modules/config_environment/tests/config_transformer_test/config_transformer_test.services.yml new file mode 100644 index 000000000000..05b9fccb8a0b --- /dev/null +++ b/core/modules/config_environment/tests/config_transformer_test/config_transformer_test.services.yml @@ -0,0 +1,6 @@ +services: + config_transformer_test.event_subscriber: + class: Drupal\config_transformer_test\EventSubscriber + arguments: ['@config.storage', '@config.storage.sync'] + tags: + - { name: event_subscriber } diff --git a/core/modules/config_environment/tests/config_transformer_test/src/EventSubscriber.php b/core/modules/config_environment/tests/config_transformer_test/src/EventSubscriber.php new file mode 100644 index 000000000000..72c8516087de --- /dev/null +++ b/core/modules/config_environment/tests/config_transformer_test/src/EventSubscriber.php @@ -0,0 +1,102 @@ +active = $active; + $this->sync = $sync; + } + + /** + * The storage is transformed for importing. + * + * In this transformation we ignore the site name from the sync storage and + * set it always to the currently active site name with an additional string + * so that there will always be something to import. + * Do not do this outside of tests. + * + * @param \Drupal\Core\Config\StorageTransformEvent $event + * The config storage transform event. + */ + public function onImportTransform(StorageTransformEvent $event) { + $storage = $event->getStorage(); + $site = $storage->read('system.site'); + // Only change something if the sync storage has data. + if (!empty($site)) { + // Add "Arrr" to the site name. Because pirates! + // The site name which is in the sync directory will be ignored. + $current = $this->active->read('system.site'); + $site['name'] = $current['name'] . ' Arrr'; + $storage->write('system.site', $site); + } + } + + /** + * The storage is transformed for exporting. + * + * In this transformation we ignore the site slogan from the site if the sync + * storage has it. Just export it again with an additional string so that + * there will always be something new exported. + * Do not do this outside of tests. + * + * @param \Drupal\Core\Config\StorageTransformEvent $event + * The config storage transform event. + */ + public function onExportTransform(StorageTransformEvent $event) { + $sync = $this->sync->read('system.site'); + // Only change something if the sync storage has data. + if (!empty($sync)) { + $storage = $event->getStorage(); + $site = $storage->read('system.site'); + // Add "Arrr" to the site slogan. Because pirates! + // The active slogan will be ignored. + $site['slogan'] = $sync['slogan'] . ' Arrr'; + $storage->write('system.site', $site); + } + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + // @todo: use class constants when they get added in #2991683 + $events['config.transform.import'][] = ['onImportTransform']; + $events['config.transform.export'][] = ['onExportTransform']; + return $events; + } + +} diff --git a/core/modules/config_environment/tests/src/Functional/TransformedConfigExportImportUITest.php b/core/modules/config_environment/tests/src/Functional/TransformedConfigExportImportUITest.php new file mode 100644 index 000000000000..6de7b7fbb3d3 --- /dev/null +++ b/core/modules/config_environment/tests/src/Functional/TransformedConfigExportImportUITest.php @@ -0,0 +1,100 @@ +webUser = $this->drupalCreateUser($permissions); + $this->drupalLogin($this->webUser); + + // Start off with the sync storage being the same as the active storage. + $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync')); + } + + /** + * Tests a simple site export import case. + */ + public function testTransformedExportImport() { + // After installation there is no snapshot but a new site name. + $this->drupalGet('admin/config/development/configuration'); + $this->assertNoText('Warning message'); + $this->assertNoText('There are no configuration changes to import.'); + + // Tests changes of system.site. + $this->drupalGet('admin/config/development/configuration/sync/diff/system.site'); + $this->assertText('name: Drupal'); + $this->assertText(Html::escape("name: 'Drupal Arrr'")); + + // Add a slogan. + $originalSlogan = $this->config('system.site')->get('slogan'); + $this->assertEmpty($originalSlogan); + $newSlogan = $this->randomMachineName(16); + $this->assertNotEqual($newSlogan, $originalSlogan); + $this->config('system.site') + ->set('slogan', $newSlogan) + ->save(); + $this->assertEqual($this->config('system.site')->get('slogan'), $newSlogan); + + // Tests changes of system.site. + $this->drupalGet('admin/config/development/configuration/sync/diff/system.site'); + $this->assertText(Html::escape("slogan: ''")); + $this->assertText(Html::escape("slogan: $newSlogan")); + + // Export the configuration. + $this->drupalPostForm('admin/config/development/configuration/full/export', [], 'Export'); + $tarball = $this->getSession()->getPage()->getContent(); + + // Import the configuration from the tarball. + $filename = 'temporary://' . $this->randomMachineName(); + file_put_contents($filename, $tarball); + $this->drupalPostForm('admin/config/development/configuration/full/import', ['files[import_tarball]' => $filename], 'Upload'); + + // Assert the new name and slogan. + $this->drupalGet('admin/config/development/configuration/sync/diff/system.site'); + $this->assertText(Html::escape("name: 'Drupal Arrr'")); + $this->assertText(Html::escape("slogan: '$originalSlogan Arrr'")); + $this->assertEqual($this->config('system.site')->get('name'), 'Drupal'); + $this->assertEqual($this->config('system.site')->get('slogan'), $newSlogan); + + // Sync the configuration. + $this->drupalPostForm('admin/config/development/configuration', [], 'Import all'); + $this->assertEqual($this->config('system.site')->get('name'), 'Drupal Arrr'); + $this->assertEqual($this->config('system.site')->get('slogan'), $originalSlogan . " Arrr"); + + // Assert that the event was dispatched again on the new config. + $this->drupalGet('admin/config/development/configuration/sync/diff/system.site'); + $this->assertText(Html::escape("name: 'Drupal Arrr Arrr'")); + } + +} diff --git a/core/modules/config_environment/tests/src/Kernel/Core/Config/ExportStorageManagerTest.php b/core/modules/config_environment/tests/src/Kernel/Core/Config/ExportStorageManagerTest.php new file mode 100644 index 000000000000..ab6e30997683 --- /dev/null +++ b/core/modules/config_environment/tests/src/Kernel/Core/Config/ExportStorageManagerTest.php @@ -0,0 +1,62 @@ +installConfig(['system']); + } + + /** + * Test getting the export storage. + */ + public function testGetStorage() { + // Get the raw system.site config and set it in the sync storage. + $rawConfig = $this->config('system.site')->getRawData(); + $this->container->get('config.storage.sync')->write('system.site', $rawConfig); + + $storage = $this->container->get('config.storage.export.manager')->getStorage(); + $exported = $storage->read('system.site'); + // The test subscriber adds "Arrr" to the slogan of the sync config. + $this->assertEquals($rawConfig['name'], $exported['name']); + $this->assertEquals($rawConfig['slogan'] . ' Arrr', $exported['slogan']); + + // Save the config to trigger the rebuild. + $this->config('system.site') + ->set('name', 'New name') + ->set('slogan', 'New slogan') + ->save(); + + // Get the storage again. + $storage = $this->container->get('config.storage.export.manager')->getStorage(); + $exported = $storage->read('system.site'); + // The test subscriber adds "Arrr" to the slogan of the sync config. + $this->assertEquals('New name', $exported['name']); + $this->assertEquals($rawConfig['slogan'] . ' Arrr', $exported['slogan']); + } + +} diff --git a/core/modules/config_environment/tests/src/Kernel/Core/Config/ImportStorageTransformerTest.php b/core/modules/config_environment/tests/src/Kernel/Core/Config/ImportStorageTransformerTest.php new file mode 100644 index 000000000000..14a0f0526040 --- /dev/null +++ b/core/modules/config_environment/tests/src/Kernel/Core/Config/ImportStorageTransformerTest.php @@ -0,0 +1,63 @@ +installConfig(['system']); + } + + /** + * Test the import transformation. + */ + public function testTransform() { + // Get the raw system.site config and set it in the sync storage. + $rawConfig = $this->config('system.site')->getRawData(); + + $storage = new MemoryStorage(); + $this->copyConfig($this->container->get('config.storage'), $storage); + + $import = $this->container->get('config.import_transformer')->transform($storage); + $config = $import->read('system.site'); + // The test subscriber always adds "Arrr" to the current site name. + $this->assertEquals($rawConfig['name'] . ' Arrr', $config['name']); + $this->assertEquals($rawConfig['slogan'], $config['slogan']); + + // Update the site config in the storage to test a second transformation. + $config['name'] = 'New name'; + $config['slogan'] = 'New slogan'; + $storage->write('system.site', $config); + + $import = $this->container->get('config.import_transformer')->transform($storage); + $config = $import->read('system.site'); + // The test subscriber always adds "Arrr" to the current site name. + $this->assertEquals($rawConfig['name'] . ' Arrr', $config['name']); + $this->assertEquals('New slogan', $config['slogan']); + } + +} diff --git a/core/modules/config_environment/tests/src/Kernel/Core/Config/Storage/ManagedStorageTest.php b/core/modules/config_environment/tests/src/Kernel/Core/Config/Storage/ManagedStorageTest.php new file mode 100644 index 000000000000..1b6ae9a72786 --- /dev/null +++ b/core/modules/config_environment/tests/src/Kernel/Core/Config/Storage/ManagedStorageTest.php @@ -0,0 +1,77 @@ +storage = new ManagedStorage($this); + // ::listAll() verifications require other configuration data to exist. + $this->storage->write('system.performance', []); + } + + /** + * {@inheritdoc} + */ + protected function read($name) { + return $this->storage->read($name); + } + + /** + * {@inheritdoc} + */ + protected function insert($name, $data) { + $this->storage->write($name, $data); + } + + /** + * {@inheritdoc} + */ + protected function update($name, $data) { + $this->storage->write($name, $data); + } + + /** + * {@inheritdoc} + */ + protected function delete($name) { + $this->storage->delete($name); + } + + /** + * {@inheritdoc} + */ + public function testInvalidStorage() { + $this->markTestSkipped('ManagedStorage cannot be invalid.'); + } + +}