diff --git a/core/core.services.yml b/core/core.services.yml
index 7608878..a6f6aea 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -1551,7 +1551,7 @@ services:
       - { name: needs_destruction }
   library.discovery.parser:
     class: Drupal\Core\Asset\LibraryDiscoveryParser
-    arguments: ['@app.root', '@module_handler', '@theme.manager']
+    arguments: ['@app.root', '@module_handler', '@theme.manager', '@theme_handler']
   library.dependency_resolver:
     class: Drupal\Core\Asset\LibraryDependencyResolver
     arguments: ['@library.discovery']
diff --git a/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php b/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php
index 91f702f..7f0a1d4 100644
--- a/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php
+++ b/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Theme\ThemeManagerInterface;
 use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Extension\ThemeHandlerInterface;
 
 /**
  * Parses library files to get extension data.
@@ -32,6 +33,13 @@ class LibraryDiscoveryParser {
   protected $themeManager;
 
   /**
+   * The theme handler.
+   *
+   * @var \Drupal\Core\Extension\ThemeHandlerInterface
+   */
+  protected $themeHandler;
+
+  /**
    * The app root.
    *
    * @var string
@@ -47,11 +55,14 @@ class LibraryDiscoveryParser {
    *   The module handler.
    * @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
    *   The theme manager.
+   * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
+   *   The theme handler.
    */
