From cc6885bde6e2b508cb28bbc891a724d50897a7c3 Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Mon, 4 Jul 2016 12:55:53 +0100
Subject: [PATCH] Issue #2755843 by alexpott, xjm: The order in which config is
 saved affects dependency calculations

---
 .../optional/rest.resource.entity.node.yml    |  12 +-
 .../KernelTests/Config/DefaultConfigTest.php  | 107 +++++++++++++-----
 2 files changed, 86 insertions(+), 33 deletions(-)

diff --git a/core/modules/rest/config/optional/rest.resource.entity.node.yml b/core/modules/rest/config/optional/rest.resource.entity.node.yml
index 0cf4d7898948..caeed781a0a7 100644
--- a/core/modules/rest/config/optional/rest.resource.entity.node.yml
+++ b/core/modules/rest/config/optional/rest.resource.entity.node.yml
@@ -1,3 +1,10 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - basic_auth
+    - hal
+    - node
 id: entity.node
 plugin_id: 'entity:node'
 granularity: method
@@ -22,8 +29,3 @@ configuration:
       - hal_json
     supported_auth:
       - basic_auth
-dependencies:
-  module:
-    - node
-    - basic_auth
-    - hal
diff --git a/core/tests/Drupal/KernelTests/Config/DefaultConfigTest.php b/core/tests/Drupal/KernelTests/Config/DefaultConfigTest.php
index e3c2aeb087eb..7b84b5979028 100644
--- a/core/tests/Drupal/KernelTests/Config/DefaultConfigTest.php
+++ b/core/tests/Drupal/KernelTests/Config/DefaultConfigTest.php
@@ -27,6 +27,21 @@ class DefaultConfigTest extends KernelTestBase {
    */
   public static $modules = ['system', 'user'];
 
+  /**
+   * The following config entries are changed on module install.
+   *
+   * Compare them does not make sense.
+   *
+   * @todo Figure out why simpletest.settings is not installed.
+   *
+   * @var array
+   */
+  public static $skippedConfig = [
+    'locale.settings' => ['path: '],
+    'syslog.settings' => ['facility: '],
+    'simpletest.settings' => TRUE,
+  ];
+
   /**
    * {@inheritdoc}
    */
@@ -49,45 +64,81 @@ protected function setUp() {
    * @dataProvider providerTestModuleConfig
    */
   public function testModuleConfig($module) {
+    // System and user are required in order to be able to install some of the
+    // other modules. Therefore they are put into static::$modules, which though
+    // doesn't install config files, so import those config files explicitly.
+    switch ($module) {
+      case 'system':
+      case 'user':
+        $this->installConfig([$module]);
+        break;
+    }
+
+    $module_path = drupal_get_path('module', $module) . '/';
+
     /** @var \Drupal\Core\Extension\ModuleInstallerInterface $module_installer */
     $module_installer = $this->container->get('module_installer');
-    /** @var \Drupal\Core\Config\StorageInterface $active_config_storage */
-    $active_config_storage = $this->container->get('config.storage');
-    /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
-    $config_manager = $this->container->get('config.manager');
 
     // @todo https://www.drupal.org/node/2308745 Rest has an implicit dependency
     //   on the Node module remove once solved.
     if (in_array($module, ['rest', 'hal'])) {
       $module_installer->install(['node']);
     }
-    $module_installer->install([$module]);
 
-    // System and user are required in order to be able to install some of the
-    // other modules. Therefore they are put into static::$modules, which though
-    // doesn't install config files, so import those config files explicitly.
-    switch ($module) {
-      case 'system':
-      case 'user':
-        $this->installConfig([$module]);
-        break;
+    // Work out any additional modules and themes that need installing to create
+    // and optional config.
+    $optional_config_storage = new FileStorage($module_path . InstallStorage::CONFIG_OPTIONAL_DIRECTORY, StorageInterface::DEFAULT_COLLECTION);
+    $modules_to_install = [$module];
+    $themes_to_install = [];
+    foreach ($optional_config_storage->listAll() as $config_name) {
+      $data = $optional_config_storage->read($config_name);
+      if (isset($data['dependencies']['module'])) {
+        $modules_to_install = array_merge($modules_to_install, $data['dependencies']['module']);
+      }
+      if (isset($data['dependencies']['theme'])) {
+        $themes_to_install = array_merge($themes_to_install, $data['dependencies']['theme']);
+      }
     }
+    $module_installer->install(array_unique($modules_to_install));
+    $this->container->get('theme_installer')->install($themes_to_install);
+
+    // Test configuration in the module's config/install directory.
+    $module_config_storage = new FileStorage($module_path . InstallStorage::CONFIG_INSTALL_DIRECTORY, StorageInterface::DEFAULT_COLLECTION);
+    $this->doTestsOnConfigStorage($module_config_storage);
+
+    // Test configuration in the module's config/optional directory.
+    $this->doTestsOnConfigStorage($optional_config_storage);
+  }
+
+  /**
+   * Tests that default config matches the installed config.
+   *
+   * @param \Drupal\Core\Config\StorageInterface $default_config_storage
+   *   The default config storage to test.
+   */
+  protected function doTestsOnConfigStorage(StorageInterface $default_config_storage) {
+    /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
+    $config_manager = $this->container->get('config.manager');
+
+    // Just connect directly to the config table so we don't need to worry about
+    // the cache layer.
+    $active_config_storage = $this->container->get('config.storage');
 
-    $default_install_path = drupal_get_path('module', $module) . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY;
-    $module_config_storage = new FileStorage($default_install_path, StorageInterface::DEFAULT_COLLECTION);
-
-    // The following config entries are changed on module install, so compare
-    // them doesn't make sense.
-    $skipped_config = [];
-    $skipped_config['locale.settings'][] = 'path: ';
-    $skipped_config['syslog.settings'][] = 'facility: ';
-    // @todo Figure out why simpletest.settings is not installed.
-    $skipped_config['simpletest.settings'] = TRUE;
-
-    // Compare the installed config with the one in the module directory.
-    foreach ($module_config_storage->listAll() as $config_name) {
-      $result = $config_manager->diff($module_config_storage, $active_config_storage, $config_name);
-      $this->assertConfigDiff($result, $config_name, $skipped_config);
+    foreach ($default_config_storage->listAll() as $config_name) {
+      if ($active_config_storage->exists($config_name)) {
+        // If it is a config entity re-save it. This ensures that any
+        // recalculation of dependencies does not cause config change.
+        if ($entity_type = $config_manager->getEntityTypeIdByName($config_name)) {
+          $entity_storage = $config_manager
+            ->getEntityManager()
+            ->getStorage($entity_type);
+          $id = $entity_storage->getIDFromConfigName($config_name, $entity_storage->getEntityType()
+            ->getConfigPrefix());
+          $entity_storage->load($id)->calculateDependencies()->save();
+        }
+        $result = $config_manager->diff($default_config_storage, $active_config_storage, $config_name);
+        $this->assertConfigDiff($result, $config_name, static::$skippedConfig);
+      }
     }
   }
 
-- 
GitLab