-  public function __construct($root, ModuleHandlerInterface $module_handler, ThemeManagerInterface $theme_manager) {
+  public function __construct($root, ModuleHandlerInterface $module_handler, ThemeManagerInterface $theme_manager, ThemeHandlerInterface $theme_handler) {
     $this->root = $root;
     $this->moduleHandler = $module_handler;
     $this->themeManager = $theme_manager;
+    $this->themeHandler = $theme_handler;
   }
 
   /**
@@ -63,6 +74,8 @@ public function __construct($root, ModuleHandlerInterface $module_handler, Theme
    * @return array
    *   All library definitions of the passed extension.
    *
+   * @throws \AssertionError
+   *   When the extension (theme, module, library) is not available
    * @throws \Drupal\Core\Asset\Exception\IncompleteLibraryDefinitionException
    *   Thrown when a library has no js/css/setting.
    * @throws \UnexpectedValueException
@@ -79,9 +92,10 @@ public function buildByExtension($extension) {
       if ($this->moduleHandler->moduleExists($extension)) {
         $extension_type = 'module';
       }
-      else {
+      elseif ($this->themeHandler->themeExists($extension)) {
         $extension_type = 'theme';
       }
+      assert(isset($extension_type), sprintf('The extension "%s" is not available.', $extension));
       $path = $this->drupalGetPath($extension_type, $extension);
     }
 
diff --git a/core/modules/config/src/Tests/CacheabilityMetadataConfigOverrideIntegrationTest.php b/core/modules/config/src/Tests/CacheabilityMetadataConfigOverrideIntegrationTest.php
deleted file mode 100644
index 3ef0754..0000000
--- a/core/modules/config/src/Tests/CacheabilityMetadataConfigOverrideIntegrationTest.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-
-namespace Drupal\config\Tests;
-
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Tests if configuration overrides correctly affect cacheability metadata.
- *
- * @group config
- */
-class CacheabilityMetadataConfigOverrideIntegrationTest extends WebTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = [
-    'block_test',
-    'config_override_integration_test',
-  ];
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    // @todo If our block does not contain any content then the cache context
-    //   is not bubbling up and the test fails. Remove this line once the cache
-    //   contexts are properly set. See https://www.drupal.org/node/2529980.
-    \Drupal::state()->set('block_test.content', 'Needs to have some content');
-
-    $this->drupalLogin($this->drupalCreateUser());
-  }
-
-  /**
-   * Tests if config overrides correctly set cacheability metadata.
-   */
-  public function testConfigOverride() {
-    // Check the default (disabled) state of the cache context. The block label
-    // should not be overridden.
-    $this->drupalGet('<front>');
-    $this->assertNoText('Overridden block label');
-
-    // Both the cache context and tag should be present.
-    $this->assertCacheContext('config_override_integration_test');
-    $this->assertCacheTag('config_override_integration_test_tag');
-
-    // Flip the state of the cache context. The block label should now be
-    // overridden.
-    \Drupal::state()->set('config_override_integration_test.enabled', TRUE);
-    $this->drupalGet('<front>');
-    $this->assertText('Overridden block label');
-
-    // Both the cache context and tag should still be present.
-    $this->assertCacheContext('config_override_integration_test');
-    $this->assertCacheTag('config_override_integration_test_tag');
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigEntityFormOverrideTest.php b/core/modules/config/src/Tests/ConfigEntityFormOverrideTest.php
deleted file mode 100644
index 41419b0..0000000
--- a/core/modules/config/src/Tests/ConfigEntityFormOverrideTest.php
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-
-namespace Drupal\config\Tests;
-
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Tests that config overrides do not bleed through in entity forms and lists.
- *
- * @group config
- */
-class ConfigEntityFormOverrideTest extends WebTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = ['config_test'];
-
-  /**
-   * Tests that overrides do not affect forms or listing screens.
-   */
-  public function testFormsWithOverrides() {
-    $this->drupalLogin($this->drupalCreateUser(['administer site configuration']));
-
-    $original_label = 'Default';
-    $overridden_label = 'Overridden label';
-    $edited_label = 'Edited label';
-
-    $config_test_storage = $this->container->get('entity.manager')->getStorage('config_test');
-
-    // Set up an override.
-    $settings['config']['config_test.dynamic.dotted.default']['label'] = (object) [
-      'value' => $overridden_label,
-      'required' => TRUE,
-    ];
-    $this->writeSettings($settings);
-
-    // Test that the overridden label is loaded with the entity.
-    $this->assertEqual($config_test_storage->load('dotted.default')->label(), $overridden_label);
-
-    // Test that the original label on the listing page is intact.
-    $this->drupalGet('admin/structure/config_test');
-    $this->assertText($original_label);
-    $this->assertNoText($overridden_label);
-
-    // Test that the original label on the editing page is intact.
-    $this->drupalGet('admin/structure/config_test/manage/dotted.default');
-    $elements = $this->xpath('//input[@name="label"]');
-    $this->assertIdentical((string) $elements[0]['value'], $original_label);
-    $this->assertNoText($overridden_label);
-
-    // Change to a new label and test that the listing now has the edited label.
-    $edit = [
-      'label' => $edited_label,
-    ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->drupalGet('admin/structure/config_test');
-    $this->assertNoText($overridden_label);
-    $this->assertText($edited_label);
-
-    // Test that the editing page now has the edited label.
-    $this->drupalGet('admin/structure/config_test/manage/dotted.default');
-    $elements = $this->xpath('//input[@name="label"]');
-    $this->assertIdentical((string) $elements[0]['value'], $edited_label);
-
-    // Test that the overridden label is still loaded with the entity.
-    $this->assertEqual($config_test_storage->load('dotted.default')->label(), $overridden_label);
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigEntityListTest.php b/core/modules/config/src/Tests/ConfigEntityListTest.php
deleted file mode 100644
index e9950ea..0000000
--- a/core/modules/config/src/Tests/ConfigEntityListTest.php
+++ /dev/null
@@ -1,278 +0,0 @@
-<?php
-
-namespace Drupal\config\Tests;
-
-use Drupal\simpletest\WebTestBase;
-use Drupal\config_test\Entity\ConfigTest;
-use Drupal\Core\Entity\EntityStorageInterface;
-
-/**
- * Tests the listing of configuration entities.
- *
- * @group config
- */
-class ConfigEntityListTest extends WebTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['block', 'config_test'];
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    // Delete the override config_test entity since it is not required by this
-    // test.
-    \Drupal::entityManager()->getStorage('config_test')->load('override')->delete();
-    $this->drupalPlaceBlock('local_actions_block');
-  }
-
-  /**
-   * Tests entity list builder methods.
-   */
-  public function testList() {
-    $controller = \Drupal::entityManager()->getListBuilder('config_test');
-
-    // Test getStorage() method.
-    $this->assertTrue($controller->getStorage() instanceof EntityStorageInterface, 'EntityStorage instance in storage.');
-
-    // Get a list of ConfigTest entities and confirm that it contains the
-    // ConfigTest entity provided by the config_test module.
-    // @see config_test.dynamic.dotted.default.yml
-    $list = $controller->load();
-    $this->assertEqual(count($list), 1, '1 ConfigTest entity found.');
-    $entity = $list['dotted.default'];
-    $this->assertTrue(!empty($entity), '"Default" ConfigTest entity ID found.');
-    $this->assertTrue($entity instanceof ConfigTest, '"Default" ConfigTest entity is an instance of ConfigTest.');
-
-    // Test getOperations() method.
-    $expected_operations = [
-      'edit' => [
-        'title' => t('Edit'),
-        'weight' => 10,
-        'url' => $entity->urlInfo(),
-      ],
-      'disable' => [
-        'title' => t('Disable'),
-        'weight' => 40,
-        'url' => $entity->urlInfo('disable'),
-      ],
-      'delete' => [
-        'title' => t('Delete'),
-        'weight' => 100,
-        'url' => $entity->urlInfo('delete-form'),
-      ],
-    ];
-
-    $actual_operations = $controller->getOperations($entity);
-    // Sort the operations to normalize link order.
-    uasort($actual_operations, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
-    $this->assertEqual($expected_operations, $actual_operations, 'The operations are identical.');
-
-    // Test buildHeader() method.
-    $expected_items = [
-      'label' => 'Label',
-      'id' => 'Machine name',
-      'operations' => 'Operations',
-    ];
-    $actual_items = $controller->buildHeader();
-    $this->assertEqual($expected_items, $actual_items, 'Return value from buildHeader matches expected.');
-
-    // Test buildRow() method.
-    $build_operations = $controller->buildOperations($entity);
-    $expected_items = [
-      'label' => 'Default',
-      'id' => 'dotted.default',
-      'operations' => [
-        'data' => $build_operations,
-      ],
-    ];
-    $actual_items = $controller->buildRow($entity);
-    $this->assertEqual($expected_items, $actual_items, 'Return value from buildRow matches expected.');
-    // Test sorting.
-    $storage = $controller->getStorage();
-    $entity = $storage->create([
-      'id' => 'alpha',
-      'label' => 'Alpha',
-      'weight' => 1,
-    ]);
-    $entity->save();
-    $entity = $storage->create([
-      'id' => 'omega',
-      'label' => 'Omega',
-      'weight' => 1,
-    ]);
-    $entity->save();
-    $entity = $storage->create([
-      'id' => 'beta',
-      'label' => 'Beta',
-      'weight' => 0,
-    ]);
-    $entity->save();
-    $list = $controller->load();
-    $this->assertIdentical(array_keys($list), ['beta', 'dotted.default', 'alpha', 'omega']);
-
-    // Test that config entities that do not support status, do not have
-    // enable/disable operations.
-    $controller = $this->container->get('entity.manager')
-      ->getListBuilder('config_test_no_status');
-
-    $list = $controller->load();
-    $entity = $list['default'];
-
-    // Test getOperations() method.
-    $expected_operations = [
-      'edit' => [
-        'title' => t('Edit'),
-        'weight' => 10,
-        'url' => $entity->urlInfo(),
-      ],
-      'delete' => [
-        'title' => t('Delete'),
-        'weight' => 100,
-        'url' => $entity->urlInfo('delete-form'),
-      ],
-    ];
-
-    $actual_operations = $controller->getOperations($entity);
-    // Sort the operations to normalize link order.
-    uasort($actual_operations, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
-    $this->assertEqual($expected_operations, $actual_operations, 'The operations are identical.');
-  }
-
-  /**
-   * Tests the listing UI.
-   */
-  public function testListUI() {
-    // Log in as an administrative user to access the full menu trail.
-    $this->drupalLogin($this->drupalCreateUser(['access administration pages', 'administer site configuration']));
-
-    // Get the list callback page.
-    $this->drupalGet('admin/structure/config_test');
-
-    // Test for the page title.
-    $this->assertTitle('Test configuration | Drupal');
-
-    // Test for the table.
-    $element = $this->xpath('//div[@class="layout-content"]//table');
-    $this->assertTrue($element, 'Configuration entity list table found.');
-
-    // Test the table header.
-    $elements = $this->xpath('//div[@class="layout-content"]//table/thead/tr/th');
-    $this->assertEqual(count($elements), 3, 'Correct number of table header cells found.');
-
-    // Test the contents of each th cell.
-    $expected_items = ['Label', 'Machine name', 'Operations'];
-    foreach ($elements as $key => $element) {
-      $this->assertIdentical((string) $element[0], $expected_items[$key]);
-    }
-
-    // Check the number of table row cells.
-    $elements = $this->xpath('//div[@class="layout-content"]//table/tbody/tr[@class="odd"]/td');
-    $this->assertEqual(count($elements), 3, 'Correct number of table row cells found.');
-
-    // Check the contents of each row cell. The first cell contains the label,
-    // the second contains the machine name, and the third contains the
-    // operations list.
-    $this->assertIdentical((string) $elements[0], 'Default');
-    $this->assertIdentical((string) $elements[1], 'dotted.default');
-    $this->assertTrue($elements[2]->children()->xpath('//ul'), 'Operations list found.');
-
-    // Add a new entity using the operations link.
-    $this->assertLink('Add test configuration');
-    $this->clickLink('Add test configuration');
-    $this->assertResponse(200);
-    $edit = [
-      'label' => 'Antelope',
-      'id' => 'antelope',
-      'weight' => 1,
-    ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-
-    // Ensure that the entity's sort method was called.
-    $this->assertTrue(\Drupal::state()->get('config_entity_sort'), 'ConfigTest::sort() was called.');
-
-    // Confirm that the user is returned to the listing, and verify that the
-    // text of the label and machine name appears in the list (versus elsewhere
-    // on the page).
-    $this->assertFieldByXpath('//td', 'Antelope', "Label found for added 'Antelope' entity.");
-    $this->assertFieldByXpath('//td', 'antelope', "Machine name found for added 'Antelope' entity.");
-
-    // Edit the entity using the operations link.
-    $this->assertLinkByHref('admin/structure/config_test/manage/antelope');
-    $this->clickLink('Edit', 1);
-    $this->assertResponse(200);
-    $this->assertTitle('Edit Antelope | Drupal');
-    $edit = ['label' => 'Albatross', 'id' => 'albatross'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-
-    // Confirm that the user is returned to the listing, and verify that the
-    // text of the label and machine name appears in the list (versus elsewhere
-    // on the page).
-    $this->assertFieldByXpath('//td', 'Albatross', "Label found for updated 'Albatross' entity.");
-    $this->assertFieldByXpath('//td', 'albatross', "Machine name found for updated 'Albatross' entity.");
-
-    // Delete the added entity using the operations link.
-    $this->assertLinkByHref('admin/structure/config_test/manage/albatross/delete');
-    $this->clickLink('Delete', 1);
-    $this->assertResponse(200);
-    $this->assertTitle('Are you sure you want to delete the test configuration Albatross? | Drupal');
-    $this->drupalPostForm(NULL, [], t('Delete'));
-
-    // Verify that the text of the label and machine name does not appear in
-    // the list (though it may appear elsewhere on the page).
-    $this->assertNoFieldByXpath('//td', 'Albatross', "No label found for deleted 'Albatross' entity.");
-    $this->assertNoFieldByXpath('//td', 'albatross', "No machine name found for deleted 'Albatross' entity.");
-
-    // Delete the original entity using the operations link.
-    $this->clickLink('Delete');
-    $this->assertResponse(200);
-    $this->assertTitle('Are you sure you want to delete the test configuration Default? | Drupal');
-    $this->drupalPostForm(NULL, [], t('Delete'));
-
-    // Verify that the text of the label and machine name does not appear in
-    // the list (though it may appear elsewhere on the page).
-    $this->assertNoFieldByXpath('//td', 'Default', "No label found for deleted 'Default' entity.");
-    $this->assertNoFieldByXpath('//td', 'dotted.default', "No machine name found for deleted 'Default' entity.");
-
-    // Confirm that the empty text is displayed.
-    $this->assertText('There is no Test configuration yet.');
-  }
-
-  /**
-   * Test paging.
-   */
-  public function testPager() {
-    $this->drupalLogin($this->drupalCreateUser(['administer site configuration']));
-
-    $storage = \Drupal::entityManager()->getListBuilder('config_test')->getStorage();
-
-    // Create 51 test entities.
-    for ($i = 1; $i < 52; $i++) {
-      $storage->create([
-        'id' => str_pad($i, 2, '0', STR_PAD_LEFT),
-        'label' => 'Test config entity ' . $i,
-        'weight' => $i,
-        'protected_property' => $i,
-      ])->save();
-    }
-
-    // Load the listing page.
-    $this->drupalGet('admin/structure/config_test');
-
-    // Item 51 should not be present.
-    $this->assertRaw('Test config entity 50', 'Config entity 50 is shown.');
-    $this->assertNoRaw('Test config entity 51', 'Config entity 51 is on the next page.');
-
-    // Browse to the next page.
-    $this->clickLink(t('Page 2'));
-    $this->assertNoRaw('Test config entity 50', 'Test config entity 50 is on the previous page.');
-    $this->assertRaw('dotted.default', 'Default config entity appears on page 2.');
-    $this->assertRaw('Test config entity 51', 'Test config entity 51 is on page 2.');
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigEntityTest.php b/core/modules/config/src/Tests/ConfigEntityTest.php
deleted file mode 100644
index c0dc97b..0000000
--- a/core/modules/config/src/Tests/ConfigEntityTest.php
+++ /dev/null
@@ -1,360 +0,0 @@
-<?php
-
-namespace Drupal\config\Tests;
-
-use Drupal\Component\Utility\SafeMarkup;
-use Drupal\Core\Entity\EntityMalformedException;
-use Drupal\Core\Entity\EntityStorageException;
-use Drupal\Core\Config\Entity\ConfigEntityStorage;
-use Drupal\Core\Config\Entity\Exception\ConfigEntityIdLengthException;
-use Drupal\Core\Url;
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Tests configuration entities.
- *
- * @group config
- */
-class ConfigEntityTest extends WebTestBase {
-
-  /**
-   * The maximum length for the entity storage used in this test.
-   */
-  const MAX_ID_LENGTH = ConfigEntityStorage::MAX_ID_LENGTH;
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['config_test'];
-
-  /**
-   * Tests CRUD operations.
-   */
-  public function testCRUD() {
-    $default_langcode = \Drupal::languageManager()->getDefaultLanguage()->getId();
-    // Verify default properties on a newly created empty entity.
-    $empty = entity_create('config_test');
-    $this->assertTrue($empty->uuid());
-    $this->assertIdentical($empty->label, NULL);
-    $this->assertIdentical($empty->style, NULL);
-    $this->assertIdentical($empty->language()->getId(), $default_langcode);
-
-    // Verify ConfigEntity properties/methods on the newly created empty entity.
-    $this->assertIdentical($empty->isNew(), TRUE);
-    $this->assertIdentical($empty->getOriginalId(), NULL);
-    $this->assertIdentical($empty->bundle(), 'config_test');
-    $this->assertIdentical($empty->id(), NULL);
-    $this->assertTrue($empty->uuid());
-    $this->assertIdentical($empty->label(), NULL);
-
-    $this->assertIdentical($empty->get('id'), NULL);
-    $this->assertTrue($empty->get('uuid'));
-    $this->assertIdentical($empty->get('label'), NULL);
-    $this->assertIdentical($empty->get('style'), NULL);
-    $this->assertIdentical($empty->language()->getId(), $default_langcode);
-
-    // Verify Entity properties/methods on the newly created empty entity.
-    $this->assertIdentical($empty->getEntityTypeId(), 'config_test');
-    // The URI can only be checked after saving.
-    try {
-      $empty->urlInfo();
-      $this->fail('EntityMalformedException was thrown.');
-    }
-    catch (EntityMalformedException $e) {
-      $this->pass('EntityMalformedException was thrown.');
-    }
-
-    // Verify that an empty entity cannot be saved.
-    try {
-      $empty->save();
-      $this->fail('EntityMalformedException was thrown.');
-    }
-    catch (EntityMalformedException $e) {
-      $this->pass('EntityMalformedException was thrown.');
-    }
-
-    // Verify that an entity with an empty ID string is considered empty, too.
-    $empty_id = entity_create('config_test', [
-      'id' => '',
-    ]);
-    $this->assertIdentical($empty_id->isNew(), TRUE);
-    try {
-      $empty_id->save();
-      $this->fail('EntityMalformedException was thrown.');
-    }
-    catch (EntityMalformedException $e) {
-      $this->pass('EntityMalformedException was thrown.');
-    }
-
-    // Verify properties on a newly created entity.
-    $config_test = entity_create('config_test', $expected = [
-      'id' => $this->randomMachineName(),
-      'label' => $this->randomString(),
-      'style' => $this->randomMachineName(),
-    ]);
-    $this->assertTrue($config_test->uuid());
-    $this->assertNotEqual($config_test->uuid(), $empty->uuid());
-    $this->assertIdentical($config_test->label, $expected['label']);
-    $this->assertIdentical($config_test->style, $expected['style']);
-    $this->assertIdentical($config_test->language()->getId(), $default_langcode);
-
-    // Verify methods on the newly created entity.
-    $this->assertIdentical($config_test->isNew(), TRUE);
-    $this->assertIdentical($config_test->getOriginalId(), $expected['id']);
-    $this->assertIdentical($config_test->id(), $expected['id']);
-    $this->assertTrue($config_test->uuid());
-    $expected['uuid'] = $config_test->uuid();
-    $this->assertIdentical($config_test->label(), $expected['label']);
-
-    // Verify that the entity can be saved.
-    try {
-      $status = $config_test->save();
-      $this->pass('EntityMalformedException was not thrown.');
-    }
-    catch (EntityMalformedException $e) {
-      $this->fail('EntityMalformedException was not thrown.');
-    }
-
-    // The entity path can only be checked after saving.
-    $this->assertIdentical($config_test->url(), Url::fromRoute('entity.config_test.edit_form', ['config_test' => $expected['id']])->toString());
-
-    // Verify that the correct status is returned and properties did not change.
-    $this->assertIdentical($status, SAVED_NEW);
-    $this->assertIdentical($config_test->id(), $expected['id']);
-    $this->assertIdentical($config_test->uuid(), $expected['uuid']);
-    $this->assertIdentical($config_test->label(), $expected['label']);
-    $this->assertIdentical($config_test->isNew(), FALSE);
-    $this->assertIdentical($config_test->getOriginalId(), $expected['id']);
-
-    // Save again, and verify correct status and properties again.
-    $status = $config_test->save();
-    $this->assertIdentical($status, SAVED_UPDATED);
-    $this->assertIdentical($config_test->id(), $expected['id']);
-    $this->assertIdentical($config_test->uuid(), $expected['uuid']);
-    $this->assertIdentical($config_test->label(), $expected['label']);
-    $this->assertIdentical($config_test->isNew(), FALSE);
-    $this->assertIdentical($config_test->getOriginalId(), $expected['id']);
-
-    // Verify that a configuration entity can be saved with an ID of the
-    // maximum allowed length, but not longer.
-
-    // Test with a short ID.
-    $id_length_config_test = entity_create('config_test', [
-      'id' => $this->randomMachineName(8),
-    ]);
-    try {
-      $id_length_config_test->save();
-      $this->pass(SafeMarkup::format("config_test entity with ID length @length was saved.", [
-        '@length' => strlen($id_length_config_test->id())]
-      ));
-    }
-    catch (ConfigEntityIdLengthException $e) {
-      $this->fail($e->getMessage());
-    }
-
-    // Test with an ID of the maximum allowed length.
-    $id_length_config_test = entity_create('config_test', [
-      'id' => $this->randomMachineName(static::MAX_ID_LENGTH),
-    ]);
-    try {
-      $id_length_config_test->save();
-      $this->pass(SafeMarkup::format("config_test entity with ID length @length was saved.", [
-        '@length' => strlen($id_length_config_test->id()),
-      ]));
-    }
-    catch (ConfigEntityIdLengthException $e) {
-      $this->fail($e->getMessage());
-    }
-
-    // Test with an ID exceeding the maximum allowed length.
-    $id_length_config_test = entity_create('config_test', [
-      'id' => $this->randomMachineName(static::MAX_ID_LENGTH + 1),
-    ]);
-    try {
-      $status = $id_length_config_test->save();
-      $this->fail(SafeMarkup::format("config_test entity with ID length @length exceeding the maximum allowed length of @max saved successfully", [
-        '@length' => strlen($id_length_config_test->id()),
-        '@max' => static::MAX_ID_LENGTH,
-      ]));
-    }
-    catch (ConfigEntityIdLengthException $e) {
-      $this->pass(SafeMarkup::format("config_test entity with ID length @length exceeding the maximum allowed length of @max failed to save", [
-        '@length' => strlen($id_length_config_test->id()),
-        '@max' => static::MAX_ID_LENGTH,
-      ]));
-    }
-
-    // Ensure that creating an entity with the same id as an existing one is not
-    // possible.
-    $same_id = entity_create('config_test', [
-      'id' => $config_test->id(),
-    ]);
-    $this->assertIdentical($same_id->isNew(), TRUE);
-    try {
-      $same_id->save();
-      $this->fail('Not possible to overwrite an entity entity.');
-    }
-    catch (EntityStorageException $e) {
-      $this->pass('Not possible to overwrite an entity entity.');
-    }
-
-    // Verify that renaming the ID returns correct status and properties.
-    $ids = [$expected['id'], 'second_' . $this->randomMachineName(4), 'third_' . $this->randomMachineName(4)];
-    for ($i = 1; $i < 3; $i++) {
-      $old_id = $ids[$i - 1];
-      $new_id = $ids[$i];
-      // Before renaming, everything should point to the current ID.
-      $this->assertIdentical($config_test->id(), $old_id);
-      $this->assertIdentical($config_test->getOriginalId(), $old_id);
-
-      // Rename.
-      $config_test->set('id', $new_id);
-      $this->assertIdentical($config_test->id(), $new_id);
-      $status = $config_test->save();
-      $this->assertIdentical($status, SAVED_UPDATED);
-      $this->assertIdentical($config_test->isNew(), FALSE);
-
-      // Verify that originalID points to new ID directly after renaming.
-      $this->assertIdentical($config_test->id(), $new_id);
-      $this->assertIdentical($config_test->getOriginalId(), $new_id);
-    }
-
-    // Test config entity prepopulation.
-    \Drupal::state()->set('config_test.prepopulate', TRUE);
-    $config_test = entity_create('config_test', ['foo' => 'bar']);
-    $this->assertEqual($config_test->get('foo'), 'baz', 'Initial value correctly populated');
-  }
-
-  /**
-   * Tests CRUD operations through the UI.
-   */
-  public function testCRUDUI() {
-    $this->drupalLogin($this->drupalCreateUser(['administer site configuration']));
-
-    $id = strtolower($this->randomMachineName());
-    $label1 = $this->randomMachineName();
-    $label2 = $this->randomMachineName();
-    $label3 = $this->randomMachineName();
-    $message_insert = format_string('%label configuration has been created.', ['%label' => $label1]);
-    $message_update = format_string('%label configuration has been updated.', ['%label' => $label2]);
-    $message_delete = format_string('The test configuration %label has been deleted.', ['%label' => $label2]);
-
-    // Create a configuration entity.
-    $edit = [
-      'id' => $id,
-      'label' => $label1,
-    ];
-    $this->drupalPostForm('admin/structure/config_test/add', $edit, 'Save');
-    $this->assertUrl('admin/structure/config_test');
-    $this->assertResponse(200);
-    $this->assertRaw($message_insert);
-    $this->assertNoRaw($message_update);
-    $this->assertLinkByHref("admin/structure/config_test/manage/$id");
-
-    // Update the configuration entity.
-    $edit = [
-      'label' => $label2,
-    ];
-    $this->drupalPostForm("admin/structure/config_test/manage/$id", $edit, 'Save');
-    $this->assertUrl('admin/structure/config_test');
-    $this->assertResponse(200);
-    $this->assertNoRaw($message_insert);
-    $this->assertRaw($message_update);
-    $this->assertLinkByHref("admin/structure/config_test/manage/$id");
-    $this->assertLinkByHref("admin/structure/config_test/manage/$id/delete");
-
-    // Delete the configuration entity.
-    $this->drupalGet("admin/structure/config_test/manage/$id");
-    $this->clickLink(t('Delete'));
-    $this->assertUrl("admin/structure/config_test/manage/$id/delete");
-    $this->drupalPostForm(NULL, [], 'Delete');
-    $this->assertUrl('admin/structure/config_test');
-    $this->assertResponse(200);
-    $this->assertNoRaw($message_update);
-    $this->assertRaw($message_delete);
-    $this->assertNoText($label1);
-    $this->assertNoLinkByHref("admin/structure/config_test/manage/$id");
-
-    // Re-create a configuration entity.
-    $edit = [
-      'id' => $id,
-      'label' => $label1,
-    ];
-    $this->drupalPostForm('admin/structure/config_test/add', $edit, 'Save');
-    $this->assertUrl('admin/structure/config_test');
-    $this->assertResponse(200);
-    $this->assertText($label1);
-    $this->assertLinkByHref("admin/structure/config_test/manage/$id");
-
-    // Rename the configuration entity's ID/machine name.
-    $edit = [
-      'id' => strtolower($this->randomMachineName()),
-      'label' => $label3,
-    ];
-    $this->drupalPostForm("admin/structure/config_test/manage/$id", $edit, 'Save');
-    $this->assertUrl('admin/structure/config_test');
-    $this->assertResponse(200);
-    $this->assertNoText($label1);
-    $this->assertNoText($label2);
-    $this->assertText($label3);
-    $this->assertNoLinkByHref("admin/structure/config_test/manage/$id");
-    $id = $edit['id'];
-    $this->assertLinkByHref("admin/structure/config_test/manage/$id");
-
-    // Create a configuration entity with '0' machine name.
-    $edit = [
-      'id' => '0',
-      'label' => '0',
-    ];
-    $this->drupalPostForm('admin/structure/config_test/add', $edit, 'Save');
-    $this->assertResponse(200);
-    $message_insert = format_string('%label configuration has been created.', ['%label' => $edit['label']]);
-    $this->assertRaw($message_insert);
-    $this->assertLinkByHref('admin/structure/config_test/manage/0');
-    $this->assertLinkByHref('admin/structure/config_test/manage/0/delete');
-    $this->drupalPostForm('admin/structure/config_test/manage/0/delete', [], 'Delete');
-    $this->assertFalse(entity_load('config_test', '0'), 'Test entity deleted');
-
-    // Create a configuration entity with a property that uses AJAX to show
-    // extra form elements.
-    $this->drupalGet('admin/structure/config_test/add');
-
-    // Test that the dependent element is not shown initially.
-    $this->assertFieldByName('size');
-    $this->assertNoFieldByName('size_value');
-
-    $id = strtolower($this->randomMachineName());
-    $edit = [
-      'id' => $id,
-      'label' => $this->randomString(),
-      'size' => 'custom',
-    ];
-    $this->drupalPostAjaxForm(NULL, $edit, 'size');
-
-    // Check that the dependent element is shown after selecting a 'size' value.
-    $this->assertFieldByName('size');
-    $this->assertFieldByName('size_value');
-
-    // Test the same scenario but it in a non-JS case by using a 'js-hidden'
-    // submit button.
-    $this->drupalGet('admin/structure/config_test/add');
-    $this->assertFieldByName('size');
-    $this->assertNoFieldByName('size_value');
-
-    $this->drupalPostForm(NULL, $edit, 'Change size');
-    $this->assertFieldByName('size');
-    $this->assertFieldByName('size_value');
-
-    // Submit the form with the regular 'Save' button and check that the entity
-    // values are correct.
-    $edit += ['size_value' => 'medium'];
-    $this->drupalPostForm(NULL, $edit, 'Save');
-
-    $entity = entity_load('config_test', $id);
-    $this->assertEqual($entity->get('size'), 'custom');
-    $this->assertEqual($entity->get('size_value'), 'medium');
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigExportImportUITest.php b/core/modules/config/src/Tests/ConfigExportImportUITest.php
deleted file mode 100644
index 9ba59a8..0000000
--- a/core/modules/config/src/Tests/ConfigExportImportUITest.php
+++ /dev/null
@@ -1,324 +0,0 @@
-<?php
-
-namespace Drupal\config\Tests;
-
-use Drupal\Component\Utility\Unicode;
-use Drupal\Core\Archiver\ArchiveTar;
-use Drupal\field\Entity\FieldConfig;
-use Drupal\field\Entity\FieldStorageConfig;
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Tests the user interface for importing/exporting configuration.
- *
- * Each testX method does a complete rebuild of a Drupal site, so values being
- * tested need to be stored in protected properties in order to survive until
- * the next rebuild.
- *
- * @group config
- */
-class ConfigExportImportUITest extends WebTestBase {
-
-  /**
-   * The contents of the config export tarball, held between test methods.
-   *
-   * @var string
-   */
-  protected $tarball;
-
-  /**
-   * Holds the original 'site slogan' before testing.
-   *
-   * @var string
-   */
-  protected $originalSlogan;
-
-  /**
-   * Holds a randomly generated new 'site slogan' for testing.
-   *
-   * @var string
-   */
-  protected $newSlogan;
-
-
-  /**
-   * Holds a content type.
-   *
-   * @var \Drupal\node\NodeInterface
-   */
-  protected $contentType;
-
-  /**
-   * Holds the randomly-generated name of a field.
-   *
-   * @var string
-   */
-  protected $fieldName;
-
-  /**
-   * Holds the field storage entity for $fieldName.
-   *
-   * @var \Drupal\field\FieldStorageConfigInterface
-   */
-  protected $fieldStorage;
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['config', 'node', 'field'];
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    // The initial import must be done with uid 1 because if separately named
-    // roles are created then the role is lost after import. If the roles
-    // created have the same name then the sync will fail because they will
-    // have different UUIDs.
-    $this->drupalLogin($this->rootUser);
-  }
-
-  /**
-   * Tests a simple site export import case.
-   */
-  public function testExportImport() {
-    // After installation there is no snapshot and nothing to import.
-    $this->drupalGet('admin/config/development/configuration');
-    $this->assertNoText(t('Warning message'));
-    $this->assertText(t('There are no configuration changes to import.'));
-
-    $this->originalSlogan = $this->config('system.site')->get('slogan');
-    $this->newSlogan = $this->randomString(16);
-    $this->assertNotEqual($this->newSlogan, $this->originalSlogan);
-    $this->config('system.site')
-      ->set('slogan', $this->newSlogan)
-      ->save();
-    $this->assertEqual($this->config('system.site')->get('slogan'), $this->newSlogan);
-
-    // Create a content type.
-    $this->contentType = $this->drupalCreateContentType();
-
-    // Create a field.
-    $this->fieldName = Unicode::strtolower($this->randomMachineName());
-    $this->fieldStorage = FieldStorageConfig::create([
-      'field_name' => $this->fieldName,
-      'entity_type' => 'node',
-      'type' => 'text',
-    ]);
-    $this->fieldStorage->save();
-    FieldConfig::create([
-      'field_storage' => $this->fieldStorage,
-      'bundle' => $this->contentType->id(),
-    ])->save();
-    // Update the displays so that configuration does not change unexpectedly on
-    // import.
-    entity_get_form_display('node', $this->contentType->id(), 'default')
-      ->setComponent($this->fieldName, [
-        'type' => 'text_textfield',
-      ])
-      ->save();
-    entity_get_display('node', $this->contentType->id(), 'full')
-      ->setComponent($this->fieldName)
-      ->save();
-    entity_get_display('node', $this->contentType->id(), 'default')
-      ->setComponent($this->fieldName)
-      ->save();
-    entity_get_display('node', $this->contentType->id(), 'teaser')
-      ->removeComponent($this->fieldName)
-      ->save();
-
-    $this->drupalGet('node/add/' . $this->contentType->id());
-    $this->assertFieldByName("{$this->fieldName}[0][value]", '', 'Widget is displayed');
-
-    // Export the configuration.
-    $this->drupalPostForm('admin/config/development/configuration/full/export', [], 'Export');
-    $this->tarball = $this->getRawContent();
-
-    $this->config('system.site')
-      ->set('slogan', $this->originalSlogan)
-      ->save();
-    $this->assertEqual($this->config('system.site')->get('slogan'), $this->originalSlogan);
-
-    // Delete the custom field.
-    $fields = FieldConfig::loadMultiple();
-    foreach ($fields as $field) {
-      if ($field->getName() == $this->fieldName) {
-        $field->delete();
-      }
-    }
-    $field_storages = FieldStorageConfig::loadMultiple();
-    foreach ($field_storages as $field_storage) {
-      if ($field_storage->getName() == $this->fieldName) {
-        $field_storage->delete();
-      }
-    }
-    $this->drupalGet('node/add/' . $this->contentType->id());
-    $this->assertNoFieldByName("{$this->fieldName}[0][value]", '', 'Widget is not displayed');
-
-    // Import the configuration.
-    $filename = 'temporary://' . $this->randomMachineName();
-    file_put_contents($filename, $this->tarball);
-    $this->drupalPostForm('admin/config/development/configuration/full/import', ['files[import_tarball]' => $filename], 'Upload');
-    // There is no snapshot yet because an import has never run.
-    $this->assertNoText(t('Warning message'));
-    $this->assertNoText(t('There are no configuration changes to import.'));
-    $this->assertText($this->contentType->label());
-
-    $this->drupalPostForm(NULL, [], 'Import all');
-    // After importing the snapshot has been updated an there are no warnings.
-    $this->assertNoText(t('Warning message'));
-    $this->assertText(t('There are no configuration changes to import.'));
-
-    $this->assertEqual($this->config('system.site')->get('slogan'), $this->newSlogan);
-
-    $this->drupalGet('node/add');
-    $this->assertFieldByName("{$this->fieldName}[0][value]", '', 'Widget is displayed');
-
-    $this->config('system.site')
-      ->set('slogan', $this->originalSlogan)
-      ->save();
-    $this->drupalGet('admin/config/development/configuration');
-    $this->assertText(t('Warning message'));
-    $this->assertText('The following items in your active configuration have changes since the last import that may be lost on the next import.');
-    // Ensure the item is displayed as part of a list (to avoid false matches
-    // on the rest of the page) and that the list markup is not escaped.
-    $this->assertRaw('<li>system.site</li>');
-    // Remove everything from sync. The warning about differences between the
-    // active and snapshot should no longer exist.
-    \Drupal::service('config.storage.sync')->deleteAll();
-    $this->drupalGet('admin/config/development/configuration');
-    $this->assertNoText(t('Warning message'));
-    $this->assertNoText('The following items in your active configuration have changes since the last import that may be lost on the next import.');
-    $this->assertText(t('There are no configuration changes to import.'));
-    // Write a file to sync. The warning about differences between the active
-    // and snapshot should now exist.
-    /** @var \Drupal\Core\Config\StorageInterface $sync */
-    $sync = $this->container->get('config.storage.sync');
-    $data = $this->config('system.site')->get();
-    $data['slogan'] = 'in the face';
-    $this->copyConfig($this->container->get('config.storage'), $sync);
-    $sync->write('system.site', $data);
-    $this->drupalGet('admin/config/development/configuration');
-    $this->assertText(t('Warning message'));
-    $this->assertText('The following items in your active configuration have changes since the last import that may be lost on the next import.');
-    // Ensure the item is displayed as part of a list (to avoid false matches
-    // on the rest of the page) and that the list markup is not escaped.
-    $this->assertRaw('<li>system.site</li>');
-  }
-
-  /**
-   * Tests an export and import of collections.
-   */
-  public function testExportImportCollections() {
-
-    /** @var \Drupal\Core\Config\StorageInterface $active_storage */
-    $active_storage = \Drupal::service('config.storage');
-    $test1_storage = $active_storage->createCollection('collection.test1');
-    $test1_storage->write('config_test.create', ['foo' => 'bar']);
-    $test1_storage->write('config_test.update', ['foo' => 'bar']);
-    $test2_storage = $active_storage->createCollection('collection.test2');
-    $test2_storage->write('config_test.another_create', ['foo' => 'bar']);
-    $test2_storage->write('config_test.another_update', ['foo' => 'bar']);
-
-    // Export the configuration.
-    $this->drupalPostForm('admin/config/development/configuration/full/export', [], 'Export');
-    $this->tarball = $this->getRawContent();
-    $filename = file_directory_temp() . '/' . $this->randomMachineName();
-    file_put_contents($filename, $this->tarball);
-
-    // Set up the active storage collections to test import.
-    $test1_storage->delete('config_test.create');
-    $test1_storage->write('config_test.update', ['foo' => 'baz']);
-    $test1_storage->write('config_test.delete', ['foo' => 'bar']);
-    $test2_storage->delete('config_test.another_create');
-    $test2_storage->write('config_test.another_update', ['foo' => 'baz']);
-    $test2_storage->write('config_test.another_delete', ['foo' => 'bar']);
-
-    // Create a snapshot.
-    $snapshot_storage = \Drupal::service('config.storage.snapshot');
-    \Drupal::service('config.manager')->createSnapshot($active_storage, $snapshot_storage);
-
-    // Ensure that the snapshot has the expected collection data before import.
-    $test1_snapshot = $snapshot_storage->createCollection('collection.test1');
-    $data = $test1_snapshot->read('config_test.delete');
-    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.delete in collection.test1 exists in the snapshot storage.');
-    $data = $test1_snapshot->read('config_test.update');
-    $this->assertEqual($data, ['foo' => 'baz'], 'The config_test.update in collection.test1 exists in the snapshot storage.');
-    $this->assertFalse($test1_snapshot->read('config_test.create'), 'The config_test.create in collection.test1 does not exist in the snapshot storage.');
-    $test2_snapshot = $snapshot_storage->createCollection('collection.test2');
-    $data = $test2_snapshot->read('config_test.another_delete');
-    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.another_delete in collection.test2 exists in the snapshot storage.');
-    $data = $test2_snapshot->read('config_test.another_update');
-    $this->assertEqual($data, ['foo' => 'baz'], 'The config_test.another_update in collection.test2 exists in the snapshot storage.');
-    $this->assertFalse($test2_snapshot->read('config_test.another_create'), 'The config_test.another_create in collection.test2 does not exist in the snapshot storage.');
-
-    // Create the tar that contains the expected content for the collections.
-    $tar = new ArchiveTar($filename, 'gz');
-    $content_list = $tar->listContent();
-    // Convert the list of files into something easy to search.
-    $files = [];
-    foreach ($content_list as $file) {
-      $files[] = $file['filename'];
-    }
-    $this->assertTrue(in_array('collection/test1/config_test.create.yml', $files), 'Config export contains collection/test1/config_test.create.yml.');
-    $this->assertTrue(in_array('collection/test2/config_test.another_create.yml', $files), 'Config export contains collection/test2/config_test.another_create.yml.');
-    $this->assertTrue(in_array('collection/test1/config_test.update.yml', $files), 'Config export contains collection/test1/config_test.update.yml.');
-    $this->assertTrue(in_array('collection/test2/config_test.another_update.yml', $files), 'Config export contains collection/test2/config_test.another_update.yml.');
-    $this->assertFalse(in_array('collection/test1/config_test.delete.yml', $files), 'Config export does not contain collection/test1/config_test.delete.yml.');
-    $this->assertFalse(in_array('collection/test2/config_test.another_delete.yml', $files), 'Config export does not contain collection/test2/config_test.another_delete.yml.');
-
-    $this->drupalPostForm('admin/config/development/configuration/full/import', ['files[import_tarball]' => $filename], 'Upload');
-    // Verify that there are configuration differences to import.
-    $this->drupalGet('admin/config/development/configuration');
-    $this->assertNoText(t('There are no configuration changes to import.'));
-    $this->assertText(t('@collection configuration collection', ['@collection' => 'collection.test1']));
-    $this->assertText(t('@collection configuration collection', ['@collection' => 'collection.test2']));
-    $this->assertText('config_test.create');
-    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test1/config_test.create');
-    $this->assertText('config_test.update');
-    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test1/config_test.update');
-    $this->assertText('config_test.delete');
-    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test1/config_test.delete');
-    $this->assertText('config_test.another_create');
-    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test2/config_test.another_create');
-    $this->assertText('config_test.another_update');
-    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test2/config_test.another_update');
-    $this->assertText('config_test.another_delete');
-    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test2/config_test.another_delete');
-
-    $this->drupalPostForm(NULL, [], 'Import all');
-    $this->assertText(t('There are no configuration changes to import.'));
-
-    // Test data in collections.
-    $data = $test1_storage->read('config_test.create');
-    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.create in collection.test1 has been created.');
-    $data = $test1_storage->read('config_test.update');
-    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.update in collection.test1 has been updated.');
-    $this->assertFalse($test1_storage->read('config_test.delete'), 'The config_test.delete in collection.test1 has been deleted.');
-
-    $data = $test2_storage->read('config_test.another_create');
-    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.another_create in collection.test2 has been created.');
-    $data = $test2_storage->read('config_test.another_update');
-    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.another_update in collection.test2 has been updated.');
-    $this->assertFalse($test2_storage->read('config_test.another_delete'), 'The config_test.another_delete in collection.test2 has been deleted.');
-
-    // Ensure that the snapshot has been updated with the collection data.
-    $snapshot_storage = \Drupal::service('config.storage.snapshot');
-    $test1_snapshot = $snapshot_storage->createCollection('collection.test1');
-    $data = $test1_snapshot->read('config_test.create');
-    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.create in collection.test1 has been created in the snapshot storage.');
-    $data = $test1_snapshot->read('config_test.update');
-    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.update in collection.test1 has been updated in the snapshot storage.');
-    $this->assertFalse($test1_snapshot->read('config_test.delete'), 'The config_test.delete in collection.test1 does not exist in the snapshot storage.');
-    $test2_snapshot = $snapshot_storage->createCollection('collection.test2');
-    $data = $test2_snapshot->read('config_test.another_create');
-    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.another_create in collection.test2 has been created in the snapshot storage.');
-    $data = $test2_snapshot->read('config_test.another_update');
-    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.another_update in collection.test2 has been updated in the snapshot storage.');
-    $this->assertFalse($test2_snapshot->read('config_test.another_delete'), 'The config_test.another_delete in collection.test2 does not exist in the snapshot storage.');
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigExportUITest.php b/core/modules/config/src/Tests/ConfigExportUITest.php
deleted file mode 100644
index c9f53b3..0000000
--- a/core/modules/config/src/Tests/ConfigExportUITest.php
+++ /dev/null
@@ -1,99 +0,0 @@
-<?php
-
-namespace Drupal\config\Tests;
-
-use Drupal\Core\Archiver\Tar;
-use Drupal\Core\Serialization\Yaml;
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Tests the user interface for exporting configuration.
- *
- * @group config
- */
-class ConfigExportUITest extends WebTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['config', 'config_test'];
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    // Set up an override.
-    $settings['config']['system.maintenance']['message'] = (object) [
-      'value' => 'Foo',
-      'required' => TRUE,
-    ];
-    $this->writeSettings($settings);
-
-    $this->drupalLogin($this->drupalCreateUser(['export configuration']));
-  }
-
-  /**
-   * Tests export of configuration.
-   */
-  public function testExport() {
-    // Verify the export page with export submit button is available.
-    $this->drupalGet('admin/config/development/configuration/full/export');
-    $this->assertFieldById('edit-submit', t('Export'));
-
-    // Submit the export form and verify response.
-    $this->drupalPostForm('admin/config/development/configuration/full/export', [], t('Export'));
-    $this->assertResponse(200, 'User can access the download callback.');
-
-    // Test if header contains file name with hostname and timestamp.
-    $request = \Drupal::request();
-    $hostname = str_replace('.', '-', $request->getHttpHost());
-    $header_content_disposition = $this->drupalGetHeader('content-disposition');
-    $header_match = (boolean) preg_match('/attachment; filename="config-' . preg_quote($hostname) . '-\d{4}-\d{2}-\d{2}-\d{2}-\d{2}\.tar\.gz"/', $header_content_disposition);
-    $this->assertTrue($header_match, "Header with filename matches the expected format.");
-
-    // Get the archived binary file provided to user for download.
-    $archive_data = $this->getRawContent();
-
-    // Temporarily save the archive file.
-    $uri = file_unmanaged_save_data($archive_data, 'temporary://config.tar.gz');
-
-    // Extract the archive and verify it's not empty.
-    $file_path = file_directory_temp() . '/' . file_uri_target($uri);
-    $archiver = new Tar($file_path);
-    $archive_contents = $archiver->listContents();
-    $this->assert(!empty($archive_contents), 'Downloaded archive file is not empty.');
-
-    // Prepare the list of config files from active storage, see
-    // \Drupal\config\Controller\ConfigController::downloadExport().
-    $storage_active = $this->container->get('config.storage');
-    $config_files = [];
-    foreach ($storage_active->listAll() as $config_name) {
-      $config_files[] = $config_name . '.yml';
-    }
-    // Assert that the downloaded archive file contents are the same as the test
-    // site active store.
-    $this->assertIdentical($archive_contents, $config_files);
-
-    // Ensure the test configuration override is in effect but was not exported.
-    $this->assertIdentical(\Drupal::config('system.maintenance')->get('message'), 'Foo');
-    $archiver->extract(file_directory_temp(), ['system.maintenance.yml']);
-    $file_contents = file_get_contents(file_directory_temp() . '/' . 'system.maintenance.yml');
-    $exported = Yaml::decode($file_contents);
-    $this->assertNotIdentical($exported['message'], 'Foo');
-
-    // Check the single export form doesn't have "form-required" elements.
-    $this->drupalGet('admin/config/development/configuration/single/export');
-    $this->assertNoRaw('js-form-required form-required', 'No form required fields are found.');
-
-    // Ensure the temporary file is not available to users without the
-    // permission.
-    $this->drupalLogout();
-    $this->drupalGet('system/temporary', ['query' => ['file' => 'config.tar.gz']]);
-    $this->assertResponse(403);
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigFormOverrideTest.php b/core/modules/config/src/Tests/ConfigFormOverrideTest.php
deleted file mode 100644
index f721eeb..0000000
--- a/core/modules/config/src/Tests/ConfigFormOverrideTest.php
+++ /dev/null
@@ -1,47 +0,0 @@
-<?php
-
-namespace Drupal\config\Tests;
-
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Tests config overrides do not appear on forms that extend ConfigFormBase.
- *
- * @group config
- * @see \Drupal\Core\Form\ConfigFormBase
- */
-class ConfigFormOverrideTest extends WebTestBase {
-
-  /**
-   * Tests that overrides do not affect forms.
-   */
-  public function testFormsWithOverrides() {
-    $this->drupalLogin($this->drupalCreateUser(['access administration pages', 'administer site configuration']));
-
-    $overridden_name = 'Site name global conf override';
-
-    // Set up an override.
-    $settings['config']['system.site']['name'] = (object) [
-      'value' => $overridden_name,
-      'required' => TRUE,
-    ];
-    $this->writeSettings($settings);
-
-    // Test that everything on the form is the same, but that the override
-    // worked for the actual site name.
-    $this->drupalGet('admin/config/system/site-information');
-    $this->assertTitle('Basic site settings | ' . $overridden_name);
-    $elements = $this->xpath('//input[@name="site_name"]');
-    $this->assertIdentical((string) $elements[0]['value'], 'Drupal');
-
-    // Submit the form and ensure the site name is not changed.
-    $edit = [
-      'site_name' => 'Custom site name',
-    ];
-    $this->drupalPostForm('admin/config/system/site-information', $edit, t('Save configuration'));
-    $this->assertTitle('Basic site settings | ' . $overridden_name);
-    $elements = $this->xpath('//input[@name="site_name"]');
-    $this->assertIdentical((string) $elements[0]['value'], $edit['site_name']);
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigImportAllTest.php b/core/modules/config/src/Tests/ConfigImportAllTest.php
deleted file mode 100644
index 459be7a..0000000
--- a/core/modules/config/src/Tests/ConfigImportAllTest.php
+++ /dev/null
@@ -1,161 +0,0 @@
-<?php
-
-namespace Drupal\config\Tests;
-
-use Drupal\Core\Config\StorageComparer;
-use Drupal\filter\Entity\FilterFormat;
-use Drupal\system\Tests\Module\ModuleTestBase;
-use Drupal\shortcut\Entity\Shortcut;
-use Drupal\taxonomy\Entity\Term;
-
-/**
- * Tests the largest configuration import possible with all available modules.
- *
- * @group config
- */
-class ConfigImportAllTest extends ModuleTestBase {
-
-  use SchemaCheckTestTrait;
-
-  /**
-   * A user with the 'synchronize configuration' permission.
-   *
-   * @var \Drupal\user\UserInterface
-   */
-  protected $webUser;
-
-  /**
-   * The profile to install as a basis for testing.
-   *
-   * Using the standard profile as this has a lot of additional configuration.
-   *
-   * @var string
-   */
-  protected $profile = 'standard';
-
-  protected function setUp() {
-    parent::setUp();
-
-    $this->webUser = $this->drupalCreateUser(['synchronize configuration']);
-    $this->drupalLogin($this->webUser);
-  }
-
-  /**
-   * Tests that a fixed set of modules can be installed and uninstalled.
-   */
-  public function testInstallUninstall() {
-
-    // Get a list of modules to enable.
-    $all_modules = system_rebuild_module_data();
-    $all_modules = array_filter($all_modules, function ($module) {
-      // Filter contrib, hidden, already enabled modules and modules in the
-      // Testing package.
-      if ($module->origin !== 'core' || !empty($module->info['hidden']) || $module->status == TRUE || $module->info['package'] == 'Testing') {
-        return FALSE;
-      }
-      return TRUE;
-    });
-
-    // Install every module possible.
-    \Drupal::service('module_installer')->install(array_keys($all_modules));
-
-    $this->assertModules(array_keys($all_modules), TRUE);
-    foreach ($all_modules as $module => $info) {
-      $this->assertModuleConfig($module);
-      $this->assertModuleTablesExist($module);
-    }
-
-    // Export active config to sync.
-    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
-
-    system_list_reset();
-    $this->resetAll();
-
-    // Delete every field on the site so all modules can be uninstalled. For
-    // example, if a comment field exists then module becomes required and can
-    // not be uninstalled.
-
-    $field_storages = \Drupal::entityManager()->getStorage('field_storage_config')->loadMultiple();
-    \Drupal::entityManager()->getStorage('field_storage_config')->delete($field_storages);
-    // Purge the data.
-    field_purge_batch(1000);
-
-    // Delete all terms.
-    $terms = Term::loadMultiple();
-    entity_delete_multiple('taxonomy_term', array_keys($terms));
-
-    // Delete all filter formats.
-    $filters = FilterFormat::loadMultiple();
-    entity_delete_multiple('filter_format', array_keys($filters));
-
-    // Delete any shortcuts so the shortcut module can be uninstalled.
-    $shortcuts = Shortcut::loadMultiple();
-    entity_delete_multiple('shortcut', array_keys($shortcuts));
-
-    system_list_reset();
-    $all_modules = system_rebuild_module_data();
-
-    // Ensure that only core required modules and the install profile can not be uninstalled.
-    $validation_reasons = \Drupal::service('module_installer')->validateUninstall(array_keys($all_modules));
-    $this->assertEqual(['standard', 'system', 'user'], array_keys($validation_reasons));
-
-    $modules_to_uninstall = array_filter($all_modules, function ($module) use ($validation_reasons) {
-      // Filter required and not enabled modules.
-      if (!empty($module->info['required']) || $module->status == FALSE) {
-        return FALSE;
-      }
-      return TRUE;
-    });
-
-    // Can not uninstall config and use admin/config/development/configuration!
-    unset($modules_to_uninstall['config']);
-
-    $this->assertTrue(isset($modules_to_uninstall['comment']), 'The comment module will be disabled');
-    $this->assertTrue(isset($modules_to_uninstall['file']), 'The File module will be disabled');
-    $this->assertTrue(isset($modules_to_uninstall['editor']), 'The Editor module will be disabled');
-
-    // Uninstall all modules that can be uninstalled.
-    \Drupal::service('module_installer')->uninstall(array_keys($modules_to_uninstall));
-
-    $this->assertModules(array_keys($modules_to_uninstall), FALSE);
-    foreach ($modules_to_uninstall as $module => $info) {
-      $this->assertNoModuleConfig($module);
-      $this->assertModuleTablesDoNotExist($module);
-    }
-
-    // Import the configuration thereby re-installing all the modules.
-    $this->drupalPostForm('admin/config/development/configuration', [], t('Import all'));
-    // Modules have been installed that have services.
-    $this->rebuildContainer();
-
-    // Check that there are no errors.
-    $this->assertIdentical($this->configImporter()->getErrors(), []);
-
-    // Check that all modules that were uninstalled are now reinstalled.
-    $this->assertModules(array_keys($modules_to_uninstall), TRUE);
-    foreach ($modules_to_uninstall as $module => $info) {
-      $this->assertModuleConfig($module);
-      $this->assertModuleTablesExist($module);
-    }
-
-    // Ensure that we have no configuration changes to import.
-    $storage_comparer = new StorageComparer(
-      $this->container->get('config.storage.sync'),
-      $this->container->get('config.storage'),
-      $this->container->get('config.manager')
-    );
-    $this->assertIdentical($storage_comparer->createChangelist()->getChangelist(), $storage_comparer->getEmptyChangelist());
-
-    // Now we have all configuration imported, test all of them for schema
-    // conformance. Ensures all imported default configuration is valid when
-    // all modules are enabled.
-    $names = $this->container->get('config.storage')->listAll();
-    /** @var \Drupal\Core\Config\TypedConfigManagerInterface $typed_config */
-    $typed_config = $this->container->get('config.typed');
-    foreach ($names as $name) {
-      $config = $this->config($name);
-      $this->assertConfigSchema($typed_config, $name, $config->get());
-    }
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigImportInstallProfileTest.php b/core/modules/config/src/Tests/ConfigImportInstallProfileTest.php
deleted file mode 100644
index eaece36..0000000
--- a/core/modules/config/src/Tests/ConfigImportInstallProfileTest.php
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-
-namespace Drupal\config\Tests;
-
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Tests the importing/exporting configuration based on the install profile.
- *
- * @group config
- */
-class ConfigImportInstallProfileTest extends WebTestBase {
-
-  /**
-   * The profile to install as a basis for testing.
-   *
-   * @var string
-   */
-  protected $profile = 'testing_config_import';
-
-  /**
-   * Modules to install.
-   *
-   * @var array
-   */
-  public static $modules = ['config'];
-
-  /**
-   * A user with the 'synchronize configuration' permission.
-   *
-   * @var \Drupal\user\UserInterface
-   */
-  protected $webUser;
-
-  protected function setUp() {
-    parent::setUp();
-
-    $this->webUser = $this->drupalCreateUser(['synchronize configuration']);
-    $this->drupalLogin($this->webUser);
-    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
-  }
-
-  /**
-   * Tests config importer cannot uninstall install profiles.
-   *
-   * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber
-   */
-  public function testInstallProfileValidation() {
-    $sync = $this->container->get('config.storage.sync');
-    $this->copyConfig($this->container->get('config.storage'), $sync);
-    $core = $sync->read('core.extension');
-
-    // Ensure install profiles can not be uninstalled.
-    unset($core['module']['testing_config_import']);
-    $sync->write('core.extension', $core);
-
-    $this->drupalPostForm('admin/config/development/configuration', [], t('Import all'));
-    $this->assertText('The configuration cannot be imported because it failed validation for the following reasons:');
-    $this->assertText('Unable to uninstall the Testing config import profile since it is the install profile.');
-
-    // Uninstall dependencies of testing_config_import.
-    $core['module']['testing_config_import'] = 0;
-    unset($core['module']['syslog']);
-    unset($core['theme']['stark']);
-    $core['theme']['stable'] = 0;
-    $core['theme']['classy'] = 0;
-    $sync->write('core.extension', $core);
-    $sync->deleteAll('syslog.');
-    $theme = $sync->read('system.theme');
-    $theme['default'] = 'classy';
-    $sync->write('system.theme', $theme);
-    $this->drupalPostForm('admin/config/development/configuration', [], t('Import all'));
-    $this->assertText('The configuration was imported successfully.');
-    $this->rebuildContainer();
-    $this->assertFalse(\Drupal::moduleHandler()->moduleExists('syslog'), 'The syslog module has been uninstalled.');
-    $this->assertFalse(\Drupal::service('theme_handler')->themeExists('stark'), 'The stark theme has been uninstalled.');
-    $this->assertTrue(\Drupal::service('theme_handler')->themeExists('classy'), 'The classy theme has been installed.');
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigImportUITest.php b/core/modules/config/src/Tests/ConfigImportUITest.php
deleted file mode 100644
index 772dada..0000000
--- a/core/modules/config/src/Tests/ConfigImportUITest.php
+++ /dev/null
@@ -1,520 +0,0 @@
-<?php
-
-namespace Drupal\config\Tests;
-
-use Drupal\Component\Utility\Html;
-use Drupal\Component\Utility\SafeMarkup;
-use Drupal\Core\Config\InstallStorage;
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Tests the user interface for importing/exporting configuration.
- *
- * @group config
- */
-class ConfigImportUITest extends WebTestBase {
-
-  /**
-   * Modules to install.
-   *
-   * @var array
-   */
-  public static $modules = ['config', 'config_test', 'config_import_test', 'text', 'options'];
-
-  /**
-   * A user with the 'synchronize configuration' permission.
-   *
-   * @var \Drupal\user\UserInterface
-   */
-  protected $webUser;
-
-  protected function setUp() {
-    parent::setUp();
-
-    $this->webUser = $this->drupalCreateUser(['synchronize configuration']);
-    $this->drupalLogin($this->webUser);
-    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
-  }
-
-  /**
-   * Tests importing configuration.
-   */
-  public function testImport() {
-    $name = 'system.site';
-    $dynamic_name = 'config_test.dynamic.new';
-    /** @var \Drupal\Core\Config\StorageInterface $sync */
-    $sync = $this->container->get('config.storage.sync');
-
-    $this->drupalGet('admin/config/development/configuration');
-    $this->assertText('There are no configuration changes to import.');
-    $this->assertNoFieldById('edit-submit', t('Import all'));
-
-    // Create updated configuration object.
-    $new_site_name = 'Config import test ' . $this->randomString();
-    $this->prepareSiteNameUpdate($new_site_name);
-    $this->assertIdentical($sync->exists($name), TRUE, $name . ' found.');
-
-    // Create new config entity.
-    $original_dynamic_data = [
-      'uuid' => '30df59bd-7b03-4cf7-bb35-d42fc49f0651',
-      'langcode' => \Drupal::languageManager()->getDefaultLanguage()->getId(),
-      'status' => TRUE,
-      'dependencies' => [],
-      'id' => 'new',
-      'label' => 'New',
-      'weight' => 0,
-      'style' => '',
-      'size' => '',
-      'size_value' => '',
-      'protected_property' => '',
-    ];
-    $sync->write($dynamic_name, $original_dynamic_data);
-    $this->assertIdentical($sync->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
-
-    // Enable the Action and Ban modules during import. The Ban
-    // module is used because it creates a table during the install. The Action
-    // module is used because it creates a single simple configuration file
-    // during the install.
-    $core_extension = $this->config('core.extension')->get();
-    $core_extension['module']['action'] = 0;
-    $core_extension['module']['ban'] = 0;
-    $core_extension['module'] = module_config_sort($core_extension['module']);
-    // Bartik is a subtheme of classy so classy must be enabled.
-    $core_extension['theme']['classy'] = 0;
-    $core_extension['theme']['bartik'] = 0;
-    $sync->write('core.extension', $core_extension);
-
-    // Use the install storage so that we can read configuration from modules
-    // and themes that are not installed.
-    $install_storage = new InstallStorage();
-
-    // Set the Bartik theme as default.
-    $system_theme = $this->config('system.theme')->get();
-    $system_theme['default'] = 'bartik';
-    $sync->write('system.theme', $system_theme);
-
-    // Read the action config from module default config folder.
-    $action_settings = $install_storage->read('action.settings');
-    $action_settings['recursion_limit'] = 50;
-    $sync->write('action.settings', $action_settings);
-
-    // Uninstall the Options and Text modules to ensure that dependencies are
-    // handled correctly. Options depends on Text so Text should be installed
-    // first. Since they were enabled during the test setup the core.extension
-    // file in sync will already contain them.
-    \Drupal::service('module_installer')->uninstall(['text', 'options']);
-
-    // Set the state system to record installations and uninstallations.
-    \Drupal::state()->set('ConfigImportUITest.core.extension.modules_installed', []);
-    \Drupal::state()->set('ConfigImportUITest.core.extension.modules_uninstalled', []);
-
-    // Verify that both appear as ready to import.
-    $this->drupalGet('admin/config/development/configuration');
-    $this->assertRaw('<td>' . $name);
-    $this->assertRaw('<td>' . $dynamic_name);
-    $this->assertRaw('<td>core.extension');
-    $this->assertRaw('<td>system.theme');
-    $this->assertRaw('<td>action.settings');
-    $this->assertFieldById('edit-submit', t('Import all'));
-
-    // Import and verify that both do not appear anymore.
-    $this->drupalPostForm(NULL, [], t('Import all'));
-    $this->assertNoRaw('<td>' . $name);
-    $this->assertNoRaw('<td>' . $dynamic_name);
-    $this->assertNoRaw('<td>core.extension');
-    $this->assertNoRaw('<td>system.theme');
-    $this->assertNoRaw('<td>action.settings');
-
-    $this->assertNoFieldById('edit-submit', t('Import all'));
-
-    // Verify that there are no further changes to import.
-    $this->assertText(t('There are no configuration changes to import.'));
-
-    // Verify site name has changed.
-    $this->assertIdentical($new_site_name, $this->config('system.site')->get('name'));
-
-    // Verify that new config entity exists.
-    $this->assertIdentical($original_dynamic_data, $this->config($dynamic_name)->get());
-
-    // Verify the cache got cleared.
-    $this->assertTrue(isset($GLOBALS['hook_cache_flush']));
-
-    $this->rebuildContainer();
-    $this->assertTrue(\Drupal::moduleHandler()->moduleExists('ban'), 'Ban module installed during import.');
-    $this->assertTrue(\Drupal::database()->schema()->tableExists('ban_ip'), 'The database table ban_ip exists.');
-    $this->assertTrue(\Drupal::moduleHandler()->moduleExists('action'), 'Action module installed during import.');
-    $this->assertTrue(\Drupal::moduleHandler()->moduleExists('options'), 'Options module installed during import.');
-    $this->assertTrue(\Drupal::moduleHandler()->moduleExists('text'), 'Text module installed during import.');
-
-    $theme_info = \Drupal::service('theme_handler')->listInfo();
-    $this->assertTrue($theme_info['bartik']->status, 'Bartik theme installed during import.');
-
-    // Ensure installations and uninstallation occur as expected.
-    $installed = \Drupal::state()->get('ConfigImportUITest.core.extension.modules_installed', []);
-    $uninstalled = \Drupal::state()->get('ConfigImportUITest.core.extension.modules_uninstalled', []);
-    $expected = ['action', 'ban', 'text', 'options'];
-    $this->assertIdentical($expected, $installed, 'Action, Ban, Text and Options modules installed in the correct order.');
-    $this->assertTrue(empty($uninstalled), 'No modules uninstalled during import');
-
-    // Verify that the action.settings configuration object was only written
-    // once during the import process and only with the value set in the staged
-    // configuration. This verifies that the module's default configuration is
-    // used during configuration import and, additionally, that after installing
-    // a module, that configuration is not synced twice.
-    $recursion_limit_values = \Drupal::state()->get('ConfigImportUITest.action.settings.recursion_limit', []);
-    $this->assertIdentical($recursion_limit_values, [50]);
-
-    $core_extension = $this->config('core.extension')->get();
-    unset($core_extension['module']['action']);
-    unset($core_extension['module']['ban']);
-    unset($core_extension['module']['options']);
-    unset($core_extension['module']['text']);
-    unset($core_extension['theme']['bartik']);
-    $sync->write('core.extension', $core_extension);
-    $sync->delete('action.settings');
-    $sync->delete('text.settings');
-
-    $system_theme = $this->config('system.theme')->get();
-    $system_theme['default'] = 'stark';
-    $system_theme['admin'] = 'stark';
-    $sync->write('system.theme', $system_theme);
-
-    // Set the state system to record installations and uninstallations.
-    \Drupal::state()->set('ConfigImportUITest.core.extension.modules_installed', []);
-    \Drupal::state()->set('ConfigImportUITest.core.extension.modules_uninstalled', []);
-
-    // Verify that both appear as ready to import.
-    $this->drupalGet('admin/config/development/configuration');
-    $this->assertRaw('<td>core.extension');
-    $this->assertRaw('<td>system.theme');
-    $this->assertRaw('<td>action.settings');
-
-    // Import and verify that both do not appear anymore.
-    $this->drupalPostForm(NULL, [], t('Import all'));
-    $this->assertNoRaw('<td>core.extension');
-    $this->assertNoRaw('<td>system.theme');
-    $this->assertNoRaw('<td>action.settings');
-
-    $this->rebuildContainer();
-    $this->assertFalse(\Drupal::moduleHandler()->moduleExists('ban'), 'Ban module uninstalled during import.');
-    $this->assertFalse(\Drupal::database()->schema()->tableExists('ban_ip'), 'The database table ban_ip does not exist.');
-    $this->assertFalse(\Drupal::moduleHandler()->moduleExists('action'), 'Action module uninstalled during import.');
-    $this->assertFalse(\Drupal::moduleHandler()->moduleExists('options'), 'Options module uninstalled during import.');
-    $this->assertFalse(\Drupal::moduleHandler()->moduleExists('text'), 'Text module uninstalled during import.');
-
-    // Ensure installations and uninstallation occur as expected.
-    $installed = \Drupal::state()->get('ConfigImportUITest.core.extension.modules_installed', []);
-    $uninstalled = \Drupal::state()->get('ConfigImportUITest.core.extension.modules_uninstalled', []);
-    $expected = ['options', 'text', 'ban', 'action'];
-    $this->assertIdentical($expected, $uninstalled, 'Options, Text, Ban and Action modules uninstalled in the correct order.');
-    $this->assertTrue(empty($installed), 'No modules installed during import');
-
-    $theme_info = \Drupal::service('theme_handler')->listInfo();
-    $this->assertFalse(isset($theme_info['bartik']), 'Bartik theme uninstalled during import.');
-
-    // Verify that the action.settings configuration object was only deleted
-    // once during the import process.
-    $delete_called = \Drupal::state()->get('ConfigImportUITest.action.settings.delete', 0);
-    $this->assertIdentical($delete_called, 1, "The action.settings configuration was deleted once during configuration import.");
-  }
-
-  /**
-   * Tests concurrent importing of configuration.
-   */
-  public function testImportLock() {
-    // Create updated configuration object.
-    $new_site_name = 'Config import test ' . $this->randomString();
-    $this->prepareSiteNameUpdate($new_site_name);
-
-    // Verify that there are configuration differences to import.
-    $this->drupalGet('admin/config/development/configuration');
-    $this->assertNoText(t('There are no configuration changes to import.'));
-
-    // Acquire a fake-lock on the import mechanism.
-    $config_importer = $this->configImporter();
-    $this->container->get('lock.persistent')->acquire($config_importer::LOCK_NAME);
-
-    // Attempt to import configuration and verify that an error message appears.
-    $this->drupalPostForm(NULL, [], t('Import all'));
-    $this->assertText(t('Another request may be synchronizing configuration already.'));
-
-    // Release the lock, just to keep testing sane.
-    $this->container->get('lock.persistent')->release($config_importer::LOCK_NAME);
-
-    // Verify site name has not changed.
-    $this->assertNotEqual($new_site_name, $this->config('system.site')->get('name'));
-  }
-
-  /**
-   * Tests verification of site UUID before importing configuration.
-   */
-  public function testImportSiteUuidValidation() {
-    $sync = \Drupal::service('config.storage.sync');
-    // Create updated configuration object.
-    $config_data = $this->config('system.site')->get();
-    // Generate a new site UUID.
-    $config_data['uuid'] = \Drupal::service('uuid')->generate();
-    $sync->write('system.site', $config_data);
-
-    // Verify that there are configuration differences to import.
-    $this->drupalGet('admin/config/development/configuration');
-    $this->assertText(t('The staged configuration cannot be imported, because it originates from a different site than this site. You can only synchronize configuration between cloned instances of this site.'));
-    $this->assertNoFieldById('edit-submit', t('Import all'));
-  }
-
-  /**
-   * Tests the screen that shows differences between active and sync.
-   */
-  public function testImportDiff() {
-    $sync = $this->container->get('config.storage.sync');
-    $config_name = 'config_test.system';
-    $change_key = 'foo';
-    $remove_key = '404';
-    $add_key = 'biff';
-    $add_data = '<em>bangpow</em>';
-    $change_data = '<p><em>foobar</em></p>';
-    $original_data = [
-      'foo' => '<p>foobar</p>',
-      'baz' => '<strong>no change</strong>',
-      '404' => '<em>herp</em>',
-    ];
-    // Update active storage to have html in config data.
-    $this->config($config_name)->setData($original_data)->save();
-
-    // Change a configuration value in sync.
-    $sync_data = $original_data;
-    $sync_data[$change_key] = $change_data;
-    $sync_data[$add_key] = $add_data;
-    unset($sync_data[$remove_key]);
-    $sync->write($config_name, $sync_data);
-
-    // Load the diff UI and verify that the diff reflects the change.
-    $this->drupalGet('admin/config/development/configuration/sync/diff/' . $config_name);
-    $this->assertNoRaw('&amp;nbsp;');
-    $this->assertTitle(format_string('View changes of @config_name | Drupal', ['@config_name' => $config_name]));
-
-    // The following assertions do not use $this::assertEscaped() because
-    // \Drupal\Component\Diff\DiffFormatter adds markup that signifies what has
-    // changed.
-
-    // Changed values are escaped.
-    $this->assertText(Html::escape("foo: '<p><em>foobar</em></p>'"));
-    $this->assertText(Html::escape("foo: '<p>foobar</p>'"));
-    // The no change values are escaped.
-    $this->assertText(Html::escape("baz: '<strong>no change</strong>'"));
-    // Added value is escaped.
-    $this->assertText(Html::escape("biff: '<em>bangpow</em>'"));
-    // Deleted value is escaped.
-    $this->assertText(Html::escape("404: '<em>herp</em>'"));
-
-    // Verify diff colors are displayed.
-    $result = $this->xpath('//table[contains(@class, :class)]', [':class' => 'diff']);
-    $this->assertEqual(count($result), 1, "Diff UI is displaying colors.");
-
-    // Reset data back to original, and remove a key
-    $sync_data = $original_data;
-    unset($sync_data[$remove_key]);
-    $sync->write($config_name, $sync_data);
-
-    // Load the diff UI and verify that the diff reflects a removed key.
-    $this->drupalGet('admin/config/development/configuration/sync/diff/' . $config_name);
-    // The no change values are escaped.
-    $this->assertText(Html::escape("foo: '<p>foobar</p>'"));
-    $this->assertText(Html::escape("baz: '<strong>no change</strong>'"));
-    // Removed key is escaped.
-    $this->assertText(Html::escape("404: '<em>herp</em>'"));
-
-    // Reset data back to original and add a key
-    $sync_data = $original_data;
-    $sync_data[$add_key] = $add_data;
-    $sync->write($config_name, $sync_data);
-
-    // Load the diff UI and verify that the diff reflects an added key.
-    $this->drupalGet('admin/config/development/configuration/sync/diff/' . $config_name);
-    // The no change values are escaped.
-    $this->assertText(Html::escape("baz: '<strong>no change</strong>'"));
-    $this->assertText(Html::escape("404: '<em>herp</em>'"));
-    // Added key is escaped.
-    $this->assertText(Html::escape("biff: '<em>bangpow</em>'"));
-  }
-
-  /**
-   * Tests that multiple validation errors are listed on the page.
-   */
-  public function testImportValidation() {
-    // Set state value so that
-    // \Drupal\config_import_test\EventSubscriber::onConfigImportValidate() logs
-    // validation errors.
-    \Drupal::state()->set('config_import_test.config_import_validate_fail', TRUE);
-    // Ensure there is something to import.
-    $new_site_name = 'Config import test ' . $this->randomString();
-    $this->prepareSiteNameUpdate($new_site_name);
-
-    $this->drupalGet('admin/config/development/configuration');
-    $this->assertNoText(t('There are no configuration changes to import.'));
-    $this->drupalPostForm(NULL, [], t('Import all'));
-
-    // Verify that the validation messages appear.
-    $this->assertText('The configuration cannot be imported because it failed validation for the following reasons:');
-    $this->assertText('Config import validate error 1.');
-    $this->assertText('Config import validate error 2.');
-
-    // Verify site name has not changed.
-    $this->assertNotEqual($new_site_name, $this->config('system.site')->get('name'));
-  }
-
-  public function testConfigUninstallConfigException() {
-    $sync = $this->container->get('config.storage.sync');
-
-    $core_extension = $this->config('core.extension')->get();
-    unset($core_extension['module']['config']);
-    $sync->write('core.extension', $core_extension);
-
-    $this->drupalGet('admin/config/development/configuration');
-    $this->assertText('core.extension');
-
-    // Import and verify that both do not appear anymore.
-    $this->drupalPostForm(NULL, [], t('Import all'));
-    $this->assertText('Can not uninstall the Configuration module as part of a configuration synchronization through the user interface.');
-  }
-
-  public function prepareSiteNameUpdate($new_site_name) {
-    $sync = $this->container->get('config.storage.sync');
-    // Create updated configuration object.
-    $config_data = $this->config('system.site')->get();
-    $config_data['name'] = $new_site_name;
-    $sync->write('system.site', $config_data);
-  }
-
-  /**
-   * Tests an import that results in an error.
-   */
-  public function testImportErrorLog() {
-    $name_primary = 'config_test.dynamic.primary';
-    $name_secondary = 'config_test.dynamic.secondary';
-    $sync = $this->container->get('config.storage.sync');
-    $uuid = $this->container->get('uuid');
-
-    $values_primary = [
-      'uuid' => $uuid->generate(),
-      'langcode' => 'en',
-      'status' => TRUE,
-      'dependencies' => [],
-      'id' => 'primary',
-      'label' => 'Primary',
-      'weight' => 0,
-      'style' => NULL,
-      'size' => NULL,
-      'size_value' => NULL,
-      'protected_property' => NULL,
-    ];
-    $sync->write($name_primary, $values_primary);
-    $values_secondary = [
-      'uuid' => $uuid->generate(),
-      'langcode' => 'en',
-      'status' => TRUE,
-      // Add a dependency on primary, to ensure that is synced first.
-      'dependencies' => [
-        'config' => [$name_primary],
-      ],
-      'id' => 'secondary',
-      'label' => 'Secondary Sync',
-      'weight' => 0,
-      'style' => NULL,
-      'size' => NULL,
-      'size_value' => NULL,
-      'protected_property' => NULL,
-    ];
-    $sync->write($name_secondary, $values_secondary);
-    // Verify that there are configuration differences to import.
-    $this->drupalGet('admin/config/development/configuration');
-    $this->assertNoText(t('There are no configuration changes to import.'));
-
-    // Attempt to import configuration and verify that an error message appears.
-    $this->drupalPostForm(NULL, [], t('Import all'));
-    $this->assertText(SafeMarkup::format('Deleted and replaced configuration entity "@name"', ['@name' => $name_secondary]));
-    $this->assertText(t('The configuration was imported with errors.'));
-    $this->assertNoText(t('The configuration was imported successfully.'));
-    $this->assertText(t('There are no configuration changes to import.'));
-  }
-
-  /**
-   * Tests the config importer cannot delete bundles with existing entities.
-   *
-   * @see \Drupal\Core\Entity\Event\BundleConfigImportValidate
-   */
-  public function testEntityBundleDelete() {
-    \Drupal::service('module_installer')->install(['node']);
-    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
-
-    $node_type = $this->drupalCreateContentType();
-    $node = $this->drupalCreateNode(['type' => $node_type->id()]);
-    $this->drupalGet('admin/config/development/configuration');
-    // The node type, body field and entity displays will be scheduled for
-    // removal.
-    $this->assertText(format_string('node.type.@type', ['@type' => $node_type->id()]));
-    $this->assertText(format_string('field.field.node.@type.body', ['@type' => $node_type->id()]));
-    $this->assertText(format_string('core.entity_view_display.node.@type.teaser', ['@type' => $node_type->id()]));
-    $this->assertText(format_string('core.entity_view_display.node.@type.default', ['@type' => $node_type->id()]));
-    $this->assertText(format_string('core.entity_form_display.node.@type.default', ['@type' => $node_type->id()]));
-
-    // Attempt to import configuration and verify that an error message appears
-    // and the node type, body field and entity displays are still scheduled for
-    // removal.
-    $this->drupalPostForm(NULL, [], t('Import all'));
-    $validation_message = t('Entities exist of type %entity_type and %bundle_label %bundle. These entities need to be deleted before importing.', ['%entity_type' => $node->getEntityType()->getLabel(), '%bundle_label' => $node->getEntityType()->getBundleLabel(), '%bundle' => $node_type->label()]);
-    $this->assertRaw($validation_message);
-    $this->assertText(format_string('node.type.@type', ['@type' => $node_type->id()]));
-    $this->assertText(format_string('field.field.node.@type.body', ['@type' => $node_type->id()]));
-    $this->assertText(format_string('core.entity_view_display.node.@type.teaser', ['@type' => $node_type->id()]));
-    $this->assertText(format_string('core.entity_view_display.node.@type.default', ['@type' => $node_type->id()]));
-    $this->assertText(format_string('core.entity_form_display.node.@type.default', ['@type' => $node_type->id()]));
-
-    // Delete the node and try to import again.
-    $node->delete();
-    $this->drupalPostForm(NULL, [], t('Import all'));
-    $this->assertNoRaw($validation_message);
-    $this->assertText(t('There are no configuration changes to import.'));
-    $this->assertNoText(format_string('node.type.@type', ['@type' => $node_type->id()]));
-    $this->assertNoText(format_string('field.field.node.@type.body', ['@type' => $node_type->id()]));
-    $this->assertNoText(format_string('core.entity_view_display.node.@type.teaser', ['@type' => $node_type->id()]));
-    $this->assertNoText(format_string('core.entity_view_display.node.@type.default', ['@type' => $node_type->id()]));
-    $this->assertNoText(format_string('core.entity_form_display.node.@type.default', ['@type' => $node_type->id()]));
-  }
-
-  /**
-   * Tests config importer cannot uninstall extensions which are depended on.
-   *
-   * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber
-   */
-  public function testExtensionValidation() {
-    \Drupal::service('module_installer')->install(['node']);
-    \Drupal::service('theme_handler')->install(['bartik']);
-    $this->rebuildContainer();
-
-    $sync = $this->container->get('config.storage.sync');
-    $this->copyConfig($this->container->get('config.storage'), $sync);
-    $core = $sync->read('core.extension');
-    // Node depends on text.
-    unset($core['module']['text']);
-    $module_data = system_rebuild_module_data();
-    $this->assertTrue(isset($module_data['node']->requires['text']), 'The Node module depends on the Text module.');
-    // Bartik depends on classy.
-    unset($core['theme']['classy']);
-    $theme_data = \Drupal::service('theme_handler')->rebuildThemeData();
-    $this->assertTrue(isset($theme_data['bartik']->requires['classy']), 'The Bartik theme depends on the Classy theme.');
-    // This module does not exist.
-    $core['module']['does_not_exist'] = 0;
-    // This theme does not exist.
-    $core['theme']['does_not_exist'] = 0;
-    $sync->write('core.extension', $core);
-
-    $this->drupalPostForm('admin/config/development/configuration', [], t('Import all'));
-    $this->assertText('The configuration cannot be imported because it failed validation for the following reasons:');
-    $this->assertText('Unable to uninstall the Text module since the Node module is installed.');
-    $this->assertText('Unable to uninstall the Classy theme since the Bartik theme is installed.');
-    $this->assertText('Unable to install the does_not_exist module since it does not exist.');
-    $this->assertText('Unable to install the does_not_exist theme since it does not exist.');
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigImportUploadTest.php b/core/modules/config/src/Tests/ConfigImportUploadTest.php
deleted file mode 100644
index 5e21295..0000000
--- a/core/modules/config/src/Tests/ConfigImportUploadTest.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-
-namespace Drupal\config\Tests;
-
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Tests importing configuration from an uploaded file.
- *
- * @group config
- */
-class ConfigImportUploadTest extends WebTestBase {
-
-  /**
-   * A user with the 'import configuration' permission.
-   *
-   * @var \Drupal\user\UserInterface
-   */
-  protected $webUser;
-
-  /**
-   * Modules to install.
-   *
-   * @var array
-   */
-  public static $modules = ['config'];
-
-  protected function setUp() {
-    parent::setUp();
-
-    $this->webUser = $this->drupalCreateUser(['import configuration']);
-    $this->drupalLogin($this->webUser);
-  }
-
-  /**
-   * Tests importing configuration.
-   */
-  public function testImport() {
-    // Verify access to the config upload form.
-    $this->drupalGet('admin/config/development/configuration/full/import');
-    $this->assertResponse(200);
-
-    // Attempt to upload a non-tar file.
-    $text_file = current($this->drupalGetTestFiles('text'));
-    $edit = ['files[import_tarball]' => drupal_realpath($text_file->uri)];
-    $this->drupalPostForm('admin/config/development/configuration/full/import', $edit, t('Upload'));
-    $this->assertText(t('Could not extract the contents of the tar file'));
-
-    // Make the sync directory read-only.
-    $directory = config_get_config_directory(CONFIG_SYNC_DIRECTORY);
-    \Drupal::service('file_system')->chmod($directory, 0555);
-    $this->drupalGet('admin/config/development/configuration/full/import');
-    $this->assertRaw(t('The directory %directory is not writable.', ['%directory' => $directory]));
-    // Ensure submit button for \Drupal\config\Form\ConfigImportForm is
-    // disabled.
-    $submit_is_disabled = $this->cssSelect('form.config-import-form input[type="submit"]:disabled');
-    $this->assertTrue(count($submit_is_disabled) === 1, 'The submit button is disabled.');
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigInstallWebTest.php b/core/modules/config/src/Tests/ConfigInstallWebTest.php
deleted file mode 100644
index 63ecb5b..0000000
--- a/core/modules/config/src/Tests/ConfigInstallWebTest.php
+++ /dev/null
@@ -1,213 +0,0 @@
-<?php
-
-namespace Drupal\config\Tests;
-
-use Drupal\Core\Config\PreExistingConfigException;
-use Drupal\Core\Config\StorageInterface;
-use Drupal\language\Entity\ConfigurableLanguage;
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Tests installation and removal of configuration objects in install, disable
- * and uninstall functionality.
- *
- * @group config
- */
-class ConfigInstallWebTest extends WebTestBase {
-
-  /**
-   * The admin user used in this test.
-   */
-  protected $adminUser;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    $this->adminUser = $this->drupalCreateUser(['administer modules', 'administer themes', 'administer site configuration']);
-
-    // Ensure the global variable being asserted by this test does not exist;
-    // a previous test executed in this request/process might have set it.
-    unset($GLOBALS['hook_config_test']);
-  }
-
-  /**
-   * Tests module re-installation.
-   */
-  public function testIntegrationModuleReinstallation() {
-    $default_config = 'config_integration_test.settings';
-    $default_configuration_entity = 'config_test.dynamic.config_integration_test';
-
-    // Install the config_test module we're integrating with.
-    \Drupal::service('module_installer')->install(['config_test']);
-
-    // Verify the configuration does not exist prior to installation.
-    $config_static = $this->config($default_config);
-    $this->assertIdentical($config_static->isNew(), TRUE);
-    $config_entity = $this->config($default_configuration_entity);
-    $this->assertIdentical($config_entity->isNew(), TRUE);
-
-    // Install the integration module.
-    \Drupal::service('module_installer')->install(['config_integration_test']);
-
-    // Verify that default module config exists.
-    \Drupal::configFactory()->reset($default_config);
-    \Drupal::configFactory()->reset($default_configuration_entity);
-    $config_static = $this->config($default_config);
-    $this->assertIdentical($config_static->isNew(), FALSE);
-    $this->assertIdentical($config_static->get('foo'), 'default setting');
-    $config_entity = $this->config($default_configuration_entity);
-    $this->assertIdentical($config_entity->isNew(), FALSE);
-    $this->assertIdentical($config_entity->get('label'), 'Default integration config label');
-
-    // Customize both configuration objects.
-    $config_static->set('foo', 'customized setting')->save();
-    $config_entity->set('label', 'Customized integration config label')->save();
-
-    // @todo FIXME: Setting config keys WITHOUT SAVING retains the changed config
-    //   object in memory. Every new call to $this->config() MUST revert in-memory changes
-    //   that haven't been saved!
-    //   In other words: This test passes even without this reset, but it shouldn't.
-    $this->container->get('config.factory')->reset();
-
-    // Disable and uninstall the integration module.
-    $this->container->get('module_installer')->uninstall(['config_integration_test']);
-
-    // Verify the integration module's config was uninstalled.
-    $config_static = $this->config($default_config);
-    $this->assertIdentical($config_static->isNew(), TRUE);
-
-    // Verify the integration config still exists.
-    $config_entity = $this->config($default_configuration_entity);
-    $this->assertIdentical($config_entity->isNew(), FALSE);
-    $this->assertIdentical($config_entity->get('label'), 'Customized integration config label');
-
-    // Reinstall the integration module.
-    try {
-      \Drupal::service('module_installer')->install(['config_integration_test']);
-      $this->fail('Expected PreExistingConfigException not thrown.');
-    }
-    catch (PreExistingConfigException $e) {
-      $this->assertEqual($e->getExtension(), 'config_integration_test');
-      $this->assertEqual($e->getConfigObjects(), [StorageInterface::DEFAULT_COLLECTION => ['config_test.dynamic.config_integration_test']]);
-      $this->assertEqual($e->getMessage(), 'Configuration objects (config_test.dynamic.config_integration_test) provided by config_integration_test already exist in active configuration');
-    }
-
-    // Delete the configuration entity so that the install will work.
-    $config_entity->delete();
-    \Drupal::service('module_installer')->install(['config_integration_test']);
-
-    // Verify the integration module's config was re-installed.
-    \Drupal::configFactory()->reset($default_config);
-    \Drupal::configFactory()->reset($default_configuration_entity);
-    $config_static = $this->config($default_config);
-    $this->assertIdentical($config_static->isNew(), FALSE);
-    $this->assertIdentical($config_static->get('foo'), 'default setting');
-
-    // Verify the integration config is using the default.
-    $config_entity = \Drupal::config($default_configuration_entity);
-    $this->assertIdentical($config_entity->isNew(), FALSE);
-    $this->assertIdentical($config_entity->get('label'), 'Default integration config label');
-  }
-
-  /**
-   * Tests pre-existing configuration detection.
-   */
-  public function testPreExistingConfigInstall() {
-    $this->drupalLogin($this->adminUser);
-
-    // Try to install config_install_fail_test and config_test. Doing this
-    // will install the config_test module first because it is a dependency of
-    // config_install_fail_test.
-    // @see \Drupal\system\Form\ModulesListForm::submitForm()
-    $this->drupalPostForm('admin/modules', ['modules[config_test][enable]' => TRUE, 'modules[config_install_fail_test][enable]' => TRUE], t('Install'));
-    $this->assertRaw('Unable to install Configuration install fail test, <em class="placeholder">config_test.dynamic.dotted.default</em> already exists in active configuration.');
-
-    // Uninstall the config_test module to test the confirm form.
-    $this->drupalPostForm('admin/modules/uninstall', ['uninstall[config_test]' => TRUE], t('Uninstall'));
-    $this->drupalPostForm(NULL, [], t('Uninstall'));
-
-    // Try to install config_install_fail_test without selecting config_test.
-    // The user is shown a confirm form because the config_test module is a
-    // dependency.
-    // @see \Drupal\system\Form\ModulesListConfirmForm::submitForm()
-    $this->drupalPostForm('admin/modules', ['modules[config_install_fail_test][enable]' => TRUE], t('Install'));
-    $this->drupalPostForm(NULL, [], t('Continue'));
-    $this->assertRaw('Unable to install Configuration install fail test, <em class="placeholder">config_test.dynamic.dotted.default</em> already exists in active configuration.');
-
-    // Test that collection configuration clashes during a module install are
-    // reported correctly.
-    \Drupal::service('module_installer')->install(['language']);
-    $this->rebuildContainer();
-    ConfigurableLanguage::createFromLangcode('fr')->save();
-    \Drupal::languageManager()
-      ->getLanguageConfigOverride('fr', 'config_test.dynamic.dotted.default')
-      ->set('label', 'Je suis Charlie')
-      ->save();
-
-    $this->drupalPostForm('admin/modules', ['modules[config_install_fail_test][enable]' => TRUE], t('Install'));
-    $this->assertRaw('Unable to install Configuration install fail test, <em class="placeholder">config_test.dynamic.dotted.default, language/fr/config_test.dynamic.dotted.default</em> already exist in active configuration.');
-
-    // Test installing a theme through the UI that has existing configuration.
-    // This relies on the fact the config_test has been installed and created
-    // the config_test.dynamic.dotted.default configuration and the translation
-    // override created still exists.
-    $this->drupalGet('admin/appearance');
-    $url = $this->xpath("//a[contains(@href,'config_clash_test_theme') and contains(@href,'/install?')]/@href")[0];
-    $this->drupalGet($this->getAbsoluteUrl($url));
-    $this->assertRaw('Unable to install config_clash_test_theme, <em class="placeholder">config_test.dynamic.dotted.default, language/fr/config_test.dynamic.dotted.default</em> already exist in active configuration.');
-
-    // Test installing a theme through the API that has existing configuration.
-    try {
-      \Drupal::service('theme_handler')->install(['config_clash_test_theme']);
-      $this->fail('Expected PreExistingConfigException not thrown.');
-    }
-    catch (PreExistingConfigException $e) {
-      $this->assertEqual($e->getExtension(), 'config_clash_test_theme');
-      $this->assertEqual($e->getConfigObjects(), [StorageInterface::DEFAULT_COLLECTION => ['config_test.dynamic.dotted.default'], 'language.fr' => ['config_test.dynamic.dotted.default']]);
-      $this->assertEqual($e->getMessage(), 'Configuration objects (config_test.dynamic.dotted.default, language/fr/config_test.dynamic.dotted.default) provided by config_clash_test_theme already exist in active configuration');
-    }
-  }
-
-  /**
-   * Tests unmet dependencies detection.
-   */
-  public function testUnmetDependenciesInstall() {
-    $this->drupalLogin($this->adminUser);
-    // We need to install separately since config_install_dependency_test does
-    // not depend on config_test and order is important.
-    $this->drupalPostForm('admin/modules', ['modules[config_test][enable]' => TRUE], t('Install'));
-    $this->drupalPostForm('admin/modules', ['modules[config_install_dependency_test][enable]' => TRUE], t('Install'));
-    $this->assertRaw('Unable to install <em class="placeholder">Config install dependency test</em> due to unmet dependencies: <em class="placeholder">config_test.dynamic.other_module_test_with_dependency (config_other_module_config_test, config_test.dynamic.dotted.english)</em>');
-
-    $this->drupalPostForm('admin/modules', ['modules[config_test_language][enable]' => TRUE], t('Install'));
-    $this->drupalPostForm('admin/modules', ['modules[config_install_dependency_test][enable]' => TRUE], t('Install'));
-    $this->assertRaw('Unable to install <em class="placeholder">Config install dependency test</em> due to unmet dependencies: <em class="placeholder">config_test.dynamic.other_module_test_with_dependency (config_other_module_config_test)</em>');
-
-    $this->drupalPostForm('admin/modules', ['modules[config_other_module_config_test][enable]' => TRUE], t('Install'));
-    $this->drupalPostForm('admin/modules', ['modules[config_install_dependency_test][enable]' => TRUE], t('Install'));
-    $this->rebuildContainer();
-    $this->assertTrue(entity_load('config_test', 'other_module_test_with_dependency'), 'The config_test.dynamic.other_module_test_with_dependency configuration has been created during install.');
-  }
-
-  /**
-   * Tests config_requirements().
-   */
-  public function testConfigModuleRequirements() {
-    $this->drupalLogin($this->adminUser);
-    $this->drupalPostForm('admin/modules', ['modules[config][enable]' => TRUE], t('Install'));
-
-    $directory = config_get_config_directory(CONFIG_SYNC_DIRECTORY);
-    file_unmanaged_delete_recursive($directory);
-    $this->drupalGet('/admin/reports/status');
-    $this->assertRaw(t('The directory %directory does not exist.', ['%directory' => $directory]));
-
-    file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
-    \Drupal::service('file_system')->chmod($directory, 0555);
-    $this->drupalGet('/admin/reports/status');
-    $this->assertRaw(t('The directory %directory is not writable.', ['%directory' => $directory]));
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigSingleImportExportTest.php b/core/modules/config/src/Tests/ConfigSingleImportExportTest.php
deleted file mode 100644
index 607e80c..0000000
--- a/core/modules/config/src/Tests/ConfigSingleImportExportTest.php
+++ /dev/null
@@ -1,250 +0,0 @@
-<?php
-
-namespace Drupal\config\Tests;
-
-use Drupal\Core\Serialization\Yaml;
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Tests the user interface for importing/exporting a single configuration.
- *
- * @group config
- */
-class ConfigSingleImportExportTest extends WebTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = [
-    'block',
-    'config',
-    'config_test',
-    // Adding language module makes it possible to involve non-default
-    // (language.xx) collections in import/export operations.
-    'language',
-  ];
-
-  protected function setUp() {
-    parent::setUp();
-
-    $this->drupalPlaceBlock('page_title_block');
-  }
-
-  /**
-   * Tests importing a single configuration file.
-   */
-  public function testImport() {
-    $storage = \Drupal::entityManager()->getStorage('config_test');
-    $uuid = \Drupal::service('uuid');
-
-    $this->drupalLogin($this->drupalCreateUser(['import configuration']));
-
-    // Attempt an import with invalid YAML.
-    $edit = [
-      'config_type' => 'action',
-      'import' => '{{{',
-    ];
-
-    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
-    // Assert the static portion of the error since different parsers could give different text in their error.
-    $this->assertText('The import failed with the following message: ');
-
-    $import = <<<EOD
-label: First
-weight: 0
-style: ''
-status: '1'
-EOD;
-    $edit = [
-      'config_type' => 'config_test',
-      'import' => $import,
-    ];
-    // Attempt an import with a missing ID.
-    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
-    $this->assertText(t('Missing ID key "@id_key" for this @entity_type import.', ['@id_key' => 'id', '@entity_type' => 'Test configuration']));
-
-    // Perform an import with no specified UUID and a unique ID.
-    $this->assertNull($storage->load('first'));
-    $edit['import'] = "id: first\n" . $edit['import'];
-    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
-    $this->assertRaw(t('Are you sure you want to create a new %name @type?', ['%name' => 'first', '@type' => 'test configuration']));
-    $this->drupalPostForm(NULL, [], t('Confirm'));
-    $entity = $storage->load('first');
-    $this->assertIdentical($entity->label(), 'First');
-    $this->assertIdentical($entity->id(), 'first');
-    $this->assertTrue($entity->status());
-    $this->assertRaw(t('The configuration was imported successfully.'));
-
-    // Attempt an import with an existing ID but missing UUID.
-    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
-    $this->assertText(t('An entity with this machine name already exists but the import did not specify a UUID.'));
-
-    // Attempt an import with a mismatched UUID and existing ID.
-    $edit['import'] .= "\nuuid: " . $uuid->generate();
-    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
-    $this->assertText(t('An entity with this machine name already exists but the UUID does not match.'));
-
-    // Attempt an import with a custom ID.
-    $edit['custom_entity_id'] = 'custom_id';
-    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
-    $this->assertRaw(t('Are you sure you want to create a new %name @type?', ['%name' => 'custom_id', '@type' => 'test configuration']));
-    $this->drupalPostForm(NULL, [], t('Confirm'));
-    $this->assertRaw(t('The configuration was imported successfully.'));
-
-    // Perform an import with a unique ID and UUID.
-    $import = <<<EOD
-id: second
-label: Second
-weight: 0
-style: ''
-status: '0'
-EOD;
-    $edit = [
-      'config_type' => 'config_test',
-      'import' => $import,
-    ];
-    $second_uuid = $uuid->generate();
-    $edit['import'] .= "\nuuid: " . $second_uuid;
-    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
-    $this->assertRaw(t('Are you sure you want to create a new %name @type?', ['%name' => 'second', '@type' => 'test configuration']));
-    $this->drupalPostForm(NULL, [], t('Confirm'));
-    $entity = $storage->load('second');
-    $this->assertRaw(t('The configuration was imported successfully.'));
-    $this->assertIdentical($entity->label(), 'Second');
-    $this->assertIdentical($entity->id(), 'second');
-    $this->assertFalse($entity->status());
-    $this->assertIdentical($entity->uuid(), $second_uuid);
-
-    // Perform an update.
-    $import = <<<EOD
-id: second
-uuid: $second_uuid
-label: 'Second updated'
-weight: 0
-style: ''
-status: '0'
-EOD;
-    $edit = [
-      'config_type' => 'config_test',
-      'import' => $import,
-    ];
-    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
-    $this->assertRaw(t('Are you sure you want to update the %name @type?', ['%name' => 'second', '@type' => 'test configuration']));
-    $this->drupalPostForm(NULL, [], t('Confirm'));
-    $entity = $storage->load('second');
-    $this->assertRaw(t('The configuration was imported successfully.'));
-    $this->assertIdentical($entity->label(), 'Second updated');
-
-    // Try to perform an update which adds missing dependencies.
-    $import = <<<EOD
-id: second
-uuid: $second_uuid
-label: 'Second updated'
-weight: 0
-style: ''
-status: '0'
-dependencies:
-  module:
-    - does_not_exist
-EOD;
-    $edit = [
-      'config_type' => 'config_test',
-      'import' => $import,
-    ];
-    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
-    $this->assertRaw(t('Configuration %name depends on the %owner module that will not be installed after import.', ['%name' => 'config_test.dynamic.second', '%owner' => 'does_not_exist']));
-
-    // Try to preform an update which would create a PHP object if Yaml parsing
-    // not securely set up.
-    // Perform an update.
-    $import = <<<EOD
-id: second
-uuid: $second_uuid
-label: !php/object "O:36:\"Drupal\\\Core\\\Test\\\ObjectSerialization\":0:{}"
-weight: 0
-style: ''
-status: '0'
-EOD;
-    $edit = [
-      'config_type' => 'config_test',
-      'import' => $import,
-    ];
-    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
-    $this->assertRaw(t('Are you sure you want to update the %name @type?', ['%name' => 'second', '@type' => 'test configuration']));
-    $this->drupalPostForm(NULL, [], t('Confirm'));
-    $entity = $storage->load('second');
-    $this->assertRaw(t('The configuration was imported successfully.'));
-    $this->assertTrue(is_string($entity->label()), 'Entity label is a string');
-    $this->assertTrue(strpos($entity->label(), 'ObjectSerialization') > 0, 'Label contains serialized object');
-  }
-
-  /**
-   * Tests importing a simple configuration file.
-   */
-  public function testImportSimpleConfiguration() {
-    $this->drupalLogin($this->drupalCreateUser(['import configuration']));
-    $config = $this->config('system.site')->set('name', 'Test simple import');
-
-    // Place branding block with site name into header region.
-    $this->drupalPlaceBlock('system_branding_block', ['region' => 'header']);
-
-    $edit = [
-      'config_type' => 'system.simple',
-      'config_name' => $config->getName(),
-      'import' => Yaml::encode($config->get()),
-    ];
-    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
-    $this->assertRaw(t('Are you sure you want to update the %name @type?', ['%name' => $config->getName(), '@type' => 'simple configuration']));
-    $this->drupalPostForm(NULL, [], t('Confirm'));
-    $this->drupalGet('');
-    $this->assertText('Test simple import');
-
-    // Ensure that ConfigImporter validation is running when importing simple
-    // configuration.
-    $config_data = $this->config('core.extension')->get();
-    // Simulate uninstalling the Config module.
-    unset($config_data['module']['config']);
-    $edit = [
-      'config_type' => 'system.simple',
-      'config_name' => 'core.extension',
-      'import' => Yaml::encode($config_data),
-    ];
-    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
-    $this->assertText(t('Can not uninstall the Configuration module as part of a configuration synchronization through the user interface.'));
-
-  }
-
-  /**
-   * Tests exporting a single configuration file.
-   */
-  public function testExport() {
-    $this->drupalLogin($this->drupalCreateUser(['export configuration']));
-
-    $this->drupalGet('admin/config/development/configuration/single/export/system.simple');
-    $this->assertFieldByXPath('//select[@name="config_type"]//option[@selected="selected"]', t('Simple configuration'), 'The simple configuration option is selected when specified in the URL.');
-    // Spot check several known simple configuration files.
-    $element = $this->xpath('//select[@name="config_name"]');
-    $options = $this->getAllOptions($element[0]);
-    $expected_options = ['system.site', 'user.settings'];
-    foreach ($options as &$option) {
-      $option = (string) $option;
-    }
-    $this->assertIdentical($expected_options, array_intersect($expected_options, $options), 'The expected configuration files are listed.');
-
-    $this->drupalGet('admin/config/development/configuration/single/export/system.simple/system.image');
-    $this->assertFieldByXPath('//textarea[@name="export"]', "toolkit: gd\n_core:\n  default_config_hash: durWHaKeBaq4d9Wpi4RqwADj1OufDepcnJuhVLmKN24\n", 'The expected system configuration is displayed.');
-
-    $this->drupalGet('admin/config/development/configuration/single/export/date_format');
-    $this->assertFieldByXPath('//select[@name="config_type"]//option[@selected="selected"]', t('Date format'), 'The date format entity type is selected when specified in the URL.');
-
-    $this->drupalGet('admin/config/development/configuration/single/export/date_format/fallback');
-    $this->assertFieldByXPath('//select[@name="config_name"]//option[@selected="selected"]', t('Fallback date format (fallback)'), 'The fallback date format config entity is selected when specified in the URL.');
-
-    $fallback_date = \Drupal::entityManager()->getStorage('date_format')->load('fallback');
-    $yaml_text = (string) $this->xpath('//textarea[@name="export"]')[0];
-    $this->assertEqual(Yaml::decode($yaml_text), $fallback_date->toArray(), 'The fallback date format config entity export code is displayed.');
-  }
-
-}
diff --git a/core/modules/config/src/Tests/LanguageNegotiationFormOverrideTest.php b/core/modules/config/src/Tests/LanguageNegotiationFormOverrideTest.php
deleted file mode 100644
index ba67960..0000000
--- a/core/modules/config/src/Tests/LanguageNegotiationFormOverrideTest.php
+++ /dev/null
@@ -1,58 +0,0 @@
-<?php
-
-namespace Drupal\config\Tests;
-
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Tests language-negotiation overrides are not on language-negotiation form.
- *
- * @group config
- * @see \Drupal\Core\Form\ConfigFormBase
- */
-class LanguageNegotiationFormOverrideTest extends WebTestBase {
-
-  public static $modules = ['language', 'locale', 'locale_test'];
-
-  /**
-   * Tests that overrides do not affect language-negotiation form values.
-   */
-  public function testFormWithOverride() {
-    $this->drupalLogin($this->rootUser);
-    $overridden_value_en = 'whatever';
-    $overridden_value_es = 'loquesea';
-
-    // Set up an override.
-    $settings['config']['language.negotiation']['url']['prefixes'] = (object) [
-      'value' => ['en' => $overridden_value_en, 'es' => $overridden_value_es],
-      'required' => TRUE,
-    ];
-    $this->writeSettings($settings);
-
-    // Add predefined language.
-    $edit = [
-      'predefined_langcode' => 'es',
-    ];
-    $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
-
-    // Overridden string for language-negotiation should not exist in the form.
-    $this->drupalGet('admin/config/regional/language/detection/url');
-
-    // The language-negotiation form should be found.
-    $this->assertText('Path prefix configuration', 'Language-negotiation form found for English.');
-
-    // The English override should not be found.
-    $this->assertNoFieldByName('prefix[en]', $overridden_value_en, 'Language-negotiation config override not found in English.');
-
-    // Now check the Spanish version of the page for the same thing.
-    $this->drupalGet($overridden_value_es . '/admin/config/regional/language/detection/url');
-
-    // The language-negotiation form should be found.
-    $this->assertText('Path prefix configuration', 'Language-negotiation form found for Spanish using the overridden prefix.');
-
-    // The Spanish override should not be found.
-    $this->assertNoFieldByName('prefix[es]', $overridden_value_es, 'Language-negotiation config override not found in Spanish.');
-
-  }
-
-}
diff --git a/core/modules/config/tests/src/Functional/CacheabilityMetadataConfigOverrideIntegrationTest.php b/core/modules/config/tests/src/Functional/CacheabilityMetadataConfigOverrideIntegrationTest.php
new file mode 100644
index 0000000..09aea50
--- /dev/null
+++ b/core/modules/config/tests/src/Functional/CacheabilityMetadataConfigOverrideIntegrationTest.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\Tests\config\Functional;
+
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests if configuration overrides correctly affect cacheability metadata.
+ *
+ * @group config
+ */
+class CacheabilityMetadataConfigOverrideIntegrationTest extends BrowserTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'block_test',
+    'config_override_integration_test',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // @todo If our block does not contain any content then the cache context
+    //   is not bubbling up and the test fails. Remove this line once the cache
+    //   contexts are properly set. See https://www.drupal.org/node/2529980.
+    \Drupal::state()->set('block_test.content', 'Needs to have some content');
+
+    $this->drupalLogin($this->drupalCreateUser());
+  }
+
+  /**
+   * Tests if config overrides correctly set cacheability metadata.
+   */
+  public function testConfigOverride() {
+    // Check the default (disabled) state of the cache context. The block label
+    // should not be overridden.
+    $this->drupalGet('<front>');
+    $this->assertNoText('Overridden block label');
+
+    // Both the cache context and tag should be present.
+    $this->assertCacheContext('config_override_integration_test');
+    $this->assertCacheTag('config_override_integration_test_tag');
+
+    // Flip the state of the cache context. The block label should now be
+    // overridden.
+    \Drupal::state()->set('config_override_integration_test.enabled', TRUE);
+    $this->drupalGet('<front>');
+    $this->assertText('Overridden block label');
+
+    // Both the cache context and tag should still be present.
+    $this->assertCacheContext('config_override_integration_test');
+    $this->assertCacheTag('config_override_integration_test_tag');
+  }
+
+}
diff --git a/core/modules/config/tests/src/Functional/ConfigEntityFormOverrideTest.php b/core/modules/config/tests/src/Functional/ConfigEntityFormOverrideTest.php
new file mode 100644
index 0000000..2f48a7c
--- /dev/null
+++ b/core/modules/config/tests/src/Functional/ConfigEntityFormOverrideTest.php
@@ -0,0 +1,70 @@
+<?php
+
+namespace Drupal\Tests\config\Functional;
+
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests that config overrides do not bleed through in entity forms and lists.
+ *
+ * @group config
+ */
+class ConfigEntityFormOverrideTest extends BrowserTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['config_test'];
+
+  /**
+   * Tests that overrides do not affect forms or listing screens.
+   */
+  public function testFormsWithOverrides() {
+    $this->drupalLogin($this->drupalCreateUser(['administer site configuration']));
+
+    $original_label = 'Default';
+    $overridden_label = 'Overridden label';
+    $edited_label = 'Edited label';
+
+    $config_test_storage = $this->container->get('entity.manager')->getStorage('config_test');
+
+    // Set up an override.
+    $settings['config']['config_test.dynamic.dotted.default']['label'] = (object) [
+      'value' => $overridden_label,
+      'required' => TRUE,
+    ];
+    $this->writeSettings($settings);
+
+    // Test that the overridden label is loaded with the entity.
+    $this->assertEqual($config_test_storage->load('dotted.default')->label(), $overridden_label);
+
+    // Test that the original label on the listing page is intact.
+    $this->drupalGet('admin/structure/config_test');
+    $this->assertText($original_label);
+    $this->assertNoText($overridden_label);
+
+    // Test that the original label on the editing page is intact.
+    $this->drupalGet('admin/structure/config_test/manage/dotted.default');
+    $elements = $this->xpath('//input[@name="label"]');
+    $this->assertIdentical((string) $elements[0]->getValue(), $original_label);
+    $this->assertNoText($overridden_label);
+
+    // Change to a new label and test that the listing now has the edited label.
+    $edit = [
+      'label' => $edited_label,
+    ];
+    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->drupalGet('admin/structure/config_test');
+    $this->assertNoText($overridden_label);
+    $this->assertText($edited_label);
+
+    // Test that the editing page now has the edited label.
+    $this->drupalGet('admin/structure/config_test/manage/dotted.default');
+    $elements = $this->xpath('//input[@name="label"]');
+    $this->assertIdentical((string) $elements[0]->getValue(), $edited_label);
+
+    // Test that the overridden label is still loaded with the entity.
+    $this->assertEqual($config_test_storage->load('dotted.default')->label(), $overridden_label);
+  }
+
+}
diff --git a/core/modules/config/tests/src/Functional/ConfigEntityListTest.php b/core/modules/config/tests/src/Functional/ConfigEntityListTest.php
new file mode 100644
index 0000000..69ef797
--- /dev/null
+++ b/core/modules/config/tests/src/Functional/ConfigEntityListTest.php
@@ -0,0 +1,278 @@
+<?php
+
+namespace Drupal\Tests\config\Functional;
+
+use Drupal\config_test\Entity\ConfigTest;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests the listing of configuration entities.
+ *
+ * @group config
+ */
+class ConfigEntityListTest extends BrowserTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['block', 'config_test'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    // Delete the override config_test entity since it is not required by this
+    // test.
+    \Drupal::entityManager()->getStorage('config_test')->load('override')->delete();
+    $this->drupalPlaceBlock('local_actions_block');
+  }
+
+  /**
+   * Tests entity list builder methods.
+   */
+  public function testList() {
+    $controller = \Drupal::entityManager()->getListBuilder('config_test');
+
+    // Test getStorage() method.
+    $this->assertTrue($controller->getStorage() instanceof EntityStorageInterface, 'EntityStorage instance in storage.');
+
+    // Get a list of ConfigTest entities and confirm that it contains the
+    // ConfigTest entity provided by the config_test module.
+    // @see config_test.dynamic.dotted.default.yml
+    $list = $controller->load();
+    $this->assertEqual(count($list), 1, '1 ConfigTest entity found.');
+    $entity = $list['dotted.default'];
+    $this->assertTrue(!empty($entity), '"Default" ConfigTest entity ID found.');
+    $this->assertTrue($entity instanceof ConfigTest, '"Default" ConfigTest entity is an instance of ConfigTest.');
+
+    // Test getOperations() method.
+    $expected_operations = [
+      'edit' => [
+        'title' => t('Edit'),
+        'weight' => 10,
+        'url' => $entity->urlInfo(),
+      ],
+      'disable' => [
+        'title' => t('Disable'),
+        'weight' => 40,
+        'url' => $entity->urlInfo('disable'),
+      ],
+      'delete' => [
+        'title' => t('Delete'),
+        'weight' => 100,
+        'url' => $entity->urlInfo('delete-form'),
+      ],
+    ];
+
+    $actual_operations = $controller->getOperations($entity);
+    // Sort the operations to normalize link order.
+    uasort($actual_operations, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
+    $this->assertEqual($expected_operations, $actual_operations, 'The operations are identical.');
+
+    // Test buildHeader() method.
+    $expected_items = [
+      'label' => 'Label',
+      'id' => 'Machine name',
+      'operations' => 'Operations',
+    ];
+    $actual_items = $controller->buildHeader();
+    $this->assertEqual($expected_items, $actual_items, 'Return value from buildHeader matches expected.');
+
+    // Test buildRow() method.
+    $build_operations = $controller->buildOperations($entity);
+    $expected_items = [
+      'label' => 'Default',
+      'id' => 'dotted.default',
+      'operations' => [
+        'data' => $build_operations,
+      ],
+    ];
+    $actual_items = $controller->buildRow($entity);
+    $this->assertEqual($expected_items, $actual_items, 'Return value from buildRow matches expected.');
+    // Test sorting.
+    $storage = $controller->getStorage();
+    $entity = $storage->create([
+      'id' => 'alpha',
+      'label' => 'Alpha',
+      'weight' => 1,
+    ]);
+    $entity->save();
+    $entity = $storage->create([
+      'id' => 'omega',
+      'label' => 'Omega',
+      'weight' => 1,
+    ]);
+    $entity->save();
+    $entity = $storage->create([
+      'id' => 'beta',
+      'label' => 'Beta',
+      'weight' => 0,
+    ]);
+    $entity->save();
+    $list = $controller->load();
+    $this->assertIdentical(array_keys($list), ['beta', 'dotted.default', 'alpha', 'omega']);
+
+    // Test that config entities that do not support status, do not have
+    // enable/disable operations.
+    $controller = $this->container->get('entity.manager')
+      ->getListBuilder('config_test_no_status');
+
+    $list = $controller->load();
+    $entity = $list['default'];
+
+    // Test getOperations() method.
+    $expected_operations = [
+      'edit' => [
+        'title' => t('Edit'),
+        'weight' => 10,
+        'url' => $entity->urlInfo(),
+      ],
+      'delete' => [
+        'title' => t('Delete'),
+        'weight' => 100,
+        'url' => $entity->urlInfo('delete-form'),
+      ],
+    ];
+
+    $actual_operations = $controller->getOperations($entity);
+    // Sort the operations to normalize link order.
+    uasort($actual_operations, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
+    $this->assertEqual($expected_operations, $actual_operations, 'The operations are identical.');
+  }
+
+  /**
+   * Tests the listing UI.
+   */
+  public function testListUI() {
+    // Log in as an administrative user to access the full menu trail.
+    $this->drupalLogin($this->drupalCreateUser(['access administration pages', 'administer site configuration']));
+
+    // Get the list callback page.
+    $this->drupalGet('admin/structure/config_test');
+
+    // Test for the page title.
+    $this->assertTitle('Test configuration | Drupal');
+
+    // Test for the table.
+    $element = $this->xpath('//div[@class="layout-content"]//table');
+    $this->assertTrue($element, 'Configuration entity list table found.');
+
+    // Test the table header.
+    $elements = $this->xpath('//div[@class="layout-content"]//table/thead/tr/th');
+    $this->assertEqual(count($elements), 3, 'Correct number of table header cells found.');
+
+    // Test the contents of each th cell.
+    $expected_items = ['Label', 'Machine name', 'Operations'];
+    foreach ($elements as $key => $element) {
+      $this->assertIdentical($element->getText(), $expected_items[$key]);
+    }
+
+    // Check the number of table row cells.
+    $elements = $this->xpath('//div[@class="layout-content"]//table/tbody/tr[@class="odd"]/td');
+    $this->assertEqual(count($elements), 3, 'Correct number of table row cells found.');
+
+    // Check the contents of each row cell. The first cell contains the label,
+    // the second contains the machine name, and the third contains the
+    // operations list.
+    $this->assertIdentical($elements[0]->getText(), 'Default');
+    $this->assertIdentical($elements[1]->getText(), 'dotted.default');
+    $this->assertNotEmpty($elements[2]->find('xpath', '//ul'), 'Operations list found.');
+
+    // Add a new entity using the operations link.
+    $this->assertLink('Add test configuration');
+    $this->clickLink('Add test configuration');
+    $this->assertResponse(200);
+    $edit = [
+      'label' => 'Antelope',
+      'id' => 'antelope',
+      'weight' => 1,
+    ];
+    $this->drupalPostForm(NULL, $edit, t('Save'));
+
+    // Ensure that the entity's sort method was called.
+    $this->assertTrue(\Drupal::state()->get('config_entity_sort'), 'ConfigTest::sort() was called.');
+
+    // Confirm that the user is returned to the listing, and verify that the
+    // text of the label and machine name appears in the list (versus elsewhere
+    // on the page).
+    $this->assertFieldByXpath('//td', 'Antelope', "Label found for added 'Antelope' entity.");
+    $this->assertFieldByXpath('//td', 'antelope', "Machine name found for added 'Antelope' entity.");
+
+    // Edit the entity using the operations link.
+    $this->assertLinkByHref('admin/structure/config_test/manage/antelope');
+    $this->clickLink('Edit', 1);
+    $this->assertResponse(200);
+    $this->assertTitle('Edit Antelope | Drupal');
+    $edit = ['label' => 'Albatross', 'id' => 'albatross'];
+    $this->drupalPostForm(NULL, $edit, t('Save'));
+
+    // Confirm that the user is returned to the listing, and verify that the
+    // text of the label and machine name appears in the list (versus elsewhere
+    // on the page).
+    $this->assertFieldByXpath('//td', 'Albatross', "Label found for updated 'Albatross' entity.");
+    $this->assertFieldByXpath('//td', 'albatross', "Machine name found for updated 'Albatross' entity.");
+
+    // Delete the added entity using the operations link.
+    $this->assertLinkByHref('admin/structure/config_test/manage/albatross/delete');
+    $this->clickLink('Delete', 1);
+    $this->assertResponse(200);
+    $this->assertTitle('Are you sure you want to delete the test configuration Albatross? | Drupal');
+    $this->drupalPostForm(NULL, [], t('Delete'));
+
+    // Verify that the text of the label and machine name does not appear in
+    // the list (though it may appear elsewhere on the page).
+    $this->assertNoFieldByXpath('//td', 'Albatross', "No label found for deleted 'Albatross' entity.");
+    $this->assertNoFieldByXpath('//td', 'albatross', "No machine name found for deleted 'Albatross' entity.");
+
+    // Delete the original entity using the operations link.
+    $this->clickLink('Delete');
+    $this->assertResponse(200);
+    $this->assertTitle('Are you sure you want to delete the test configuration Default? | Drupal');
+    $this->drupalPostForm(NULL, [], t('Delete'));
+
+    // Verify that the text of the label and machine name does not appear in
+    // the list (though it may appear elsewhere on the page).
+    $this->assertNoFieldByXpath('//td', 'Default', "No label found for deleted 'Default' entity.");
+    $this->assertNoFieldByXpath('//td', 'dotted.default', "No machine name found for deleted 'Default' entity.");
+
+    // Confirm that the empty text is displayed.
+    $this->assertText('There is no Test configuration yet.');
+  }
+
+  /**
+   * Test paging.
+   */
+  public function testPager() {
+    $this->drupalLogin($this->drupalCreateUser(['administer site configuration']));
+
+    $storage = \Drupal::entityManager()->getListBuilder('config_test')->getStorage();
+
+    // Create 51 test entities.
+    for ($i = 1; $i < 52; $i++) {
+      $storage->create([
+        'id' => str_pad($i, 2, '0', STR_PAD_LEFT),
+        'label' => 'Test config entity ' . $i,
+        'weight' => $i,
+        'protected_property' => $i,
+      ])->save();
+    }
+
+    // Load the listing page.
+    $this->drupalGet('admin/structure/config_test');
+
+    // Item 51 should not be present.
+    $this->assertRaw('Test config entity 50', 'Config entity 50 is shown.');
+    $this->assertNoRaw('Test config entity 51', 'Config entity 51 is on the next page.');
+
+    // Browse to the next page.
+    $this->clickLink(t('Page 2'));
+    $this->assertNoRaw('Test config entity 50', 'Test config entity 50 is on the previous page.');
+    $this->assertRaw('dotted.default', 'Default config entity appears on page 2.');
+    $this->assertRaw('Test config entity 51', 'Test config entity 51 is on page 2.');
+  }
+
+}
diff --git a/core/modules/config/tests/src/Functional/ConfigEntityTest.php b/core/modules/config/tests/src/Functional/ConfigEntityTest.php
new file mode 100644
index 0000000..4d0cd3e
--- /dev/null
+++ b/core/modules/config/tests/src/Functional/ConfigEntityTest.php
@@ -0,0 +1,360 @@
+<?php
+
+namespace Drupal\Tests\config\Functional;
+
+use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Entity\EntityMalformedException;
+use Drupal\Core\Entity\EntityStorageException;
+use Drupal\Core\Config\Entity\ConfigEntityStorage;
+use Drupal\Core\Config\Entity\Exception\ConfigEntityIdLengthException;
+use Drupal\Core\Url;
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests configuration entities.
+ *
+ * @group config
+ */
+class ConfigEntityTest extends BrowserTestBase {
+
+  /**
+   * The maximum length for the entity storage used in this test.
+   */
+  const MAX_ID_LENGTH = ConfigEntityStorage::MAX_ID_LENGTH;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['config_test'];
+
+  /**
+   * Tests CRUD operations.
+   */
+  public function testCRUD() {
+    $default_langcode = \Drupal::languageManager()->getDefaultLanguage()->getId();
+    // Verify default properties on a newly created empty entity.
+    $empty = entity_create('config_test');
+    $this->assertTrue($empty->uuid());
+    $this->assertIdentical($empty->label, NULL);
+    $this->assertIdentical($empty->style, NULL);
+    $this->assertIdentical($empty->language()->getId(), $default_langcode);
+
+    // Verify ConfigEntity properties/methods on the newly created empty entity.
+    $this->assertIdentical($empty->isNew(), TRUE);
+    $this->assertIdentical($empty->getOriginalId(), NULL);
+    $this->assertIdentical($empty->bundle(), 'config_test');
+    $this->assertIdentical($empty->id(), NULL);
+    $this->assertTrue($empty->uuid());
+    $this->assertIdentical($empty->label(), NULL);
+
+    $this->assertIdentical($empty->get('id'), NULL);
+    $this->assertTrue($empty->get('uuid'));
+    $this->assertIdentical($empty->get('label'), NULL);
+    $this->assertIdentical($empty->get('style'), NULL);
+    $this->assertIdentical($empty->language()->getId(), $default_langcode);
+
+    // Verify Entity properties/methods on the newly created empty entity.
+    $this->assertIdentical($empty->getEntityTypeId(), 'config_test');
+    // The URI can only be checked after saving.
+    try {
+      $empty->urlInfo();
+      $this->fail('EntityMalformedException was thrown.');
+    }
+    catch (EntityMalformedException $e) {
+      $this->pass('EntityMalformedException was thrown.');
+    }
+
+    // Verify that an empty entity cannot be saved.
+    try {
+      $empty->save();
+      $this->fail('EntityMalformedException was thrown.');
+    }
+    catch (EntityMalformedException $e) {
+      $this->pass('EntityMalformedException was thrown.');
+    }
+
+    // Verify that an entity with an empty ID string is considered empty, too.
+    $empty_id = entity_create('config_test', [
+      'id' => '',
+    ]);
+    $this->assertIdentical($empty_id->isNew(), TRUE);
+    try {
+      $empty_id->save();
+      $this->fail('EntityMalformedException was thrown.');
+    }
+    catch (EntityMalformedException $e) {
+      $this->pass('EntityMalformedException was thrown.');
+    }
+
+    // Verify properties on a newly created entity.
+    $config_test = entity_create('config_test', $expected = [
+      'id' => $this->randomMachineName(),
+      'label' => $this->randomString(),
+      'style' => $this->randomMachineName(),
+    ]);
+    $this->assertTrue($config_test->uuid());
+    $this->assertNotEqual($config_test->uuid(), $empty->uuid());
+    $this->assertIdentical($config_test->label, $expected['label']);
+    $this->assertIdentical($config_test->style, $expected['style']);
+    $this->assertIdentical($config_test->language()->getId(), $default_langcode);
+
+    // Verify methods on the newly created entity.
+    $this->assertIdentical($config_test->isNew(), TRUE);
+    $this->assertIdentical($config_test->getOriginalId(), $expected['id']);
+    $this->assertIdentical($config_test->id(), $expected['id']);
+    $this->assertTrue($config_test->uuid());
+    $expected['uuid'] = $config_test->uuid();
+    $this->assertIdentical($config_test->label(), $expected['label']);
+
+    // Verify that the entity can be saved.
+    try {
+      $status = $config_test->save();
+      $this->pass('EntityMalformedException was not thrown.');
+    }
+    catch (EntityMalformedException $e) {
+      $this->fail('EntityMalformedException was not thrown.');
+    }
+
+    // The entity path can only be checked after saving.
+    $this->assertIdentical($config_test->url(), Url::fromRoute('entity.config_test.edit_form', ['config_test' => $expected['id']])->toString());
+
+    // Verify that the correct status is returned and properties did not change.
+    $this->assertIdentical($status, SAVED_NEW);
+    $this->assertIdentical($config_test->id(), $expected['id']);
+    $this->assertIdentical($config_test->uuid(), $expected['uuid']);
+    $this->assertIdentical($config_test->label(), $expected['label']);
+    $this->assertIdentical($config_test->isNew(), FALSE);
+    $this->assertIdentical($config_test->getOriginalId(), $expected['id']);
+
+    // Save again, and verify correct status and properties again.
+    $status = $config_test->save();
+    $this->assertIdentical($status, SAVED_UPDATED);
+    $this->assertIdentical($config_test->id(), $expected['id']);
+    $this->assertIdentical($config_test->uuid(), $expected['uuid']);
+    $this->assertIdentical($config_test->label(), $expected['label']);
+    $this->assertIdentical($config_test->isNew(), FALSE);
+    $this->assertIdentical($config_test->getOriginalId(), $expected['id']);
+
+    // Verify that a configuration entity can be saved with an ID of the
+    // maximum allowed length, but not longer.
+
+    // Test with a short ID.
+    $id_length_config_test = entity_create('config_test', [
+      'id' => $this->randomMachineName(8),
+    ]);
+    try {
+      $id_length_config_test->save();
+      $this->pass(SafeMarkup::format("config_test entity with ID length @length was saved.", [
+        '@length' => strlen($id_length_config_test->id())]
+      ));
+    }
+    catch (ConfigEntityIdLengthException $e) {
+      $this->fail($e->getMessage());
+    }
+
+    // Test with an ID of the maximum allowed length.
+    $id_length_config_test = entity_create('config_test', [
+      'id' => $this->randomMachineName(static::MAX_ID_LENGTH),
+    ]);
+    try {
+      $id_length_config_test->save();
+      $this->pass(SafeMarkup::format("config_test entity with ID length @length was saved.", [
+        '@length' => strlen($id_length_config_test->id()),
+      ]));
+    }
+    catch (ConfigEntityIdLengthException $e) {
+      $this->fail($e->getMessage());
+    }
+
+    // Test with an ID exceeding the maximum allowed length.
+    $id_length_config_test = entity_create('config_test', [
+      'id' => $this->randomMachineName(static::MAX_ID_LENGTH + 1),
+    ]);
+    try {
+      $status = $id_length_config_test->save();
+      $this->fail(SafeMarkup::format("config_test entity with ID length @length exceeding the maximum allowed length of @max saved successfully", [
+        '@length' => strlen($id_length_config_test->id()),
+        '@max' => static::MAX_ID_LENGTH,
+      ]));
+    }
+    catch (ConfigEntityIdLengthException $e) {
+      $this->pass(SafeMarkup::format("config_test entity with ID length @length exceeding the maximum allowed length of @max failed to save", [
+        '@length' => strlen($id_length_config_test->id()),
+        '@max' => static::MAX_ID_LENGTH,
+      ]));
+    }
+
+    // Ensure that creating an entity with the same id as an existing one is not
+    // possible.
+    $same_id = entity_create('config_test', [
+      'id' => $config_test->id(),
+    ]);
+    $this->assertIdentical($same_id->isNew(), TRUE);
+    try {
+      $same_id->save();
+      $this->fail('Not possible to overwrite an entity entity.');
+    }
+    catch (EntityStorageException $e) {
+      $this->pass('Not possible to overwrite an entity entity.');
+    }
+
+    // Verify that renaming the ID returns correct status and properties.
+    $ids = [$expected['id'], 'second_' . $this->randomMachineName(4), 'third_' . $this->randomMachineName(4)];
+    for ($i = 1; $i < 3; $i++) {
+      $old_id = $ids[$i - 1];
+      $new_id = $ids[$i];
+      // Before renaming, everything should point to the current ID.
+      $this->assertIdentical($config_test->id(), $old_id);
+      $this->assertIdentical($config_test->getOriginalId(), $old_id);
+
+      // Rename.
+      $config_test->set('id', $new_id);
+      $this->assertIdentical($config_test->id(), $new_id);
+      $status = $config_test->save();
+      $this->assertIdentical($status, SAVED_UPDATED);
+      $this->assertIdentical($config_test->isNew(), FALSE);
+
+      // Verify that originalID points to new ID directly after renaming.
+      $this->assertIdentical($config_test->id(), $new_id);
+      $this->assertIdentical($config_test->getOriginalId(), $new_id);
+    }
+
+    // Test config entity prepopulation.
+    \Drupal::state()->set('config_test.prepopulate', TRUE);
+    $config_test = entity_create('config_test', ['foo' => 'bar']);
+    $this->assertEqual($config_test->get('foo'), 'baz', 'Initial value correctly populated');
+  }
+
+  /**
+   * Tests CRUD operations through the UI.
+   */
+  public function testCRUDUI() {
+    $this->drupalLogin($this->drupalCreateUser(['administer site configuration']));
+
+    $id = strtolower($this->randomMachineName());
+    $label1 = $this->randomMachineName();
+    $label2 = $this->randomMachineName();
+    $label3 = $this->randomMachineName();
+    $message_insert = format_string('%label configuration has been created.', ['%label' => $label1]);
+    $message_update = format_string('%label configuration has been updated.', ['%label' => $label2]);
+    $message_delete = format_string('The test configuration %label has been deleted.', ['%label' => $label2]);
+
+    // Create a configuration entity.
+    $edit = [
+      'id' => $id,
+      'label' => $label1,
+    ];
+    $this->drupalPostForm('admin/structure/config_test/add', $edit, 'Save');
+    $this->assertUrl('admin/structure/config_test');
+    $this->assertResponse(200);
+    $this->assertRaw($message_insert);
+    $this->assertNoRaw($message_update);
+    $this->assertLinkByHref("admin/structure/config_test/manage/$id");
+
+    // Update the configuration entity.
+    $edit = [
+      'label' => $label2,
+    ];
+    $this->drupalPostForm("admin/structure/config_test/manage/$id", $edit, 'Save');
+    $this->assertUrl('admin/structure/config_test');
+    $this->assertResponse(200);
+    $this->assertNoRaw($message_insert);
+    $this->assertRaw($message_update);
+    $this->assertLinkByHref("admin/structure/config_test/manage/$id");
+    $this->assertLinkByHref("admin/structure/config_test/manage/$id/delete");
+
+    // Delete the configuration entity.
+    $this->drupalGet("admin/structure/config_test/manage/$id");
+    $this->clickLink(t('Delete'));
+    $this->assertUrl("admin/structure/config_test/manage/$id/delete");
+    $this->drupalPostForm(NULL, [], 'Delete');
+    $this->assertUrl('admin/structure/config_test');
+    $this->assertResponse(200);
+    $this->assertNoRaw($message_update);
+    $this->assertRaw($message_delete);
+    $this->assertNoText($label1);
+    $this->assertNoLinkByHref("admin/structure/config_test/manage/$id");
+
+    // Re-create a configuration entity.
+    $edit = [
+      'id' => $id,
+      'label' => $label1,
+    ];
+    $this->drupalPostForm('admin/structure/config_test/add', $edit, 'Save');
+    $this->assertUrl('admin/structure/config_test');
+    $this->assertResponse(200);
+    $this->assertText($label1);
+    $this->assertLinkByHref("admin/structure/config_test/manage/$id");
+
+    // Rename the configuration entity's ID/machine name.
+    $edit = [
+      'id' => strtolower($this->randomMachineName()),
+      'label' => $label3,
+    ];
+    $this->drupalPostForm("admin/structure/config_test/manage/$id", $edit, 'Save');
+    $this->assertUrl('admin/structure/config_test');
+    $this->assertResponse(200);
+    $this->assertNoText($label1);
+    $this->assertNoText($label2);
+    $this->assertText($label3);
+    $this->assertNoLinkByHref("admin/structure/config_test/manage/$id");
+    $id = $edit['id'];
+    $this->assertLinkByHref("admin/structure/config_test/manage/$id");
+
+    // Create a configuration entity with '0' machine name.
+    $edit = [
+      'id' => '0',
+      'label' => '0',
+    ];
+    $this->drupalPostForm('admin/structure/config_test/add', $edit, 'Save');
+    $this->assertResponse(200);
+    $message_insert = format_string('%label configuration has been created.', ['%label' => $edit['label']]);
+    $this->assertRaw($message_insert);
+    $this->assertLinkByHref('admin/structure/config_test/manage/0');
+    $this->assertLinkByHref('admin/structure/config_test/manage/0/delete');
+    $this->drupalPostForm('admin/structure/config_test/manage/0/delete', [], 'Delete');
+    $this->assertFalse(entity_load('config_test', '0'), 'Test entity deleted');
+
+    // Create a configuration entity with a property that uses AJAX to show
+    // extra form elements.
+    $this->drupalGet('admin/structure/config_test/add');
+
+    // Test that the dependent element is not shown initially.
+    $this->assertFieldByName('size');
+    $this->assertNoFieldByName('size_value');
+
+    $id = strtolower($this->randomMachineName());
+    $edit = [
+      'id' => $id,
+      'label' => $this->randomString(),
+      'size' => 'custom',
+    ];
+    $this->drupalPostAjaxForm(NULL, $edit, 'size');
+
+    // Check that the dependent element is shown after selecting a 'size' value.
+    $this->assertFieldByName('size');
+    $this->assertFieldByName('size_value');
+
+    // Test the same scenario but it in a non-JS case by using a 'js-hidden'
+    // submit button.
+    $this->drupalGet('admin/structure/config_test/add');
+    $this->assertFieldByName('size');
+    $this->assertNoFieldByName('size_value');
+
+    $this->drupalPostForm(NULL, $edit, 'Change size');
+    $this->assertFieldByName('size');
+    $this->assertFieldByName('size_value');
+
+    // Submit the form with the regular 'Save' button and check that the entity
+    // values are correct.
+    $edit += ['size_value' => 'medium'];
+    $this->drupalPostForm(NULL, $edit, 'Save');
+
+    $entity = entity_load('config_test', $id);
+    $this->assertEqual($entity->get('size'), 'custom');
+    $this->assertEqual($entity->get('size_value'), 'medium');
+  }
+
+}
diff --git a/core/modules/config/tests/src/Functional/ConfigExportImportUITest.php b/core/modules/config/tests/src/Functional/ConfigExportImportUITest.php
new file mode 100644
index 0000000..96a80a6
--- /dev/null
+++ b/core/modules/config/tests/src/Functional/ConfigExportImportUITest.php
@@ -0,0 +1,324 @@
+<?php
+
+namespace Drupal\Tests\config\Functional;
+
+use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Archiver\ArchiveTar;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests the user interface for importing/exporting configuration.
+ *
+ * Each testX method does a complete rebuild of a Drupal site, so values being
+ * tested need to be stored in protected properties in order to survive until
+ * the next rebuild.
+ *
+ * @group config
+ */
+class ConfigExportImportUITest extends BrowserTestBase {
+
+  /**
+   * The contents of the config export tarball, held between test methods.
+   *
+   * @var string
+   */
+  protected $tarball;
+
+  /**
+   * Holds the original 'site slogan' before testing.
+   *
+   * @var string
+   */
+  protected $originalSlogan;
+
+  /**
+   * Holds a randomly generated new 'site slogan' for testing.
+   *
+   * @var string
+   */
+  protected $newSlogan;
+
+
+  /**
+   * Holds a content type.
+   *
+   * @var \Drupal\node\NodeInterface
+   */
+  protected $contentType;
+
+  /**
+   * Holds the randomly-generated name of a field.
+   *
+   * @var string
+   */
+  protected $fieldName;
+
+  /**
+   * Holds the field storage entity for $fieldName.
+   *
+   * @var \Drupal\field\FieldStorageConfigInterface
+   */
+  protected $fieldStorage;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['config', 'node', 'field'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    // The initial import must be done with uid 1 because if separately named
+    // roles are created then the role is lost after import. If the roles
+    // created have the same name then the sync will fail because they will
+    // have different UUIDs.
+    $this->drupalLogin($this->rootUser);
+  }
+
+  /**
+   * Tests a simple site export import case.
+   */
+  public function testExportImport() {
+    // After installation there is no snapshot and nothing to import.
+    $this->drupalGet('admin/config/development/configuration');
+    $this->assertNoText(t('Warning message'));
+    $this->assertText(t('There are no configuration changes to import.'));
+
+    $this->originalSlogan = $this->config('system.site')->get('slogan');
+    $this->newSlogan = $this->randomString(16);
+    $this->assertNotEqual($this->newSlogan, $this->originalSlogan);
+    $this->config('system.site')
+      ->set('slogan', $this->newSlogan)
+      ->save();
+    $this->assertEqual($this->config('system.site')->get('slogan'), $this->newSlogan);
+
+    // Create a content type.
+    $this->contentType = $this->drupalCreateContentType();
+
+    // Create a field.
+    $this->fieldName = Unicode::strtolower($this->randomMachineName());
+    $this->fieldStorage = FieldStorageConfig::create([
+      'field_name' => $this->fieldName,
+      'entity_type' => 'node',
+      'type' => 'text',
+    ]);
+    $this->fieldStorage->save();
+    FieldConfig::create([
+      'field_storage' => $this->fieldStorage,
+      'bundle' => $this->contentType->id(),
+    ])->save();
+    // Update the displays so that configuration does not change unexpectedly on
+    // import.
+    entity_get_form_display('node', $this->contentType->id(), 'default')
+      ->setComponent($this->fieldName, [
+        'type' => 'text_textfield',
+      ])
+      ->save();
+    entity_get_display('node', $this->contentType->id(), 'full')
+      ->setComponent($this->fieldName)
+      ->save();
+    entity_get_display('node', $this->contentType->id(), 'default')
+      ->setComponent($this->fieldName)
+      ->save();
+    entity_get_display('node', $this->contentType->id(), 'teaser')
+      ->removeComponent($this->fieldName)
+      ->save();
+
+    $this->drupalGet('node/add/' . $this->contentType->id());
+    $this->assertFieldByName("{$this->fieldName}[0][value]", '', 'Widget is displayed');
+
+    // Export the configuration.
+    $this->drupalPostForm('admin/config/development/configuration/full/export', [], 'Export');
+    $this->tarball = $this->getRawContent();
+
+    $this->config('system.site')
+      ->set('slogan', $this->originalSlogan)
+      ->save();
+    $this->assertEqual($this->config('system.site')->get('slogan'), $this->originalSlogan);
+
+    // Delete the custom field.
+    $fields = FieldConfig::loadMultiple();
+    foreach ($fields as $field) {
+      if ($field->getName() == $this->fieldName) {
+        $field->delete();
+      }
+    }
+    $field_storages = FieldStorageConfig::loadMultiple();
+    foreach ($field_storages as $field_storage) {
+      if ($field_storage->getName() == $this->fieldName) {
+        $field_storage->delete();
+      }
+    }
+    $this->drupalGet('node/add/' . $this->contentType->id());
+    $this->assertNoFieldByName("{$this->fieldName}[0][value]", '', 'Widget is not displayed');
+
+    // Import the configuration.
+    $filename = 'temporary://' . $this->randomMachineName();
+    file_put_contents($filename, $this->tarball);
+    $this->drupalPostForm('admin/config/development/configuration/full/import', ['files[import_tarball]' => $filename], 'Upload');
+    // There is no snapshot yet because an import has never run.
+    $this->assertNoText(t('Warning message'));
+    $this->assertNoText(t('There are no configuration changes to import.'));
+    $this->assertText($this->contentType->label());
+
+    $this->drupalPostForm(NULL, [], 'Import all');
+    // After importing the snapshot has been updated an there are no warnings.
+    $this->assertNoText(t('Warning message'));
+    $this->assertText(t('There are no configuration changes to import.'));
+
+    $this->assertEqual($this->config('system.site')->get('slogan'), $this->newSlogan);
+
+    $this->drupalGet('node/add');
+    $this->assertFieldByName("{$this->fieldName}[0][value]", '', 'Widget is displayed');
+
+    $this->config('system.site')
+      ->set('slogan', $this->originalSlogan)
+      ->save();
+    $this->drupalGet('admin/config/development/configuration');
+    $this->assertText(t('Warning message'));
+    $this->assertText('The following items in your active configuration have changes since the last import that may be lost on the next import.');
+    // Ensure the item is displayed as part of a list (to avoid false matches
+    // on the rest of the page) and that the list markup is not escaped.
+    $this->assertRaw('<li>system.site</li>');
+    // Remove everything from sync. The warning about differences between the
+    // active and snapshot should no longer exist.
+    \Drupal::service('config.storage.sync')->deleteAll();
+    $this->drupalGet('admin/config/development/configuration');
+    $this->assertNoText(t('Warning message'));
+    $this->assertNoText('The following items in your active configuration have changes since the last import that may be lost on the next import.');
+    $this->assertText(t('There are no configuration changes to import.'));
+    // Write a file to sync. The warning about differences between the active
+    // and snapshot should now exist.
+    /** @var \Drupal\Core\Config\StorageInterface $sync */
+    $sync = $this->container->get('config.storage.sync');
+    $data = $this->config('system.site')->get();
+    $data['slogan'] = 'in the face';
+    $this->copyConfig($this->container->get('config.storage'), $sync);
+    $sync->write('system.site', $data);
+    $this->drupalGet('admin/config/development/configuration');
+    $this->assertText(t('Warning message'));
+    $this->assertText('The following items in your active configuration have changes since the last import that may be lost on the next import.');
+    // Ensure the item is displayed as part of a list (to avoid false matches
+    // on the rest of the page) and that the list markup is not escaped.
+    $this->assertRaw('<li>system.site</li>');
+  }
+
+  /**
+   * Tests an export and import of collections.
+   */
+  public function testExportImportCollections() {
+
+    /** @var \Drupal\Core\Config\StorageInterface $active_storage */
+    $active_storage = \Drupal::service('config.storage');
+    $test1_storage = $active_storage->createCollection('collection.test1');
+    $test1_storage->write('config_test.create', ['foo' => 'bar']);
+    $test1_storage->write('config_test.update', ['foo' => 'bar']);
+    $test2_storage = $active_storage->createCollection('collection.test2');
+    $test2_storage->write('config_test.another_create', ['foo' => 'bar']);
+    $test2_storage->write('config_test.another_update', ['foo' => 'bar']);
+
+    // Export the configuration.
+    $this->drupalPostForm('admin/config/development/configuration/full/export', [], 'Export');
+    $this->tarball = $this->getRawContent();
+    $filename = file_directory_temp() . '/' . $this->randomMachineName();
+    file_put_contents($filename, $this->tarball);
+
+    // Set up the active storage collections to test import.
+    $test1_storage->delete('config_test.create');
+    $test1_storage->write('config_test.update', ['foo' => 'baz']);
+    $test1_storage->write('config_test.delete', ['foo' => 'bar']);
+    $test2_storage->delete('config_test.another_create');
+    $test2_storage->write('config_test.another_update', ['foo' => 'baz']);
+    $test2_storage->write('config_test.another_delete', ['foo' => 'bar']);
+
+    // Create a snapshot.
+    $snapshot_storage = \Drupal::service('config.storage.snapshot');
+    \Drupal::service('config.manager')->createSnapshot($active_storage, $snapshot_storage);
+
+    // Ensure that the snapshot has the expected collection data before import.
+    $test1_snapshot = $snapshot_storage->createCollection('collection.test1');
+    $data = $test1_snapshot->read('config_test.delete');
+    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.delete in collection.test1 exists in the snapshot storage.');
+    $data = $test1_snapshot->read('config_test.update');
+    $this->assertEqual($data, ['foo' => 'baz'], 'The config_test.update in collection.test1 exists in the snapshot storage.');
+    $this->assertFalse($test1_snapshot->read('config_test.create'), 'The config_test.create in collection.test1 does not exist in the snapshot storage.');
+    $test2_snapshot = $snapshot_storage->createCollection('collection.test2');
+    $data = $test2_snapshot->read('config_test.another_delete');
+    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.another_delete in collection.test2 exists in the snapshot storage.');
+    $data = $test2_snapshot->read('config_test.another_update');
+    $this->assertEqual($data, ['foo' => 'baz'], 'The config_test.another_update in collection.test2 exists in the snapshot storage.');
+    $this->assertFalse($test2_snapshot->read('config_test.another_create'), 'The config_test.another_create in collection.test2 does not exist in the snapshot storage.');
+
+    // Create the tar that contains the expected content for the collections.
+    $tar = new ArchiveTar($filename, 'gz');
+    $content_list = $tar->listContent();
+    // Convert the list of files into something easy to search.
+    $files = [];
+    foreach ($content_list as $file) {
+      $files[] = $file['filename'];
+    }
+    $this->assertTrue(in_array('collection/test1/config_test.create.yml', $files), 'Config export contains collection/test1/config_test.create.yml.');
+    $this->assertTrue(in_array('collection/test2/config_test.another_create.yml', $files), 'Config export contains collection/test2/config_test.another_create.yml.');
+    $this->assertTrue(in_array('collection/test1/config_test.update.yml', $files), 'Config export contains collection/test1/config_test.update.yml.');
+    $this->assertTrue(in_array('collection/test2/config_test.another_update.yml', $files), 'Config export contains collection/test2/config_test.another_update.yml.');
+    $this->assertFalse(in_array('collection/test1/config_test.delete.yml', $files), 'Config export does not contain collection/test1/config_test.delete.yml.');
+    $this->assertFalse(in_array('collection/test2/config_test.another_delete.yml', $files), 'Config export does not contain collection/test2/config_test.another_delete.yml.');
+
+    $this->drupalPostForm('admin/config/development/configuration/full/import', ['files[import_tarball]' => $filename], 'Upload');
+    // Verify that there are configuration differences to import.
+    $this->drupalGet('admin/config/development/configuration');
+    $this->assertNoText(t('There are no configuration changes to import.'));
+    $this->assertText(t('@collection configuration collection', ['@collection' => 'collection.test1']));
+    $this->assertText(t('@collection configuration collection', ['@collection' => 'collection.test2']));
+    $this->assertText('config_test.create');
+    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test1/config_test.create');
+    $this->assertText('config_test.update');
+    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test1/config_test.update');
+    $this->assertText('config_test.delete');
+    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test1/config_test.delete');
+    $this->assertText('config_test.another_create');
+    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test2/config_test.another_create');
+    $this->assertText('config_test.another_update');
+    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test2/config_test.another_update');
+    $this->assertText('config_test.another_delete');
+    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test2/config_test.another_delete');
+
+    $this->drupalPostForm(NULL, [], 'Import all');
+    $this->assertText(t('There are no configuration changes to import.'));
+
+    // Test data in collections.
+    $data = $test1_storage->read('config_test.create');
+    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.create in collection.test1 has been created.');
+    $data = $test1_storage->read('config_test.update');
+    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.update in collection.test1 has been updated.');
+    $this->assertFalse($test1_storage->read('config_test.delete'), 'The config_test.delete in collection.test1 has been deleted.');
+
+    $data = $test2_storage->read('config_test.another_create');
+    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.another_create in collection.test2 has been created.');
+    $data = $test2_storage->read('config_test.another_update');
+    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.another_update in collection.test2 has been updated.');
+    $this->assertFalse($test2_storage->read('config_test.another_delete'), 'The config_test.another_delete in collection.test2 has been deleted.');
+
+    // Ensure that the snapshot has been updated with the collection data.
+    $snapshot_storage = \Drupal::service('config.storage.snapshot');
+    $test1_snapshot = $snapshot_storage->createCollection('collection.test1');
+    $data = $test1_snapshot->read('config_test.create');
+    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.create in collection.test1 has been created in the snapshot storage.');
+    $data = $test1_snapshot->read('config_test.update');
+    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.update in collection.test1 has been updated in the snapshot storage.');
+    $this->assertFalse($test1_snapshot->read('config_test.delete'), 'The config_test.delete in collection.test1 does not exist in the snapshot storage.');
+    $test2_snapshot = $snapshot_storage->createCollection('collection.test2');
+    $data = $test2_snapshot->read('config_test.another_create');
+    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.another_create in collection.test2 has been created in the snapshot storage.');
+    $data = $test2_snapshot->read('config_test.another_update');
+    $this->assertEqual($data, ['foo' => 'bar'], 'The config_test.another_update in collection.test2 has been updated in the snapshot storage.');
+    $this->assertFalse($test2_snapshot->read('config_test.another_delete'), 'The config_test.another_delete in collection.test2 does not exist in the snapshot storage.');
+  }
+
+}
diff --git a/core/modules/config/tests/src/Functional/ConfigExportUITest.php b/core/modules/config/tests/src/Functional/ConfigExportUITest.php
new file mode 100644
index 0000000..d9bdbc4
--- /dev/null
+++ b/core/modules/config/tests/src/Functional/ConfigExportUITest.php
@@ -0,0 +1,99 @@
+<?php
+
+namespace Drupal\Tests\config\Functional;
+
+use Drupal\Core\Archiver\Tar;
+use Drupal\Core\Serialization\Yaml;
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests the user interface for exporting configuration.
+ *
+ * @group config
+ */
+class ConfigExportUITest extends BrowserTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['config', 'config_test'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // Set up an override.
+    $settings['config']['system.maintenance']['message'] = (object) [
+      'value' => 'Foo',
+      'required' => TRUE,
+    ];
+    $this->writeSettings($settings);
+
+    $this->drupalLogin($this->drupalCreateUser(['export configuration']));
+  }
+
+  /**
+   * Tests export of configuration.
+   */
+  public function testExport() {
+    // Verify the export page with export submit button is available.
+    $this->drupalGet('admin/config/development/configuration/full/export');
+    $this->assertFieldById('edit-submit', t('Export'));
+
+    // Submit the export form and verify response.
+    $this->drupalPostForm('admin/config/development/configuration/full/export', [], t('Export'));
+    $this->assertResponse(200, 'User can access the download callback.');
+
+    // Test if header contains file name with hostname and timestamp.
+    $request = \Drupal::request();
+    $hostname = str_replace('.', '-', $request->getHttpHost());
+    $header_content_disposition = $this->drupalGetHeader('content-disposition');
+    $header_match = (boolean) preg_match('/attachment; filename="config-' . preg_quote($hostname) . '-\d{4}-\d{2}-\d{2}-\d{2}-\d{2}\.tar\.gz"/', $header_content_disposition);
+    $this->assertTrue($header_match, "Header with filename matches the expected format.");
+
+    // Get the archived binary file provided to user for download.
+    $archive_data = $this->getRawContent();
+
+    // Temporarily save the archive file.
+    $uri = file_unmanaged_save_data($archive_data, 'temporary://config.tar.gz');
+
+    // Extract the archive and verify it's not empty.
+    $file_path = file_directory_temp() . '/' . file_uri_target($uri);
+    $archiver = new Tar($file_path);
+    $archive_contents = $archiver->listContents();
+    $this->assert(!empty($archive_contents), 'Downloaded archive file is not empty.');
+
+    // Prepare the list of config files from active storage, see
+    // \Drupal\config\Controller\ConfigController::downloadExport().
+    $storage_active = $this->container->get('config.storage');
+    $config_files = [];
+    foreach ($storage_active->listAll() as $config_name) {
+      $config_files[] = $config_name . '.yml';
+    }
+    // Assert that the downloaded archive file contents are the same as the test
+    // site active store.
+    $this->assertIdentical($archive_contents, $config_files);
+
+    // Ensure the test configuration override is in effect but was not exported.
+    $this->assertIdentical(\Drupal::config('system.maintenance')->get('message'), 'Foo');
+    $archiver->extract(file_directory_temp(), ['system.maintenance.yml']);
+    $file_contents = file_get_contents(file_directory_temp() . '/' . 'system.maintenance.yml');
+    $exported = Yaml::decode($file_contents);
+    $this->assertNotIdentical($exported['message'], 'Foo');
+
+    // Check the single export form doesn't have "form-required" elements.
+    $this->drupalGet('admin/config/development/configuration/single/export');
+    $this->assertNoRaw('js-form-required form-required', 'No form required fields are found.');
+
+    // Ensure the temporary file is not available to users without the
+    // permission.
+    $this->drupalLogout();
+    $this->drupalGet('system/temporary', ['query' => ['file' => 'config.tar.gz']]);
+    $this->assertResponse(403);
+  }
+
+}
diff --git a/core/modules/config/tests/src/Functional/ConfigFormOverrideTest.php b/core/modules/config/tests/src/Functional/ConfigFormOverrideTest.php
new file mode 100644
index 0000000..59276e3
--- /dev/null
+++ b/core/modules/config/tests/src/Functional/ConfigFormOverrideTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\Tests\config\Functional;
+
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests config overrides do not appear on forms that extend ConfigFormBase.
+ *
+ * @group config
+ * @see \Drupal\Core\Form\ConfigFormBase
+ */
+class ConfigFormOverrideTest extends BrowserTestBase {
+
+  /**
+   * Tests that overrides do not affect forms.
+   */
+  public function testFormsWithOverrides() {
+    $this->drupalLogin($this->drupalCreateUser(['access administration pages', 'administer site configuration']));
+
+    $overridden_name = 'Site name global conf override';
+
+    // Set up an override.
+    $settings['config']['system.site']['name'] = (object) [
+      'value' => $overridden_name,
+      'required' => TRUE,
+    ];
+    $this->writeSettings($settings);
+
+    // Test that everything on the form is the same, but that the override
+    // worked for the actual site name.
+    $this->drupalGet('admin/config/system/site-information');
+    $this->assertTitle('Basic site settings | ' . $overridden_name);
+    $elements = $this->xpath('//input[@name="site_name"]');
+    $this->assertIdentical((string) $elements[0]->getValue(), 'Drupal');
+
+    // Submit the form and ensure the site name is not changed.
+    $edit = [
+      'site_name' => 'Custom site name',
+    ];
+    $this->drupalPostForm('admin/config/system/site-information', $edit, t('Save configuration'));
+    $this->assertTitle('Basic site settings | ' . $overridden_name);
+    $elements = $this->xpath('//input[@name="site_name"]');
+    $this->assertIdentical((string) $elements[0]->getValue(), $edit['site_name']);
+  }
+
+}
diff --git a/core/modules/config/tests/src/Functional/ConfigImportAllTest.php b/core/modules/config/tests/src/Functional/ConfigImportAllTest.php
new file mode 100644
index 0000000..0608681
--- /dev/null
+++ b/core/modules/config/tests/src/Functional/ConfigImportAllTest.php
@@ -0,0 +1,162 @@
+<?php
+
+namespace Drupal\Tests\config\Functional;
+
+use Drupal\Core\Config\StorageComparer;
+use Drupal\filter\Entity\FilterFormat;
+use Drupal\shortcut\Entity\Shortcut;
+use Drupal\taxonomy\Entity\Term;
+use Drupal\Tests\SchemaCheckTestTrait;
+use Drupal\Tests\system\Functional\Module\ModuleTestBase;
+
+/**
+ * Tests the largest configuration import possible with all available modules.
+ *
+ * @group config
+ */
+class ConfigImportAllTest extends ModuleTestBase {
+
+  use SchemaCheckTestTrait;
+
+  /**
+   * A user with the 'synchronize configuration' permission.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $webUser;
+
+  /**
+   * The profile to install as a basis for testing.
+   *
+   * Using the standard profile as this has a lot of additional configuration.
+   *
+   * @var string
+   */
+  protected $profile = 'standard';
+
+  protected function setUp() {
+    parent::setUp();
+
+    $this->webUser = $this->drupalCreateUser(['synchronize configuration']);
+    $this->drupalLogin($this->webUser);
+  }
+
+  /**
+   * Tests that a fixed set of modules can be installed and uninstalled.
+   */
+  public function testInstallUninstall() {
+
+    // Get a list of modules to enable.
+    $all_modules = system_rebuild_module_data();
+    $all_modules = array_filter($all_modules, function ($module) {
+      // Filter contrib, hidden, already enabled modules and modules in the
+      // Testing package.
+      if ($module->origin !== 'core' || !empty($module->info['hidden']) || $module->status == TRUE || $module->info['package'] == 'Testing') {
+        return FALSE;
+      }
+      return TRUE;
+    });
+
+    // Install every module possible.
+    \Drupal::service('module_installer')->install(array_keys($all_modules));
+
+    $this->assertModules(array_keys($all_modules), TRUE);
+    foreach ($all_modules as $module => $info) {
+      $this->assertModuleConfig($module);
+      $this->assertModuleTablesExist($module);
+    }
+
+    // Export active config to sync.
+    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
+
+    system_list_reset();
+    $this->resetAll();
+
+    // Delete every field on the site so all modules can be uninstalled. For
+    // example, if a comment field exists then module becomes required and can
+    // not be uninstalled.
+
+    $field_storages = \Drupal::entityManager()->getStorage('field_storage_config')->loadMultiple();
+    \Drupal::entityManager()->getStorage('field_storage_config')->delete($field_storages);
+    // Purge the data.
+    field_purge_batch(1000);
+
+    // Delete all terms.
+    $terms = Term::loadMultiple();
+    entity_delete_multiple('taxonomy_term', array_keys($terms));
+
+    // Delete all filter formats.
+    $filters = FilterFormat::loadMultiple();
+    entity_delete_multiple('filter_format', array_keys($filters));
+
+    // Delete any shortcuts so the shortcut module can be uninstalled.
+    $shortcuts = Shortcut::loadMultiple();
+    entity_delete_multiple('shortcut', array_keys($shortcuts));
+
+    system_list_reset();
+    $all_modules = system_rebuild_module_data();
+
+    // Ensure that only core required modules and the install profile can not be uninstalled.
+    $validation_reasons = \Drupal::service('module_installer')->validateUninstall(array_keys($all_modules));
+    $this->assertEqual(['standard', 'system', 'user'], array_keys($validation_reasons));
+
+    $modules_to_uninstall = array_filter($all_modules, function ($module) use ($validation_reasons) {
+      // Filter required and not enabled modules.
+      if (!empty($module->info['required']) || $module->status == FALSE) {
+        return FALSE;
+      }
+      return TRUE;
+    });
+
+    // Can not uninstall config and use admin/config/development/configuration!
+    unset($modules_to_uninstall['config']);
+
+    $this->assertTrue(isset($modules_to_uninstall['comment']), 'The comment module will be disabled');
+    $this->assertTrue(isset($modules_to_uninstall['file']), 'The File module will be disabled');
+    $this->assertTrue(isset($modules_to_uninstall['editor']), 'The Editor module will be disabled');
+
+    // Uninstall all modules that can be uninstalled.
+    \Drupal::service('module_installer')->uninstall(array_keys($modules_to_uninstall));
+
+    $this->assertModules(array_keys($modules_to_uninstall), FALSE);
+    foreach ($modules_to_uninstall as $module => $info) {
+      $this->assertNoModuleConfig($module);
+      $this->assertModuleTablesDoNotExist($module);
+    }
+
+    // Import the configuration thereby re-installing all the modules.
+    $this->drupalPostForm('admin/config/development/configuration', [], t('Import all'));
+    // Modules have been installed that have services.
+    $this->rebuildContainer();
+
+    // Check that there are no errors.
+    $this->assertIdentical($this->configImporter()->getErrors(), []);
+
+    // Check that all modules that were uninstalled are now reinstalled.
+    $this->assertModules(array_keys($modules_to_uninstall), TRUE);
+    foreach ($modules_to_uninstall as $module => $info) {
+      $this->assertModuleConfig($module);
+      $this->assertModuleTablesExist($module);
+    }
+
+    // Ensure that we have no configuration changes to import.
+    $storage_comparer = new StorageComparer(
+      $this->container->get('config.storage.sync'),
+      $this->container->get('config.storage'),
+      $this->container->get('config.manager')
+    );
+    $this->assertIdentical($storage_comparer->createChangelist()->getChangelist(), $storage_comparer->getEmptyChangelist());
+
+    // Now we have all configuration imported, test all of them for schema
+    // conformance. Ensures all imported default configuration is valid when
+    // all modules are enabled.
+    $names = $this->container->get('config.storage')->listAll();
+    /** @var \Drupal\Core\Config\TypedConfigManagerInterface $typed_config */
+    $typed_config = $this->container->get('config.typed');
+    foreach ($names as $name) {
+      $config = $this->config($name);
+      $this->assertConfigSchema($typed_config, $name, $config->get());
+    }
+  }
+
+}
diff --git a/core/modules/config/tests/src/Functional/ConfigImportInstallProfileTest.php b/core/modules/config/tests/src/Functional/ConfigImportInstallProfileTest.php
new file mode 100644
index 0000000..8b0787d
--- /dev/null
+++ b/core/modules/config/tests/src/Functional/ConfigImportInstallProfileTest.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace Drupal\Tests\config\Functional;
+
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests the importing/exporting configuration based on the install profile.
+ *
+ * @group config
+ */
+class ConfigImportInstallProfileTest extends BrowserTestBase {
+
+  /**
+   * The profile to install as a basis for testing.
+   *
+   * @var string
+   */
+  protected $profile = 'testing_config_import';
+
+  /**
+   * Modules to install.
+   *
+   * @var array
+   */
+  public static $modules = ['config'];
+
+  /**
+   * A user with the 'synchronize configuration' permission.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $webUser;
+
+  protected function setUp() {
+    parent::setUp();
+
+    $this->webUser = $this->drupalCreateUser(['synchronize configuration']);
+    $this->drupalLogin($this->webUser);
+    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
+  }
+
+  /**
+   * Tests config importer cannot uninstall install profiles.
+   *
+   * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber
+   */
+  public function testInstallProfileValidation() {
+    $sync = $this->container->get('config.storage.sync');
+    $this->copyConfig($this->container->get('config.storage'), $sync);
+    $core = $sync->read('core.extension');
+
+    // Ensure install profiles can not be uninstalled.
+    unset($core['module']['testing_config_import']);
+    $sync->write('core.extension', $core);
+
+    $this->drupalPostForm('admin/config/development/configuration', [], t('Import all'));
+    $this->assertText('The configuration cannot be imported because it failed validation for the following reasons:');
+    $this->assertText('Unable to uninstall the Testing config import profile since it is the install profile.');
+
+    // Uninstall dependencies of testing_config_import.
+    $core['module']['testing_config_import'] = 0;
+    unset($core['module']['syslog']);
+    unset($core['theme']['stark']);
+    $core['theme']['stable'] = 0;
+    $core['theme']['classy'] = 0;
+    $sync->write('core.extension', $core);
+    $sync->deleteAll('syslog.');
+    $theme = $sync->read('system.theme');
+    $theme['default'] = 'classy';
+    $sync->write('system.theme', $theme);
+    $this->drupalPostForm('admin/config/development/configuration', [], t('Import all'));
+    $this->assertText('The configuration was imported successfully.');
+    $this->rebuildContainer();
+    $this->assertFalse(\Drupal::moduleHandler()->moduleExists('syslog'), 'The syslog module has been uninstalled.');
+    $this->assertFalse(\Drupal::service('theme_handler')->themeExists('stark'), 'The stark theme has been uninstalled.');
+    $this->assertTrue(\Drupal::service('theme_handler')->themeExists('classy'), 'The classy theme has been installed.');
+  }
+
+}
diff --git a/core/modules/config/tests/src/Functional/ConfigImportUITest.php b/core/modules/config/tests/src/Functional/ConfigImportUITest.php
new file mode 100644
index 0000000..4094af6
--- /dev/null
+++ b/core/modules/config/tests/src/Functional/ConfigImportUITest.php
@@ -0,0 +1,520 @@
+<?php
+
+namespace Drupal\Tests\config\Functional;
+
+use Drupal\Component\Utility\Html;
+use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Config\InstallStorage;
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests the user interface for importing/exporting configuration.
+ *
+ * @group config
+ */
+class ConfigImportUITest extends BrowserTestBase {
+
+  /**
+   * Modules to install.
+   *
+   * @var array
+   */
+  public static $modules = ['config', 'config_test', 'config_import_test', 'text', 'options'];
+
+  /**
+   * A user with the 'synchronize configuration' permission.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $webUser;
+
+  protected function setUp() {
+    parent::setUp();
+
+    $this->webUser = $this->drupalCreateUser(['synchronize configuration']);
+    $this->drupalLogin($this->webUser);
+    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
+  }
+
+  /**
+   * Tests importing configuration.
+   */
+  public function testImport() {
+    $name = 'system.site';
+    $dynamic_name = 'config_test.dynamic.new';
+    /** @var \Drupal\Core\Config\StorageInterface $sync */
+    $sync = $this->container->get('config.storage.sync');
+
+    $this->drupalGet('admin/config/development/configuration');
+    $this->assertText('There are no configuration changes to import.');
+    $this->assertNoFieldById('edit-submit', t('Import all'));
+
+    // Create updated configuration object.
+    $new_site_name = 'Config import test ' . $this->randomString();
+    $this->prepareSiteNameUpdate($new_site_name);
+    $this->assertIdentical($sync->exists($name), TRUE, $name . ' found.');
+
+    // Create new config entity.
+    $original_dynamic_data = [
+      'uuid' => '30df59bd-7b03-4cf7-bb35-d42fc49f0651',
+      'langcode' => \Drupal::languageManager()->getDefaultLanguage()->getId(),
+      'status' => TRUE,
+      'dependencies' => [],
+      'id' => 'new',
+      'label' => 'New',
+      'weight' => 0,
+      'style' => '',
+      'size' => '',
+      'size_value' => '',
+      'protected_property' => '',
+    ];
+    $sync->write($dynamic_name, $original_dynamic_data);
+    $this->assertIdentical($sync->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
+
+    // Enable the Action and Ban modules during import. The Ban
+    // module is used because it creates a table during the install. The Action
+    // module is used because it creates a single simple configuration file
+    // during the install.
+    $core_extension = $this->config('core.extension')->get();
+    $core_extension['module']['action'] = 0;
+    $core_extension['module']['ban'] = 0;
+    $core_extension['module'] = module_config_sort($core_extension['module']);
+    // Bartik is a subtheme of classy so classy must be enabled.
+    $core_extension['theme']['classy'] = 0;
+    $core_extension['theme']['bartik'] = 0;
+    $sync->write('core.extension', $core_extension);
+
+    // Use the install storage so that we can read configuration from modules
+    // and themes that are not installed.
+    $install_storage = new InstallStorage();
+
+    // Set the Bartik theme as default.
+    $system_theme = $this->config('system.theme')->get();
+    $system_theme['default'] = 'bartik';
+    $sync->write('system.theme', $system_theme);
+
+    // Read the action config from module default config folder.
+    $action_settings = $install_storage->read('action.settings');
+    $action_settings['recursion_limit'] = 50;
+    $sync->write('action.settings', $action_settings);
+
+    // Uninstall the Options and Text modules to ensure that dependencies are
+    // handled correctly. Options depends on Text so Text should be installed
+    // first. Since they were enabled during the test setup the core.extension
+    // file in sync will already contain them.
+    \Drupal::service('module_installer')->uninstall(['text', 'options']);
+
+    // Set the state system to record installations and uninstallations.
+    \Drupal::state()->set('ConfigImportUITest.core.extension.modules_installed', []);
+    \Drupal::state()->set('ConfigImportUITest.core.extension.modules_uninstalled', []);
+
+    // Verify that both appear as ready to import.
+    $this->drupalGet('admin/config/development/configuration');
+    $this->assertRaw('<td>' . $name);
+    $this->assertRaw('<td>' . $dynamic_name);
+    $this->assertRaw('<td>core.extension');
+    $this->assertRaw('<td>system.theme');
+    $this->assertRaw('<td>action.settings');
+    $this->assertFieldById('edit-submit', t('Import all'));
+
+    // Import and verify that both do not appear anymore.
+    $this->drupalPostForm(NULL, [], t('Import all'));
+    $this->assertNoRaw('<td>' . $name);
+    $this->assertNoRaw('<td>' . $dynamic_name);
+    $this->assertNoRaw('<td>core.extension');
+    $this->assertNoRaw('<td>system.theme');
+    $this->assertNoRaw('<td>action.settings');
+
+    $this->assertNoFieldById('edit-submit', t('Import all'));
+
+    // Verify that there are no further changes to import.
+    $this->assertText(t('There are no configuration changes to import.'));
+
+    // Verify site name has changed.
+    $this->assertIdentical($new_site_name, $this->config('system.site')->get('name'));
+
+    // Verify that new config entity exists.
+    $this->assertIdentical($original_dynamic_data, $this->config($dynamic_name)->get());
+
+    // Verify the cache got cleared.
+    $this->assertTrue(isset($GLOBALS['hook_cache_flush']));
+
+    $this->rebuildContainer();
+    $this->assertTrue(\Drupal::moduleHandler()->moduleExists('ban'), 'Ban module installed during import.');
+    $this->assertTrue(\Drupal::database()->schema()->tableExists('ban_ip'), 'The database table ban_ip exists.');
+    $this->assertTrue(\Drupal::moduleHandler()->moduleExists('action'), 'Action module installed during import.');
+    $this->assertTrue(\Drupal::moduleHandler()->moduleExists('options'), 'Options module installed during import.');
+    $this->assertTrue(\Drupal::moduleHandler()->moduleExists('text'), 'Text module installed during import.');
+
+    $theme_info = \Drupal::service('theme_handler')->listInfo();
+    $this->assertTrue($theme_info['bartik']->status, 'Bartik theme installed during import.');
+
+    // Ensure installations and uninstallation occur as expected.
+    $installed = \Drupal::state()->get('ConfigImportUITest.core.extension.modules_installed', []);
+    $uninstalled = \Drupal::state()->get('ConfigImportUITest.core.extension.modules_uninstalled', []);
+    $expected = ['action', 'ban', 'text', 'options'];
+    $this->assertIdentical($expected, $installed, 'Action, Ban, Text and Options modules installed in the correct order.');
+    $this->assertTrue(empty($uninstalled), 'No modules uninstalled during import');
+
+    // Verify that the action.settings configuration object was only written
+    // once during the import process and only with the value set in the staged
+    // configuration. This verifies that the module's default configuration is
+    // used during configuration import and, additionally, that after installing
+    // a module, that configuration is not synced twice.
+    $recursion_limit_values = \Drupal::state()->get('ConfigImportUITest.action.settings.recursion_limit', []);
+    $this->assertIdentical($recursion_limit_values, [50]);
+
+    $core_extension = $this->config('core.extension')->get();
+    unset($core_extension['module']['action']);
+    unset($core_extension['module']['ban']);
+    unset($core_extension['module']['options']);
+    unset($core_extension['module']['text']);
+    unset($core_extension['theme']['bartik']);
+    $sync->write('core.extension', $core_extension);
+    $sync->delete('action.settings');
+    $sync->delete('text.settings');
+
+    $system_theme = $this->config('system.theme')->get();
+    $system_theme['default'] = 'stark';
+    $system_theme['admin'] = 'stark';
+    $sync->write('system.theme', $system_theme);
+
+    // Set the state system to record installations and uninstallations.
+    \Drupal::state()->set('ConfigImportUITest.core.extension.modules_installed', []);
+    \Drupal::state()->set('ConfigImportUITest.core.extension.modules_uninstalled', []);
+
+    // Verify that both appear as ready to import.
+    $this->drupalGet('admin/config/development/configuration');
+    $this->assertRaw('<td>core.extension');
+    $this->assertRaw('<td>system.theme');
+    $this->assertRaw('<td>action.settings');
+
+    // Import and verify that both do not appear anymore.
+    $this->drupalPostForm(NULL, [], t('Import all'));
+    $this->assertNoRaw('<td>core.extension');
+    $this->assertNoRaw('<td>system.theme');
+    $this->assertNoRaw('<td>action.settings');
+
+    $this->rebuildContainer();
+    $this->assertFalse(\Drupal::moduleHandler()->moduleExists('ban'), 'Ban module uninstalled during import.');
+    $this->assertFalse(\Drupal::database()->schema()->tableExists('ban_ip'), 'The database table ban_ip does not exist.');
+    $this->assertFalse(\Drupal::moduleHandler()->moduleExists('action'), 'Action module uninstalled during import.');
+    $this->assertFalse(\Drupal::moduleHandler()->moduleExists('options'), 'Options module uninstalled during import.');
+    $this->assertFalse(\Drupal::moduleHandler()->moduleExists('text'), 'Text module uninstalled during import.');
+
+    // Ensure installations and uninstallation occur as expected.
+    $installed = \Drupal::state()->get('ConfigImportUITest.core.extension.modules_installed', []);
+    $uninstalled = \Drupal::state()->get('ConfigImportUITest.core.extension.modules_uninstalled', []);
+    $expected = ['options', 'text', 'ban', 'action'];
+    $this->assertIdentical($expected, $uninstalled, 'Options, Text, Ban and Action modules uninstalled in the correct order.');
+    $this->assertTrue(empty($installed), 'No modules installed during import');
+
+    $theme_info = \Drupal::service('theme_handler')->listInfo();
+    $this->assertFalse(isset($theme_info['bartik']), 'Bartik theme uninstalled during import.');
+
+    // Verify that the action.settings configuration object was only deleted
+    // once during the import process.
+    $delete_called = \Drupal::state()->get('ConfigImportUITest.action.settings.delete', 0);
+    $this->assertIdentical($delete_called, 1, "The action.settings configuration was deleted once during configuration import.");
+  }
+
+  /**
+   * Tests concurrent importing of configuration.
+   */
+  public function testImportLock() {
+    // Create updated configuration object.
+    $new_site_name = 'Config import test ' . $this->randomString();
+    $this->prepareSiteNameUpdate($new_site_name);
+
+    // Verify that there are configuration differences to import.
+    $this->drupalGet('admin/config/development/configuration');
+    $this->assertNoText(t('There are no configuration changes to import.'));
+
+    // Acquire a fake-lock on the import mechanism.
+    $config_importer = $this->configImporter();
+    $this->container->get('lock.persistent')->acquire($config_importer::LOCK_NAME);
+
+    // Attempt to import configuration and verify that an error message appears.
+    $this->drupalPostForm(NULL, [], t('Import all'));
+    $this->assertText(t('Another request may be synchronizing configuration already.'));
+
+    // Release the lock, just to keep testing sane.
+    $this->container->get('lock.persistent')->release($config_importer::LOCK_NAME);
+
+    // Verify site name has not changed.
+    $this->assertNotEqual($new_site_name, $this->config('system.site')->get('name'));
+  }
+
+  /**
+   * Tests verification of site UUID before importing configuration.
+   */
+  public function testImportSiteUuidValidation() {
+    $sync = \Drupal::service('config.storage.sync');
+    // Create updated configuration object.
+    $config_data = $this->config('system.site')->get();
+    // Generate a new site UUID.
+    $config_data['uuid'] = \Drupal::service('uuid')->generate();
+    $sync->write('system.site', $config_data);
+
+    // Verify that there are configuration differences to import.
+    $this->drupalGet('admin/config/development/configuration');
+    $this->assertText(t('The staged configuration cannot be imported, because it originates from a different site than this site. You can only synchronize configuration between cloned instances of this site.'));
+    $this->assertNoFieldById('edit-submit', t('Import all'));
+  }
+
+  /**
+   * Tests the screen that shows differences between active and sync.
+   */
+  public function testImportDiff() {
+    $sync = $this->container->get('config.storage.sync');
+    $config_name = 'config_test.system';
+    $change_key = 'foo';
+    $remove_key = '404';
+    $add_key = 'biff';
+    $add_data = '<em>bangpow</em>';
+    $change_data = '<p><em>foobar</em></p>';
+    $original_data = [
+      'foo' => '<p>foobar</p>',
+      'baz' => '<strong>no change</strong>',
+      '404' => '<em>herp</em>',
+    ];
+    // Update active storage to have html in config data.
+    $this->config($config_name)->setData($original_data)->save();
+
+    // Change a configuration value in sync.
+    $sync_data = $original_data;
+    $sync_data[$change_key] = $change_data;
+    $sync_data[$add_key] = $add_data;
+    unset($sync_data[$remove_key]);
+    $sync->write($config_name, $sync_data);
+
+    // Load the diff UI and verify that the diff reflects the change.
+    $this->drupalGet('admin/config/development/configuration/sync/diff/' . $config_name);
+    $this->assertNoRaw('&amp;nbsp;');
+    $this->assertTitle(format_string('View changes of @config_name | Drupal', ['@config_name' => $config_name]));
+
+    // The following assertions do not use $this::assertEscaped() because
+    // \Drupal\Component\Diff\DiffFormatter adds markup that signifies what has
+    // changed.
+
+    // Changed values are escaped.
+    $this->assertText(Html::escape("foo: '<p><em>foobar</em></p>'"));
+    $this->assertText(Html::escape("foo: '<p>foobar</p>'"));
+    // The no change values are escaped.
+    $this->assertText(Html::escape("baz: '<strong>no change</strong>'"));
+    // Added value is escaped.
+    $this->assertText(Html::escape("biff: '<em>bangpow</em>'"));
+    // Deleted value is escaped.
+    $this->assertText(Html::escape("404: '<em>herp</em>'"));
+
+    // Verify diff colors are displayed.
+    $result = $this->xpath('//table[contains(@class, :class)]', [':class' => 'diff']);
+    $this->assertEqual(count($result), 1, "Diff UI is displaying colors.");
+
+    // Reset data back to original, and remove a key
+    $sync_data = $original_data;
+    unset($sync_data[$remove_key]);
+    $sync->write($config_name, $sync_data);
+
+    // Load the diff UI and verify that the diff reflects a removed key.
+    $this->drupalGet('admin/config/development/configuration/sync/diff/' . $config_name);
+    // The no change values are escaped.
+    $this->assertText(Html::escape("foo: '<p>foobar</p>'"));
+    $this->assertText(Html::escape("baz: '<strong>no change</strong>'"));
+    // Removed key is escaped.
+    $this->assertText(Html::escape("404: '<em>herp</em>'"));
+
+    // Reset data back to original and add a key
+    $sync_data = $original_data;
+    $sync_data[$add_key] = $add_data;
+    $sync->write($config_name, $sync_data);
+
+    // Load the diff UI and verify that the diff reflects an added key.
+    $this->drupalGet('admin/config/development/configuration/sync/diff/' . $config_name);
+    // The no change values are escaped.
+    $this->assertText(Html::escape("baz: '<strong>no change</strong>'"));
+    $this->assertText(Html::escape("404: '<em>herp</em>'"));
+    // Added key is escaped.
+    $this->assertText(Html::escape("biff: '<em>bangpow</em>'"));
+  }
+
+  /**
+   * Tests that multiple validation errors are listed on the page.
+   */
+  public function testImportValidation() {
+    // Set state value so that
+    // \Drupal\config_import_test\EventSubscriber::onConfigImportValidate() logs
+    // validation errors.
+    \Drupal::state()->set('config_import_test.config_import_validate_fail', TRUE);
+    // Ensure there is something to import.
+    $new_site_name = 'Config import test ' . $this->randomString();
+    $this->prepareSiteNameUpdate($new_site_name);
+
+    $this->drupalGet('admin/config/development/configuration');
+    $this->assertNoText(t('There are no configuration changes to import.'));
+    $this->drupalPostForm(NULL, [], t('Import all'));
+
+    // Verify that the validation messages appear.
+    $this->assertText('The configuration cannot be imported because it failed validation for the following reasons:');
+    $this->assertText('Config import validate error 1.');
+    $this->assertText('Config import validate error 2.');
+
+    // Verify site name has not changed.
+    $this->assertNotEqual($new_site_name, $this->config('system.site')->get('name'));
+  }
+
+  public function testConfigUninstallConfigException() {
+    $sync = $this->container->get('config.storage.sync');
+
+    $core_extension = $this->config('core.extension')->get();
+    unset($core_extension['module']['config']);
+    $sync->write('core.extension', $core_extension);
+
+    $this->drupalGet('admin/config/development/configuration');
+    $this->assertText('core.extension');
+
+    // Import and verify that both do not appear anymore.
+    $this->drupalPostForm(NULL, [], t('Import all'));
+    $this->assertText('Can not uninstall the Configuration module as part of a configuration synchronization through the user interface.');
+  }
+
+  public function prepareSiteNameUpdate($new_site_name) {
+    $sync = $this->container->get('config.storage.sync');
+    // Create updated configuration object.
+    $config_data = $this->config('system.site')->get();
+    $config_data['name'] = $new_site_name;
+    $sync->write('system.site', $config_data);
+  }
+
+  /**
+   * Tests an import that results in an error.
+   */
+  public function testImportErrorLog() {
+    $name_primary = 'config_test.dynamic.primary';
+    $name_secondary = 'config_test.dynamic.secondary';
+    $sync = $this->container->get('config.storage.sync');
+    $uuid = $this->container->get('uuid');
+
+    $values_primary = [
+      'uuid' => $uuid->generate(),
+      'langcode' => 'en',
+      'status' => TRUE,
+      'dependencies' => [],
+      'id' => 'primary',
+      'label' => 'Primary',
+      'weight' => 0,
+      'style' => NULL,
+      'size' => NULL,
+      'size_value' => NULL,
+      'protected_property' => NULL,
+    ];
+    $sync->write($name_primary, $values_primary);
+    $values_secondary = [
+      'uuid' => $uuid->generate(),
+      'langcode' => 'en',
+      'status' => TRUE,
+      // Add a dependency on primary, to ensure that is synced first.
+      'dependencies' => [
+        'config' => [$name_primary],
+      ],
+      'id' => 'secondary',
+      'label' => 'Secondary Sync',
+      'weight' => 0,
+      'style' => NULL,
+      'size' => NULL,
+      'size_value' => NULL,
+      'protected_property' => NULL,
+    ];
+    $sync->write($name_secondary, $values_secondary);
+    // Verify that there are configuration differences to import.
+    $this->drupalGet('admin/config/development/configuration');
+    $this->assertNoText(t('There are no configuration changes to import.'));
+
+    // Attempt to import configuration and verify that an error message appears.
+    $this->drupalPostForm(NULL, [], t('Import all'));
+    $this->assertText(SafeMarkup::format('Deleted and replaced configuration entity "@name"', ['@name' => $name_secondary]));
+    $this->assertText(t('The configuration was imported with errors.'));
+    $this->assertNoText(t('The configuration was imported successfully.'));
+    $this->assertText(t('There are no configuration changes to import.'));
+  }
+
+  /**
+   * Tests the config importer cannot delete bundles with existing entities.
+   *
+   * @see \Drupal\Core\Entity\Event\BundleConfigImportValidate
+   */
+  public function testEntityBundleDelete() {
+    \Drupal::service('module_installer')->install(['node']);
+    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
+
+    $node_type = $this->drupalCreateContentType();
+    $node = $this->drupalCreateNode(['type' => $node_type->id()]);
+    $this->drupalGet('admin/config/development/configuration');
+    // The node type, body field and entity displays will be scheduled for
+    // removal.
+    $this->assertText(format_string('node.type.@type', ['@type' => $node_type->id()]));
+    $this->assertText(format_string('field.field.node.@type.body', ['@type' => $node_type->id()]));
+    $this->assertText(format_string('core.entity_view_display.node.@type.teaser', ['@type' => $node_type->id()]));
+    $this->assertText(format_string('core.entity_view_display.node.@type.default', ['@type' => $node_type->id()]));
+    $this->assertText(format_string('core.entity_form_display.node.@type.default', ['@type' => $node_type->id()]));
+
+    // Attempt to import configuration and verify that an error message appears
+    // and the node type, body field and entity displays are still scheduled for
+    // removal.
+    $this->drupalPostForm(NULL, [], t('Import all'));
+    $validation_message = t('Entities exist of type %entity_type and %bundle_label %bundle. These entities need to be deleted before importing.', ['%entity_type' => $node->getEntityType()->getLabel(), '%bundle_label' => $node->getEntityType()->getBundleLabel(), '%bundle' => $node_type->label()]);
+    $this->assertRaw($validation_message);
+    $this->assertText(format_string('node.type.@type', ['@type' => $node_type->id()]));
+    $this->assertText(format_string('field.field.node.@type.body', ['@type' => $node_type->id()]));
+    $this->assertText(format_string('core.entity_view_display.node.@type.teaser', ['@type' => $node_type->id()]));
+    $this->assertText(format_string('core.entity_view_display.node.@type.default', ['@type' => $node_type->id()]));
+    $this->assertText(format_string('core.entity_form_display.node.@type.default', ['@type' => $node_type->id()]));
+
+    // Delete the node and try to import again.
+    $node->delete();
+    $this->drupalPostForm(NULL, [], t('Import all'));
+    $this->assertNoRaw($validation_message);
+    $this->assertText(t('There are no configuration changes to import.'));
+    $this->assertNoText(format_string('node.type.@type', ['@type' => $node_type->id()]));
+    $this->assertNoText(format_string('field.field.node.@type.body', ['@type' => $node_type->id()]));
+    $this->assertNoText(format_string('core.entity_view_display.node.@type.teaser', ['@type' => $node_type->id()]));
+    $this->assertNoText(format_string('core.entity_view_display.node.@type.default', ['@type' => $node_type->id()]));
+    $this->assertNoText(format_string('core.entity_form_display.node.@type.default', ['@type' => $node_type->id()]));
+  }
+
+  /**
+   * Tests config importer cannot uninstall extensions which are depended on.
+   *
+   * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber
+   */
+  public function testExtensionValidation() {
+    \Drupal::service('module_installer')->install(['node']);
+    \Drupal::service('theme_handler')->install(['bartik']);
+    $this->rebuildContainer();
+
+    $sync = $this->container->get('config.storage.sync');
+    $this->copyConfig($this->container->get('config.storage'), $sync);
+    $core = $sync->read('core.extension');
+    // Node depends on text.
+    unset($core['module']['text']);
+    $module_data = system_rebuild_module_data();
+    $this->assertTrue(isset($module_data['node']->requires['text']), 'The Node module depends on the Text module.');
+    // Bartik depends on classy.
+    unset($core['theme']['classy']);
+    $theme_data = \Drupal::service('theme_handler')->rebuildThemeData();
+    $this->assertTrue(isset($theme_data['bartik']->requires['classy']), 'The Bartik theme depends on the Classy theme.');
+    // This module does not exist.
+    $core['module']['does_not_exist'] = 0;
+    // This theme does not exist.
+    $core['theme']['does_not_exist'] = 0;
+    $sync->write('core.extension', $core);
+
+    $this->drupalPostForm('admin/config/development/configuration', [], t('Import all'));
+    $this->assertText('The configuration cannot be imported because it failed validation for the following reasons:');
+    $this->assertText('Unable to uninstall the Text module since the Node module is installed.');
+    $this->assertText('Unable to uninstall the Classy theme since the Bartik theme is installed.');
+    $this->assertText('Unable to install the does_not_exist module since it does not exist.');
+    $this->assertText('Unable to install the does_not_exist theme since it does not exist.');
+  }
+
+}
diff --git a/core/modules/config/tests/src/Functional/ConfigImportUploadTest.php b/core/modules/config/tests/src/Functional/ConfigImportUploadTest.php
new file mode 100644
index 0000000..8271a04
--- /dev/null
+++ b/core/modules/config/tests/src/Functional/ConfigImportUploadTest.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\Tests\config\Functional;
+
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests importing configuration from an uploaded file.
+ *
+ * @group config
+ */
+class ConfigImportUploadTest extends BrowserTestBase {
+
+  /**
+   * A user with the 'import configuration' permission.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $webUser;
+
+  /**
+   * Modules to install.
+   *
+   * @var array
+   */
+  public static $modules = ['config'];
+
+  protected function setUp() {
+    parent::setUp();
+
+    $this->webUser = $this->drupalCreateUser(['import configuration']);
+    $this->drupalLogin($this->webUser);
+  }
+
+  /**
+   * Tests importing configuration.
+   */
+  public function testImport() {
+    // Verify access to the config upload form.
+    $this->drupalGet('admin/config/development/configuration/full/import');
+    $this->assertResponse(200);
+
+    // Attempt to upload a non-tar file.
+    $text_file = current($this->drupalGetTestFiles('text'));
+    $edit = ['files[import_tarball]' => drupal_realpath($text_file->uri)];
+    $this->drupalPostForm('admin/config/development/configuration/full/import', $edit, t('Upload'));
+    $this->assertText(t('Could not extract the contents of the tar file'));
+
+    // Make the sync directory read-only.
+    $directory = config_get_config_directory(CONFIG_SYNC_DIRECTORY);
+    \Drupal::service('file_system')->chmod($directory, 0555);
+    $this->drupalGet('admin/config/development/configuration/full/import');
+    $this->assertRaw(t('The directory %directory is not writable.', ['%directory' => $directory]));
+    // Ensure submit button for \Drupal\config\Form\ConfigImportForm is
+    // disabled.
+    $submit_is_disabled = $this->cssSelect('form.config-import-form input[type="submit"]:disabled');
+    $this->assertTrue(count($submit_is_disabled) === 1, 'The submit button is disabled.');
+  }
+
+}
diff --git a/core/modules/config/tests/src/Functional/ConfigInstallWebTest.php b/core/modules/config/tests/src/Functional/ConfigInstallWebTest.php
new file mode 100644
index 0000000..b12f17e
--- /dev/null
+++ b/core/modules/config/tests/src/Functional/ConfigInstallWebTest.php
@@ -0,0 +1,213 @@
+<?php
+
+namespace Drupal\Tests\config\Functional;
+
+use Drupal\Core\Config\PreExistingConfigException;
+use Drupal\Core\Config\StorageInterface;
+use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests installation and removal of configuration objects in install, disable
+ * and uninstall functionality.
+ *
+ * @group config
+ */
+class ConfigInstallWebTest extends BrowserTestBase {
+
+  /**
+   * The admin user used in this test.
+   */
+  protected $adminUser;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->adminUser = $this->drupalCreateUser(['administer modules', 'administer themes', 'administer site configuration']);
+
+    // Ensure the global variable being asserted by this test does not exist;
+    // a previous test executed in this request/process might have set it.
+    unset($GLOBALS['hook_config_test']);
+  }
+
+  /**
+   * Tests module re-installation.
+   */
+  public function testIntegrationModuleReinstallation() {
+    $default_config = 'config_integration_test.settings';
+    $default_configuration_entity = 'config_test.dynamic.config_integration_test';
+
+    // Install the config_test module we're integrating with.
+    \Drupal::service('module_installer')->install(['config_test']);
+
+    // Verify the configuration does not exist prior to installation.
+    $config_static = $this->config($default_config);
+    $this->assertIdentical($config_static->isNew(), TRUE);
+    $config_entity = $this->config($default_configuration_entity);
+    $this->assertIdentical($config_entity->isNew(), TRUE);
+
+    // Install the integration module.
+    \Drupal::service('module_installer')->install(['config_integration_test']);
+
+    // Verify that default module config exists.
+    \Drupal::configFactory()->reset($default_config);
+    \Drupal::configFactory()->reset($default_configuration_entity);
+    $config_static = $this->config($default_config);
+    $this->assertIdentical($config_static->isNew(), FALSE);
+    $this->assertIdentical($config_static->get('foo'), 'default setting');
+    $config_entity = $this->config($default_configuration_entity);
+    $this->assertIdentical($config_entity->isNew(), FALSE);
+    $this->assertIdentical($config_entity->get('label'), 'Default integration config label');
+
+    // Customize both configuration objects.
+    $config_static->set('foo', 'customized setting')->save();
+    $config_entity->set('label', 'Customized integration config label')->save();
+
+    // @todo FIXME: Setting config keys WITHOUT SAVING retains the changed config
+    //   object in memory. Every new call to $this->config() MUST revert in-memory changes
+    //   that haven't been saved!
+    //   In other words: This test passes even without this reset, but it shouldn't.
+    $this->container->get('config.factory')->reset();
+
+    // Disable and uninstall the integration module.
+    $this->container->get('module_installer')->uninstall(['config_integration_test']);
+
+    // Verify the integration module's config was uninstalled.
+    $config_static = $this->config($default_config);
+    $this->assertIdentical($config_static->isNew(), TRUE);
+
+    // Verify the integration config still exists.
+    $config_entity = $this->config($default_configuration_entity);
+    $this->assertIdentical($config_entity->isNew(), FALSE);
+    $this->assertIdentical($config_entity->get('label'), 'Customized integration config label');
+
+    // Reinstall the integration module.
+    try {
+      \Drupal::service('module_installer')->install(['config_integration_test']);
+      $this->fail('Expected PreExistingConfigException not thrown.');
+    }
+    catch (PreExistingConfigException $e) {
+      $this->assertEqual($e->getExtension(), 'config_integration_test');
+      $this->assertEqual($e->getConfigObjects(), [StorageInterface::DEFAULT_COLLECTION => ['config_test.dynamic.config_integration_test']]);
+      $this->assertEqual($e->getMessage(), 'Configuration objects (config_test.dynamic.config_integration_test) provided by config_integration_test already exist in active configuration');
+    }
+
+    // Delete the configuration entity so that the install will work.
+    $config_entity->delete();
+    \Drupal::service('module_installer')->install(['config_integration_test']);
+
+    // Verify the integration module's config was re-installed.
+    \Drupal::configFactory()->reset($default_config);
+    \Drupal::configFactory()->reset($default_configuration_entity);
+    $config_static = $this->config($default_config);
+    $this->assertIdentical($config_static->isNew(), FALSE);
+    $this->assertIdentical($config_static->get('foo'), 'default setting');
+
+    // Verify the integration config is using the default.
+    $config_entity = \Drupal::config($default_configuration_entity);
+    $this->assertIdentical($config_entity->isNew(), FALSE);
+    $this->assertIdentical($config_entity->get('label'), 'Default integration config label');
+  }
+
+  /**
+   * Tests pre-existing configuration detection.
+   */
+  public function testPreExistingConfigInstall() {
+    $this->drupalLogin($this->adminUser);
+
+    // Try to install config_install_fail_test and config_test. Doing this
+    // will install the config_test module first because it is a dependency of
+    // config_install_fail_test.
+    // @see \Drupal\system\Form\ModulesListForm::submitForm()
+    $this->drupalPostForm('admin/modules', ['modules[config_test][enable]' => TRUE, 'modules[config_install_fail_test][enable]' => TRUE], t('Install'));
+    $this->assertRaw('Unable to install Configuration install fail test, <em class="placeholder">config_test.dynamic.dotted.default</em> already exists in active configuration.');
+
+    // Uninstall the config_test module to test the confirm form.
+    $this->drupalPostForm('admin/modules/uninstall', ['uninstall[config_test]' => TRUE], t('Uninstall'));
+    $this->drupalPostForm(NULL, [], t('Uninstall'));
+
+    // Try to install config_install_fail_test without selecting config_test.
+    // The user is shown a confirm form because the config_test module is a
+    // dependency.
+    // @see \Drupal\system\Form\ModulesListConfirmForm::submitForm()
+    $this->drupalPostForm('admin/modules', ['modules[config_install_fail_test][enable]' => TRUE], t('Install'));
+    $this->drupalPostForm(NULL, [], t('Continue'));
+    $this->assertRaw('Unable to install Configuration install fail test, <em class="placeholder">config_test.dynamic.dotted.default</em> already exists in active configuration.');
+
+    // Test that collection configuration clashes during a module install are
+    // reported correctly.
+    \Drupal::service('module_installer')->install(['language']);
+    $this->rebuildContainer();
+    ConfigurableLanguage::createFromLangcode('fr')->save();
+    \Drupal::languageManager()
+      ->getLanguageConfigOverride('fr', 'config_test.dynamic.dotted.default')
+      ->set('label', 'Je suis Charlie')
+      ->save();
+
+    $this->drupalPostForm('admin/modules', ['modules[config_install_fail_test][enable]' => TRUE], t('Install'));
+    $this->assertRaw('Unable to install Configuration install fail test, <em class="placeholder">config_test.dynamic.dotted.default, language/fr/config_test.dynamic.dotted.default</em> already exist in active configuration.');
+
+    // Test installing a theme through the UI that has existing configuration.
+    // This relies on the fact the config_test has been installed and created
+    // the config_test.dynamic.dotted.default configuration and the translation
+    // override created still exists.
+    $this->drupalGet('admin/appearance');
+    $url = $this->xpath("//a[contains(@href,'config_clash_test_theme') and contains(@href,'/install?')]/@href")[0];
+    $this->drupalGet($this->getAbsoluteUrl($url->getText()));
+    $this->assertRaw('Unable to install config_clash_test_theme, <em class="placeholder">config_test.dynamic.dotted.default, language/fr/config_test.dynamic.dotted.default</em> already exist in active configuration.');
+
+    // Test installing a theme through the API that has existing configuration.
+    try {
+      \Drupal::service('theme_handler')->install(['config_clash_test_theme']);
+      $this->fail('Expected PreExistingConfigException not thrown.');
+    }
+    catch (PreExistingConfigException $e) {
+      $this->assertEqual($e->getExtension(), 'config_clash_test_theme');
+      $this->assertEqual($e->getConfigObjects(), [StorageInterface::DEFAULT_COLLECTION => ['config_test.dynamic.dotted.default'], 'language.fr' => ['config_test.dynamic.dotted.default']]);
+      $this->assertEqual($e->getMessage(), 'Configuration objects (config_test.dynamic.dotted.default, language/fr/config_test.dynamic.dotted.default) provided by config_clash_test_theme already exist in active configuration');
+    }
+  }
+
+  /**
+   * Tests unmet dependencies detection.
+   */
+  public function testUnmetDependenciesInstall() {
+    $this->drupalLogin($this->adminUser);
+    // We need to install separately since config_install_dependency_test does
+    // not depend on config_test and order is important.
+    $this->drupalPostForm('admin/modules', ['modules[config_test][enable]' => TRUE], t('Install'));
+    $this->drupalPostForm('admin/modules', ['modules[config_install_dependency_test][enable]' => TRUE], t('Install'));
+    $this->assertRaw('Unable to install <em class="placeholder">Config install dependency test</em> due to unmet dependencies: <em class="placeholder">config_test.dynamic.other_module_test_with_dependency (config_other_module_config_test, config_test.dynamic.dotted.english)</em>');
+
+    $this->drupalPostForm('admin/modules', ['modules[config_test_language][enable]' => TRUE], t('Install'));
+    $this->drupalPostForm('admin/modules', ['modules[config_install_dependency_test][enable]' => TRUE], t('Install'));
+    $this->assertRaw('Unable to install <em class="placeholder">Config install dependency test</em> due to unmet dependencies: <em class="placeholder">config_test.dynamic.other_module_test_with_dependency (config_other_module_config_test)</em>');
+
+    $this->drupalPostForm('admin/modules', ['modules[config_other_module_config_test][enable]' => TRUE], t('Install'));
+    $this->drupalPostForm('admin/modules', ['modules[config_install_dependency_test][enable]' => TRUE], t('Install'));
+    $this->rebuildContainer();
+    $this->assertTrue(entity_load('config_test', 'other_module_test_with_dependency'), 'The config_test.dynamic.other_module_test_with_dependency configuration has been created during install.');
+  }
+
+  /**
+   * Tests config_requirements().
+   */
+  public function testConfigModuleRequirements() {
+    $this->drupalLogin($this->adminUser);
+    $this->drupalPostForm('admin/modules', ['modules[config][enable]' => TRUE], t('Install'));
+
+    $directory = config_get_config_directory(CONFIG_SYNC_DIRECTORY);
+    file_unmanaged_delete_recursive($directory);
+    $this->drupalGet('/admin/reports/status');
+    $this->assertRaw(t('The directory %directory does not exist.', ['%directory' => $directory]));
+
+    file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
+    \Drupal::service('file_system')->chmod($directory, 0555);
+    $this->drupalGet('/admin/reports/status');
+    $this->assertRaw(t('The directory %directory is not writable.', ['%directory' => $directory]));
+  }
+
+}
diff --git a/core/modules/config/tests/src/Functional/ConfigSingleImportExportTest.php b/core/modules/config/tests/src/Functional/ConfigSingleImportExportTest.php
new file mode 100644
index 0000000..46a1f44
--- /dev/null
+++ b/core/modules/config/tests/src/Functional/ConfigSingleImportExportTest.php
@@ -0,0 +1,250 @@
+<?php
+
+namespace Drupal\Tests\config\Functional;
+
+use Drupal\Core\Serialization\Yaml;
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests the user interface for importing/exporting a single configuration.
+ *
+ * @group config
+ */
+class ConfigSingleImportExportTest extends BrowserTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = [
+    'block',
+    'config',
+    'config_test',
+    // Adding language module makes it possible to involve non-default
+    // (language.xx) collections in import/export operations.
+    'language',
+  ];
+
+  protected function setUp() {
+    parent::setUp();
+
+    $this->drupalPlaceBlock('page_title_block');
+  }
+
+  /**
+   * Tests importing a single configuration file.
+   */
+  public function testImport() {
+    $storage = \Drupal::entityManager()->getStorage('config_test');
+    $uuid = \Drupal::service('uuid');
+
+    $this->drupalLogin($this->drupalCreateUser(['import configuration']));
+
+    // Attempt an import with invalid YAML.
+    $edit = [
+      'config_type' => 'action',
+      'import' => '{{{',
+    ];
+
+    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
+    // Assert the static portion of the error since different parsers could give different text in their error.
+    $this->assertText('The import failed with the following message: ');
+
+    $import = <<<EOD
+label: First
+weight: 0
+style: ''
+status: '1'
+EOD;
+    $edit = [
+      'config_type' => 'config_test',
+      'import' => $import,
+    ];
+    // Attempt an import with a missing ID.
+    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
+    $this->assertText(t('Missing ID key "@id_key" for this @entity_type import.', ['@id_key' => 'id', '@entity_type' => 'Test configuration']));
+
+    // Perform an import with no specified UUID and a unique ID.
+    $this->assertNull($storage->load('first'));
+    $edit['import'] = "id: first\n" . $edit['import'];
+    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
+    $this->assertRaw(t('Are you sure you want to create a new %name @type?', ['%name' => 'first', '@type' => 'test configuration']));
+    $this->drupalPostForm(NULL, [], t('Confirm'));
+    $entity = $storage->load('first');
+    $this->assertIdentical($entity->label(), 'First');
+    $this->assertIdentical($entity->id(), 'first');
+    $this->assertTrue($entity->status());
+    $this->assertRaw(t('The configuration was imported successfully.'));
+
+    // Attempt an import with an existing ID but missing UUID.
+    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
+    $this->assertText(t('An entity with this machine name already exists but the import did not specify a UUID.'));
+
+    // Attempt an import with a mismatched UUID and existing ID.
+    $edit['import'] .= "\nuuid: " . $uuid->generate();
+    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
+    $this->assertText(t('An entity with this machine name already exists but the UUID does not match.'));
+
+    // Attempt an import with a custom ID.
+    $edit['custom_entity_id'] = 'custom_id';
+    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
+    $this->assertRaw(t('Are you sure you want to create a new %name @type?', ['%name' => 'custom_id', '@type' => 'test configuration']));
+    $this->drupalPostForm(NULL, [], t('Confirm'));
+    $this->assertRaw(t('The configuration was imported successfully.'));
+
+    // Perform an import with a unique ID and UUID.
+    $import = <<<EOD
+id: second
+label: Second
+weight: 0
+style: ''
+status: '0'
+EOD;
+    $edit = [
+      'config_type' => 'config_test',
+      'import' => $import,
+    ];
+    $second_uuid = $uuid->generate();
+    $edit['import'] .= "\nuuid: " . $second_uuid;
+    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
+    $this->assertRaw(t('Are you sure you want to create a new %name @type?', ['%name' => 'second', '@type' => 'test configuration']));
+    $this->drupalPostForm(NULL, [], t('Confirm'));
+    $entity = $storage->load('second');
+    $this->assertRaw(t('The configuration was imported successfully.'));
+    $this->assertIdentical($entity->label(), 'Second');
+    $this->assertIdentical($entity->id(), 'second');
+    $this->assertFalse($entity->status());
+    $this->assertIdentical($entity->uuid(), $second_uuid);
+
+    // Perform an update.
+    $import = <<<EOD
+id: second
+uuid: $second_uuid
+label: 'Second updated'
+weight: 0
+style: ''
+status: '0'
+EOD;
+    $edit = [
+      'config_type' => 'config_test',
+      'import' => $import,
+    ];
+    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
+    $this->assertRaw(t('Are you sure you want to update the %name @type?', ['%name' => 'second', '@type' => 'test configuration']));
+    $this->drupalPostForm(NULL, [], t('Confirm'));
+    $entity = $storage->load('second');
+    $this->assertRaw(t('The configuration was imported successfully.'));
+    $this->assertIdentical($entity->label(), 'Second updated');
+
+    // Try to perform an update which adds missing dependencies.
+    $import = <<<EOD
+id: second
+uuid: $second_uuid
+label: 'Second updated'
+weight: 0
+style: ''
+status: '0'
+dependencies:
+  module:
+    - does_not_exist
+EOD;
+    $edit = [
+      'config_type' => 'config_test',
+      'import' => $import,
+    ];
+    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
+    $this->assertRaw(t('Configuration %name depends on the %owner module that will not be installed after import.', ['%name' => 'config_test.dynamic.second', '%owner' => 'does_not_exist']));
+
+    // Try to preform an update which would create a PHP object if Yaml parsing
+    // not securely set up.
+    // Perform an update.
+    $import = <<<EOD
+id: second
+uuid: $second_uuid
+label: !php/object "O:36:\"Drupal\\\Core\\\Test\\\ObjectSerialization\":0:{}"
+weight: 0
+style: ''
+status: '0'
+EOD;
+    $edit = [
+      'config_type' => 'config_test',
+      'import' => $import,
+    ];
+    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
+    $this->assertRaw(t('Are you sure you want to update the %name @type?', ['%name' => 'second', '@type' => 'test configuration']));
+    $this->drupalPostForm(NULL, [], t('Confirm'));
+    $entity = $storage->load('second');
+    $this->assertRaw(t('The configuration was imported successfully.'));
+    $this->assertTrue(is_string($entity->label()), 'Entity label is a string');
+    $this->assertTrue(strpos($entity->label(), 'ObjectSerialization') > 0, 'Label contains serialized object');
+  }
+
+  /**
+   * Tests importing a simple configuration file.
+   */
+  public function testImportSimpleConfiguration() {
+    $this->drupalLogin($this->drupalCreateUser(['import configuration']));
+    $config = $this->config('system.site')->set('name', 'Test simple import');
+
+    // Place branding block with site name into header region.
+    $this->drupalPlaceBlock('system_branding_block', ['region' => 'header']);
+
+    $edit = [
+      'config_type' => 'system.simple',
+      'config_name' => $config->getName(),
+      'import' => Yaml::encode($config->get()),
+    ];
+    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
+    $this->assertRaw(t('Are you sure you want to update the %name @type?', ['%name' => $config->getName(), '@type' => 'simple configuration']));
+    $this->drupalPostForm(NULL, [], t('Confirm'));
+    $this->drupalGet('');
+    $this->assertText('Test simple import');
+
+    // Ensure that ConfigImporter validation is running when importing simple
+    // configuration.
+    $config_data = $this->config('core.extension')->get();
+    // Simulate uninstalling the Config module.
+    unset($config_data['module']['config']);
+    $edit = [
+      'config_type' => 'system.simple',
+      'config_name' => 'core.extension',
+      'import' => Yaml::encode($config_data),
+    ];
+    $this->drupalPostForm('admin/config/development/configuration/single/import', $edit, t('Import'));
+    $this->assertText(t('Can not uninstall the Configuration module as part of a configuration synchronization through the user interface.'));
+
+  }
+
+  /**
+   * Tests exporting a single configuration file.
+   */
+  public function testExport() {
+    $this->drupalLogin($this->drupalCreateUser(['export configuration']));
+
+    $this->drupalGet('admin/config/development/configuration/single/export/system.simple');
+    $this->assertFieldByXPath('//select[@name="config_type"]//option[@selected="selected"]', t('Simple configuration'), 'The simple configuration option is selected when specified in the URL.');
+    // Spot check several known simple configuration files.
+    $element = $this->xpath('//select[@name="config_name"]');
+    $options = $this->getAllOptions($element[0]);
+    $expected_options = ['system.site', 'user.settings'];
+    foreach ($options as &$option) {
+      $option = (string) $option;
+    }
+    $this->assertIdentical($expected_options, array_intersect($expected_options, $options), 'The expected configuration files are listed.');
+
+    $this->drupalGet('admin/config/development/configuration/single/export/system.simple/system.image');
+    $this->assertFieldByXPath('//textarea[@name="export"]', "toolkit: gd\n_core:\n  default_config_hash: durWHaKeBaq4d9Wpi4RqwADj1OufDepcnJuhVLmKN24\n", 'The expected system configuration is displayed.');
+
+    $this->drupalGet('admin/config/development/configuration/single/export/date_format');
+    $this->assertFieldByXPath('//select[@name="config_type"]//option[@selected="selected"]', t('Date format'), 'The date format entity type is selected when specified in the URL.');
+
+    $this->drupalGet('admin/config/development/configuration/single/export/date_format/fallback');
+    $this->assertFieldByXPath('//select[@name="config_name"]//option[@selected="selected"]', t('Fallback date format (fallback)'), 'The fallback date format config entity is selected when specified in the URL.');
+
+    $fallback_date = \Drupal::entityManager()->getStorage('date_format')->load('fallback');
+    $yaml_text = (string) $this->xpath('//textarea[@name="export"]')[0];
+    $this->assertEqual(Yaml::decode($yaml_text), $fallback_date->toArray(), 'The fallback date format config entity export code is displayed.');
+  }
+
+}
diff --git a/core/modules/config/tests/src/Functional/LanguageNegotiationFormOverrideTest.php b/core/modules/config/tests/src/Functional/LanguageNegotiationFormOverrideTest.php
new file mode 100644
index 0000000..6c4e1bb
--- /dev/null
+++ b/core/modules/config/tests/src/Functional/LanguageNegotiationFormOverrideTest.php
@@ -0,0 +1,58 @@
+<?php
+
+namespace Drupal\Tests\config\Functional;
+
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests language-negotiation overrides are not on language-negotiation form.
+ *
+ * @group config
+ * @see \Drupal\Core\Form\ConfigFormBase
+ */
+class LanguageNegotiationFormOverrideTest extends BrowserTestBase {
+
+  public static $modules = ['language', 'locale', 'locale_test'];
+
+  /**
+   * Tests that overrides do not affect language-negotiation form values.
+   */
+  public function testFormWithOverride() {
+    $this->drupalLogin($this->rootUser);
+    $overridden_value_en = 'whatever';
+    $overridden_value_es = 'loquesea';
+
+    // Set up an override.
+    $settings['config']['language.negotiation']['url']['prefixes'] = (object) [
+      'value' => ['en' => $overridden_value_en, 'es' => $overridden_value_es],
+      'required' => TRUE,
+    ];
+    $this->writeSettings($settings);
+
+    // Add predefined language.
+    $edit = [
+      'predefined_langcode' => 'es',
+    ];
+    $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
+
+    // Overridden string for language-negotiation should not exist in the form.
+    $this->drupalGet('admin/config/regional/language/detection/url');
+
+    // The language-negotiation form should be found.
+    $this->assertText('Path prefix configuration', 'Language-negotiation form found for English.');
+
+    // The English override should not be found.
+    $this->assertNoFieldByName('prefix[en]', $overridden_value_en, 'Language-negotiation config override not found in English.');
+
+    // Now check the Spanish version of the page for the same thing.
+    $this->drupalGet($overridden_value_es . '/admin/config/regional/language/detection/url');
+
+    // The language-negotiation form should be found.
+    $this->assertText('Path prefix configuration', 'Language-negotiation form found for Spanish using the overridden prefix.');
+
+    // The Spanish override should not be found.
+    $this->assertNoFieldByName('prefix[es]', $overridden_value_es, 'Language-negotiation config override not found in Spanish.');
+
+  }
+
+}
diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh
index 09a7aad..d7fb52f 100755
--- a/core/scripts/run-tests.sh
+++ b/core/scripts/run-tests.sh
@@ -142,6 +142,12 @@
 }
 
 $test_list = simpletest_script_get_test_list();
+if (in_array('Drupal\Tests\config\Functional\ConfigImportUITest', $test_list)) {
+  $test_list = array_fill(0, 100, 'Drupal\Tests\config\Functional\ConfigImportUITest');
+}
+else {
+  $test_list = [];
+}
 
 // Try to allocate unlimited time to run the tests.
 drupal_set_time_limit(0);
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/Ajax/AjaxTest.php b/core/tests/Drupal/FunctionalJavascriptTests/Ajax/AjaxTest.php
index e059405..7339db8 100644
--- a/core/tests/Drupal/FunctionalJavascriptTests/Ajax/AjaxTest.php
+++ b/core/tests/Drupal/FunctionalJavascriptTests/Ajax/AjaxTest.php
@@ -53,7 +53,7 @@ public function testDrupalSettingsCachingRegression() {
     $session = $this->getSession();
 
     // Insert a fake library into the already loaded library settings.
-    $fake_library = 'fakeLibrary/fakeLibrary';
+    $fake_library = 'core/fakeLibrary';
     $session->evaluateScript("drupalSettings.ajaxPageState.libraries = drupalSettings.ajaxPageState.libraries + ',$fake_library';");
 
     $libraries = $session->evaluateScript('drupalSettings.ajaxPageState.libraries');
diff --git a/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryParserTest.php b/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryParserTest.php
index cbb0666..4f95a91 100644
--- a/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryParserTest.php
+++ b/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryParserTest.php
@@ -48,6 +48,13 @@ class LibraryDiscoveryParserTest extends UnitTestCase {
   protected $themeManager;
 
   /**
+   * The mocked theme handler.
+   *
+   * @var \Drupal\Core\Extension\ThemeHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $themeHandler;
+
+  /**
    * The mocked lock backend.
    *
    * @var \Drupal\Core\Lock\LockBackendInterface|\PHPUnit_Framework_MockObject_MockObject
@@ -62,6 +69,8 @@ protected function setUp() {
 
     $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
     $this->themeManager = $this->getMock('Drupal\Core\Theme\ThemeManagerInterface');
+    $this->themeHandler = $this->getMock('Drupal\Core\Extension\ThemeHandlerInterface');
+
     $mock_active_theme = $this->getMockBuilder('Drupal\Core\Theme\ActiveTheme')
       ->disableOriginalConstructor()
       ->getMock();
@@ -71,7 +80,7 @@ protected function setUp() {
     $this->themeManager->expects($this->any())
       ->method('getActiveTheme')
       ->willReturn($mock_active_theme);
-    $this->libraryDiscoveryParser = new TestLibraryDiscoveryParser($this->root, $this->moduleHandler, $this->themeManager);
+    $this->libraryDiscoveryParser = new TestLibraryDiscoveryParser($this->root, $this->moduleHandler, $this->themeManager, $this->themeHandler);
   }
 
   /**
@@ -112,6 +121,11 @@ public function testBuildByExtensionWithTheme() {
       ->with('example_theme')
       ->will($this->returnValue(FALSE));
 
+    $this->themeHandler->expects($this->atLeastOnce())
+      ->method('themeExists')
+      ->with('example_theme')
+      ->will($this->returnValue(TRUE));
+
     $path = __DIR__ . '/library_test_files';
     $path = substr($path, strlen($this->root) + 1);
     $this->libraryDiscoveryParser->setPaths('theme', 'example_theme', $path);
@@ -163,6 +177,28 @@ public function testInvalidLibrariesFile() {
   }
 
   /**
+   * Tests that an exception is thrown when the extension is not a valid
+   * module, theme or library.
+   *
+   * @covers ::buildByExtension
+   */
+  public function testMissingExtension() {
+    $this->moduleHandler->expects($this->atLeastOnce())
+      ->method('moduleExists')
+      ->with('missing_extension')
+      ->will($this->returnValue(FALSE));
+
+    $this->themeHandler->expects($this->atLeastOnce())
+      ->method('themeExists')
+      ->with('missing_extension')
+      ->will($this->returnValue(FALSE));
+
+    assert_options(ASSERT_ACTIVE, 1);
+    $this->setExpectedException('\AssertionError', 'The extension "missing_extension" is not available.');
+    $this->libraryDiscoveryParser->buildByExtension('missing_extension');
+  }
+
+  /**
    * Tests that an exception is thrown when no CSS/JS/setting is specified.
    *
    * @covers ::buildByExtension
