diff --git a/core/modules/aggregator/src/Tests/AggregatorTitleTest.php b/core/modules/aggregator/src/Tests/AggregatorTitleTest.php
deleted file mode 100644
index d599d9a..0000000
--- a/core/modules/aggregator/src/Tests/AggregatorTitleTest.php
+++ /dev/null
@@ -1,93 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\aggregator\Tests\AggregatorTitleTest.
- */
-
-namespace Drupal\aggregator\Tests;
-
-use Drupal\aggregator\Entity\Feed;
-use Drupal\aggregator\Entity\Item;
-use Drupal\simpletest\KernelTestBase;
-
-
-/**
- * Tests the aggregator_title formatter.
- *
- * @group field
- */
-class AggregatorTitleTest extends KernelTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['file', 'field', 'options', 'aggregator'];
-
-  /**
-   * The field name that is tested.
-   *
-   * @var string
-   */
-  protected $fieldName;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    $this->installConfig(['field']);
-    $this->installEntitySchema('aggregator_feed');
-    $this->installEntitySchema('aggregator_item');
-
-    $this->fieldName = 'title';
-  }
-
-  /*
-   * Tests the formatter output.
-   */
-  public function testStringFormatter() {
-    // Create an aggregator feed.
-    $aggregator_feed = Feed::create([
-      'title' => 'testing title',
-      'url' => 'http://www.example.com',
-    ]);
-    $aggregator_feed->save();
-
-    // Create an aggregator feed item.
-    $aggregator_item = Item::create([
-      'title' => 'test title',
-      'fid' => $aggregator_feed->id(),
-      'link' => 'http://www.example.com',
-      ]);
-    $aggregator_item->save();
-
-    // Verify aggregator feed title with and without links.
-    $build = $aggregator_feed->{$this->fieldName}->view(['type' => 'aggregator_title', 'settings' => ['display_as_link' => TRUE]]);
-    $result = $this->render($build);
-
-    $this->assertTrue(strpos($result, 'testing title'));
-    $this->assertTrue(strpos($result, 'href="' . $aggregator_feed->getUrl()) . '"');
-
-    $build = $aggregator_feed->{$this->fieldName}->view(['type' => 'aggregator_title', 'settings' => ['display_as_link' => FALSE]]);
-    $result = $this->render($build);
-    $this->assertTrue(strpos($result, 'testing title') === 0);
-    $this->assertTrue(strpos($result, $aggregator_feed->getUrl()) === FALSE);
-
-    // Verify aggregator item title with and without links.
-    $build = $aggregator_item->{$this->fieldName}->view(['type' => 'aggregator_title', 'settings' => ['display_as_link' =>TRUE]]);
-    $result = $this->render($build);
-
-    $this->assertTrue(strpos($result, 'test title'));
-    $this->assertTrue(strpos($result, 'href="' . $aggregator_item->getLink()) . '"');
-
-    $build = $aggregator_item->{$this->fieldName}->view(['type' => 'aggregator_title', 'settings' => ['display_as_link' => FALSE]]);
-    $result = $this->render($build);
-    $this->assertTrue(strpos($result, 'test title') === 0);
-    $this->assertTrue(strpos($result, $aggregator_item->getLink()) === FALSE);
-  }
-
-}
diff --git a/core/modules/aggregator/tests/src/Kernel/AggregatorTitleTest.php b/core/modules/aggregator/tests/src/Kernel/AggregatorTitleTest.php
new file mode 100644
index 0000000..186db13
--- /dev/null
+++ b/core/modules/aggregator/tests/src/Kernel/AggregatorTitleTest.php
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\aggregator\Tests\AggregatorTitleTest.
+ */
+
+namespace Drupal\Tests\aggregator\Kernel;
+
+use Drupal\aggregator\Entity\Feed;
+use Drupal\aggregator\Entity\Item;
+use Drupal\KernelTests\KernelTestBase;
+
+
+/**
+ * Tests the aggregator_title formatter.
+ *
+ * @group field
+ */
+class AggregatorTitleTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['file', 'field', 'options', 'aggregator'];
+
+  /**
+   * The field name that is tested.
+   *
+   * @var string
+   */
+  protected $fieldName;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installConfig(['field']);
+    $this->installEntitySchema('aggregator_feed');
+    $this->installEntitySchema('aggregator_item');
+
+    $this->fieldName = 'title';
+  }
+
+  /*
+   * Tests the formatter output.
+   */
+  public function testStringFormatter() {
+    // Create an aggregator feed.
+    $aggregator_feed = Feed::create([
+      'title' => 'testing title',
+      'url' => 'http://www.example.com',
+    ]);
+    $aggregator_feed->save();
+
+    // Create an aggregator feed item.
+    $aggregator_item = Item::create([
+      'title' => 'test title',
+      'fid' => $aggregator_feed->id(),
+      'link' => 'http://www.example.com',
+      ]);
+    $aggregator_item->save();
+
+    // Verify aggregator feed title with and without links.
+    $build = $aggregator_feed->{$this->fieldName}->view(['type' => 'aggregator_title', 'settings' => ['display_as_link' => TRUE]]);
+    $result = $this->render($build);
+
+    $this->assertTrue(strpos($result, 'testing title'));
+    $this->assertTrue(strpos($result, 'href="' . $aggregator_feed->getUrl()) . '"');
+
+    $build = $aggregator_feed->{$this->fieldName}->view(['type' => 'aggregator_title', 'settings' => ['display_as_link' => FALSE]]);
+    $result = $this->render($build);
+    $this->assertTrue(strpos($result, 'testing title') === 0);
+    $this->assertTrue(strpos($result, $aggregator_feed->getUrl()) === FALSE);
+
+    // Verify aggregator item title with and without links.
+    $build = $aggregator_item->{$this->fieldName}->view(['type' => 'aggregator_title', 'settings' => ['display_as_link' =>TRUE]]);
+    $result = $this->render($build);
+
+    $this->assertTrue(strpos($result, 'test title'));
+    $this->assertTrue(strpos($result, 'href="' . $aggregator_item->getLink()) . '"');
+
+    $build = $aggregator_item->{$this->fieldName}->view(['type' => 'aggregator_title', 'settings' => ['display_as_link' => FALSE]]);
+    $result = $this->render($build);
+    $this->assertTrue(strpos($result, 'test title') === 0);
+    $this->assertTrue(strpos($result, $aggregator_item->getLink()) === FALSE);
+  }
+
+}
diff --git a/core/modules/block/src/Tests/BlockConfigSchemaTest.php b/core/modules/block/src/Tests/BlockConfigSchemaTest.php
deleted file mode 100644
index 9d7bcfe..0000000
--- a/core/modules/block/src/Tests/BlockConfigSchemaTest.php
+++ /dev/null
@@ -1,98 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\block\Tests\BlockConfigSchemaTest.
- */
-
-namespace Drupal\block\Tests;
-
-use Drupal\block\Entity\Block;
-use Drupal\config\Tests\SchemaCheckTestTrait;
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests the block config schema.
- *
- * @group block
- */
-class BlockConfigSchemaTest extends KernelTestBase {
-
-  use SchemaCheckTestTrait;
-
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = array(
-    'block',
-    'aggregator',
-    'book',
-    'block_content',
-    'comment',
-    'forum',
-    'node',
-    'statistics',
-    // BlockManager->getModuleName() calls system_get_info().
-    'system',
-    'taxonomy',
-    'user',
-    'text',
-  );
-
-  /**
-   * The typed config manager.
-   *
-   * @var \Drupal\Core\Config\TypedConfigManagerInterface
-   */
-  protected $typedConfig;
-
-  /**
-   * The block manager.
-   *
-   * @var \Drupal\Core\Block\BlockManagerInterface
-   */
-  protected $blockManager;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    $this->typedConfig = \Drupal::service('config.typed');
-    $this->blockManager = \Drupal::service('plugin.manager.block');
-    $this->installEntitySchema('block_content');
-    $this->installEntitySchema('taxonomy_term');
-    $this->installEntitySchema('node');
-    $this->installSchema('book', array('book'));
-  }
-
-  /**
-   * Tests the block config schema for block plugins.
-   */
-  public function testBlockConfigSchema() {
-    foreach ($this->blockManager->getDefinitions() as $block_id => $definition) {
-      $id = strtolower($this->randomMachineName());
-      $block = Block::create(array(
-        'id' => $id,
-        'theme' => 'classy',
-        'weight' => 00,
-        'status' => TRUE,
-        'region' => 'content',
-        'plugin' => $block_id,
-        'settings' => array(
-          'label' => $this->randomMachineName(),
-          'provider' => 'system',
-          'label_display' => FALSE,
-        ),
-        'visibility' => array(),
-      ));
-      $block->save();
-
-      $config = $this->config("block.block.$id");
-      $this->assertEqual($config->get('id'), $id);
-      $this->assertConfigSchema($this->typedConfig, $config->getName(), $config->get());
-    }
-  }
-
-}
diff --git a/core/modules/block/src/Tests/BlockStorageUnitTest.php b/core/modules/block/src/Tests/BlockStorageUnitTest.php
deleted file mode 100644
index 140f746..0000000
--- a/core/modules/block/src/Tests/BlockStorageUnitTest.php
+++ /dev/null
@@ -1,160 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\block\Tests\BlockStorageUnitTest.
- */
-
-namespace Drupal\block\Tests;
-
-use Drupal\Core\Config\Entity\ConfigEntityStorage;
-use Drupal\simpletest\KernelTestBase;
-use Drupal\block_test\Plugin\Block\TestHtmlBlock;
-use Drupal\Component\Plugin\Exception\PluginException;
-use Drupal\block\Entity\Block;
-use Drupal\block\BlockInterface;
-
-/**
- * Tests the storage of blocks.
- *
- * @group block
- */
-class BlockStorageUnitTest extends KernelTestBase {
-
-  /**
-   * Modules to install.
-   *
-   * @var array
-   */
-  public static $modules = array('block', 'block_test');
-
-  /**
-   * The block storage.
-   *
-   * @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface.
-   */
-  protected $controller;
-
-  protected function setUp() {
-    parent::setUp();
-
-    $this->controller = $this->container->get('entity.manager')->getStorage('block');
-  }
-
-  /**
-   * Tests CRUD operations.
-   */
-  public function testBlockCRUD() {
-    $this->assertTrue($this->controller instanceof ConfigEntityStorage, 'The block storage is loaded.');
-
-    // Run each test method in the same installation.
-    $this->createTests();
-    $this->loadTests();
-    $this->deleteTests();
-  }
-
-  /**
-   * Tests the creation of blocks.
-   */
-  protected function createTests() {
-    // Attempt to create a block without a plugin.
-    try {
-      $entity = $this->controller->create(array());
-      $entity->getPlugin();
-      $this->fail('A block without a plugin was created with no exception thrown.');
-    }
-    catch (PluginException $e) {
-      $this->assertEqual('The block \'\' did not specify a plugin.', $e->getMessage(), 'An exception was thrown when a block was created without a plugin.');
-    }
-
-    // Create a block with only required values.
-    $entity = $this->controller->create(array(
-      'id' => 'test_block',
-      'theme' => 'stark',
-      'plugin' => 'test_html',
-    ));
-    $entity->save();
-
-    $this->assertTrue($entity instanceof Block, 'The newly created entity is a Block.');
-
-    // Verify all of the block properties.
-    $actual_properties = $this->config('block.block.test_block')->get();
-    $this->assertTrue(!empty($actual_properties['uuid']), 'The block UUID is set.');
-    unset($actual_properties['uuid']);
-
-    // Ensure that default values are filled in.
-    $expected_properties = array(
-      'langcode' => \Drupal::languageManager()->getDefaultLanguage()->getId(),
-      'status' => TRUE,
-      'dependencies' => array('module' => array('block_test'), 'theme' => array('stark')),
-      'id' => 'test_block',
-      'theme' => 'stark',
-      'region' => '-1',
-      'weight' => NULL,
-      'provider' => NULL,
-      'plugin' => 'test_html',
-      'settings' => array(
-        'id' => 'test_html',
-        'label' => '',
-        'provider' => 'block_test',
-        'label_display' => BlockInterface::BLOCK_LABEL_VISIBLE,
-      ),
-      'visibility' => array(),
-    );
-
-    $this->assertIdentical($actual_properties, $expected_properties);
-
-    $this->assertTrue($entity->getPlugin() instanceof TestHtmlBlock, 'The entity has an instance of the correct block plugin.');
-  }
-
-  /**
-   * Tests the loading of blocks.
-   */
-  protected function loadTests() {
-    $entity = $this->controller->load('test_block');
-
-    $this->assertTrue($entity instanceof Block, 'The loaded entity is a Block.');
-
-    // Verify several properties of the block.
-    $this->assertEqual($entity->getRegion(), '-1');
-    $this->assertTrue($entity->status());
-    $this->assertEqual($entity->getTheme(), 'stark');
-    $this->assertTrue($entity->uuid());
-  }
-
-  /**
-   * Tests the deleting of blocks.
-   */
-  protected function deleteTests() {
-    $entity = $this->controller->load('test_block');
-
-    // Ensure that the storage isn't currently empty.
-    $config_storage = $this->container->get('config.storage');
-    $config = $config_storage->listAll('block.block.');
-    $this->assertFalse(empty($config), 'There are blocks in config storage.');
-
-    // Delete the block.
-    $entity->delete();
-
-    // Ensure that the storage is now empty.
-    $config = $config_storage->listAll('block.block.');
-    $this->assertTrue(empty($config), 'There are no blocks in config storage.');
-  }
-
-  /**
-   * Tests the installation of default blocks.
-   */
-  public function testDefaultBlocks() {
-    \Drupal::service('theme_handler')->install(['classy']);
-    $entities = $this->controller->loadMultiple();
-    $this->assertTrue(empty($entities), 'There are no blocks initially.');
-
-    // Install the block_test.module, so that its default config is installed.
-    $this->installConfig(array('block_test'));
-
-    $entities = $this->controller->loadMultiple();
-    $entity = reset($entities);
-    $this->assertEqual($entity->id(), 'test_block', 'The default test block was loaded.');
-  }
-
-}
diff --git a/core/modules/block/src/Tests/BlockViewBuilderTest.php b/core/modules/block/src/Tests/BlockViewBuilderTest.php
deleted file mode 100644
index 331db82..0000000
--- a/core/modules/block/src/Tests/BlockViewBuilderTest.php
+++ /dev/null
@@ -1,333 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\block\Tests\BlockViewBuilderTest.
- */
-
-namespace Drupal\block\Tests;
-
-use Drupal\Component\Utility\Html;
-use Drupal\Core\Cache\Cache;
-use Drupal\Core\Language\LanguageInterface;
-use Drupal\simpletest\KernelTestBase;
-use Drupal\block\Entity\Block;
-
-/**
- * Tests the block view builder.
- *
- * @group block
- */
-class BlockViewBuilderTest extends KernelTestBase {
-
-  /**
-   * Modules to install.
-   *
-   * @var array
-   */
-  public static $modules = array('block', 'block_test', 'system', 'user');
-
-  /**
-   * The block being tested.
-   *
-   * @var \Drupal\block\Entity\BlockInterface
-   */
-  protected $block;
-
-  /**
-   * The block storage.
-   *
-   * @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
-   */
-  protected $controller;
-
-  /**
-   * The renderer.
-   *
-   * @var \Drupal\Core\Render\RendererInterface
-   */
-  protected $renderer;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    $this->controller = $this->container
-      ->get('entity.manager')
-      ->getStorage('block');
-
-    \Drupal::state()->set('block_test.content', 'Llamas &gt; unicorns!');
-
-    // Create a block with only required values.
-    $this->block = $this->controller->create(array(
-      'id' => 'test_block',
-      'theme' => 'stark',
-      'plugin' => 'test_cache',
-    ));
-    $this->block->save();
-
-    $this->container->get('cache.render')->deleteAll();
-
-    $this->renderer = $this->container->get('renderer');
-  }
-
-  /**
-   * Tests the rendering of blocks.
-   */
-  public function testBasicRendering() {
-    \Drupal::state()->set('block_test.content', '');
-
-    $entity = $this->controller->create(array(
-      'id' => 'test_block1',
-      'theme' => 'stark',
-      'plugin' => 'test_html',
-    ));
-    $entity->save();
-
-    // Test the rendering of a block.
-    $entity = Block::load('test_block1');
-    $output = entity_view($entity, 'block');
-    $expected = array();
-    $expected[] = '<div id="block-test-block1">';
-    $expected[] = '  ';
-    $expected[] = '    ';
-    $expected[] = '      ';
-    $expected[] = '  </div>';
-    $expected[] = '';
-    $expected_output = implode("\n", $expected);
-    $this->assertEqual($this->renderer->renderRoot($output), $expected_output);
-
-    // Reset the HTML IDs so that the next render is not affected.
-    Html::resetSeenIds();
-
-    // Test the rendering of a block with a given title.
-    $entity = $this->controller->create(array(
-      'id' => 'test_block2',
-      'theme' => 'stark',
-      'plugin' => 'test_html',
-      'settings' => array(
-        'label' => 'Powered by Bananas',
-      ),
-    ));
-    $entity->save();
-    $output = entity_view($entity, 'block');
-    $expected = array();
-    $expected[] = '<div id="block-test-block2">';
-    $expected[] = '  ';
-    $expected[] = '      <h2>Powered by Bananas</h2>';
-    $expected[] = '    ';
-    $expected[] = '      ';
-    $expected[] = '  </div>';
-    $expected[] = '';
-    $expected_output = implode("\n", $expected);
-    $this->assertEqual($this->renderer->renderRoot($output), $expected_output);
-  }
-
-  /**
-   * Tests block render cache handling.
-   */
-  public function testBlockViewBuilderCache() {
-    // Verify cache handling for a non-empty block.
-    $this->verifyRenderCacheHandling();
-
-    // Create an empty block.
-    $this->block = $this->controller->create(array(
-      'id' => 'test_block',
-      'theme' => 'stark',
-      'plugin' => 'test_cache',
-    ));
-    $this->block->save();
-    \Drupal::state()->set('block_test.content', NULL);
-
-    // Verify cache handling for an empty block.
-    $this->verifyRenderCacheHandling();
-  }
-
-  /**
-   * Verifies render cache handling of the block being tested.
-   *
-   * @see ::testBlockViewBuilderCache()
-   */
-  protected function verifyRenderCacheHandling() {
-    // Force a request via GET so we can test the render cache.
-    $request = \Drupal::request();
-    $request_method = $request->server->get('REQUEST_METHOD');
-    $request->setMethod('GET');
-
-    // Test that a cache entry is created.
-    $build = $this->getBlockRenderArray();
-    $cid = 'entity_view:block:test_block:' . implode(':', \Drupal::service('cache_contexts_manager')->convertTokensToKeys(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions'])->getKeys());
-    $this->renderer->renderRoot($build);
-    $this->assertTrue($this->container->get('cache.render')->get($cid), 'The block render element has been cached.');
-
-    // Re-save the block and check that the cache entry has been deleted.
-    $this->block->save();
-    $this->assertFalse($this->container->get('cache.render')->get($cid), 'The block render cache entry has been cleared when the block was saved.');
-
-    // Rebuild the render array (creating a new cache entry in the process) and
-    // delete the block to check the cache entry is deleted.
-    unset($build['#printed']);
-    // Re-add the block because \Drupal\block\BlockViewBuilder::buildBlock()
-    // removes it.
-    $build['#block'] = $this->block;
-
-    $this->renderer->renderRoot($build);
-    $this->assertTrue($this->container->get('cache.render')->get($cid), 'The block render element has been cached.');
-    $this->block->delete();
-    $this->assertFalse($this->container->get('cache.render')->get($cid), 'The block render cache entry has been cleared when the block was deleted.');
-
-    // Restore the previous request method.
-    $request->setMethod($request_method);
-  }
-
-  /**
-   * Tests block view altering.
-   *
-   * @see hook_block_view_alter()
-   * @see hook_block_view_BASE_BLOCK_ID_alter()
-   */
-  public function testBlockViewBuilderViewAlter() {
-    // Establish baseline.
-    $build = $this->getBlockRenderArray();
-    $this->setRawContent((string) $this->renderer->renderRoot($build));
-    $this->assertIdentical(trim((string) $this->cssSelect('div')[0]), 'Llamas > unicorns!');
-
-    // Enable the block view alter hook that adds a foo=bar attribute.
-    \Drupal::state()->set('block_test_view_alter_suffix', TRUE);
-    Cache::invalidateTags($this->block->getCacheTagsToInvalidate());
-    $build = $this->getBlockRenderArray();
-    $this->setRawContent((string) $this->renderer->renderRoot($build));
-    $this->assertIdentical(trim((string) $this->cssSelect('[foo=bar]')[0]), 'Llamas > unicorns!');
-    \Drupal::state()->set('block_test_view_alter_suffix', FALSE);
-
-    \Drupal::state()->set('block_test.content', NULL);
-    Cache::invalidateTags($this->block->getCacheTagsToInvalidate());
-
-    // Advanced: cached block, but an alter hook adds a #pre_render callback to
-    // alter the eventual content.
-    \Drupal::state()->set('block_test_view_alter_append_pre_render_prefix', TRUE);
-    $build = $this->getBlockRenderArray();
-    $this->assertFalse(isset($build['#prefix']), 'The appended #pre_render callback has not yet run before rendering.');
-    $this->assertIdentical((string) $this->renderer->renderRoot($build), 'Hiya!<br>');
-    $this->assertTrue(isset($build['#prefix']) && $build['#prefix'] === 'Hiya!<br>', 'A cached block without content is altered.');
-  }
-
-  /**
-   * Tests block build altering.
-   *
-   * @see hook_block_build_alter()
-   * @see hook_block_build_BASE_BLOCK_ID_alter()
-   */
-  public function testBlockViewBuilderBuildAlter() {
-    // Force a request via GET so we can test the render cache.
-    $request = \Drupal::request();
-    $request_method = $request->server->get('REQUEST_METHOD');
-    $request->setMethod('GET');
-
-    $default_keys = ['entity_view', 'block', 'test_block'];
-    $default_contexts = [];
-    $default_tags = ['block_view', 'config:block.block.test_block'];
-    $default_max_age = Cache::PERMANENT;
-
-    // hook_block_build_alter() adds an additional cache key.
-    $alter_add_key = $this->randomMachineName();
-    \Drupal::state()->set('block_test_block_alter_cache_key', $alter_add_key);
-    $this->assertBlockRenderedWithExpectedCacheability(array_merge($default_keys, [$alter_add_key]), $default_contexts, $default_tags, $default_max_age);
-    \Drupal::state()->set('block_test_block_alter_cache_key', NULL);
-
-    // hook_block_build_alter() adds an additional cache context.
-    $alter_add_context = 'url.query_args:' . $this->randomMachineName();
-    \Drupal::state()->set('block_test_block_alter_cache_context', $alter_add_context);
-    $this->assertBlockRenderedWithExpectedCacheability($default_keys, Cache::mergeContexts($default_contexts, [$alter_add_context]), $default_tags, $default_max_age);
-    \Drupal::state()->set('block_test_block_alter_cache_context', NULL);
-
-    // hook_block_build_alter() adds an additional cache tag.
-    $alter_add_tag = $this->randomMachineName();
-    \Drupal::state()->set('block_test_block_alter_cache_tag', $alter_add_tag);
-    $this->assertBlockRenderedWithExpectedCacheability($default_keys, $default_contexts, Cache::mergeTags($default_tags, [$alter_add_tag]), $default_max_age);
-    \Drupal::state()->set('block_test_block_alter_cache_tag', NULL);
-
-    // hook_block_build_alter() alters the max-age.
-    $alter_max_age = 300;
-    \Drupal::state()->set('block_test_block_alter_cache_max_age', $alter_max_age);
-    $this->assertBlockRenderedWithExpectedCacheability($default_keys, $default_contexts, $default_tags, $alter_max_age);
-    \Drupal::state()->set('block_test_block_alter_cache_max_age', NULL);
-
-    // hook_block_build_alter() alters cache keys, contexts, tags and max-age.
-    \Drupal::state()->set('block_test_block_alter_cache_key', $alter_add_key);
-    \Drupal::state()->set('block_test_block_alter_cache_context', $alter_add_context);
-    \Drupal::state()->set('block_test_block_alter_cache_tag', $alter_add_tag);
-    \Drupal::state()->set('block_test_block_alter_cache_max_age', $alter_max_age);
-    $this->assertBlockRenderedWithExpectedCacheability(array_merge($default_keys, [$alter_add_key]), Cache::mergeContexts($default_contexts, [$alter_add_context]), Cache::mergeTags($default_tags, [$alter_add_tag]), $alter_max_age);
-    \Drupal::state()->set('block_test_block_alter_cache_key', NULL);
-    \Drupal::state()->set('block_test_block_alter_cache_context', NULL);
-    \Drupal::state()->set('block_test_block_alter_cache_tag', NULL);
-    \Drupal::state()->set('block_test_block_alter_cache_max_age', NULL);
-
-    // hook_block_build_alter() sets #create_placeholder.
-    foreach ([TRUE, FALSE] as $value) {
-      \Drupal::state()->set('block_test_block_alter_create_placeholder', $value);
-      $build = $this->getBlockRenderArray();
-      $this->assertTrue(isset($build['#create_placeholder']));
-      $this->assertIdentical($value, $build['#create_placeholder']);
-    }
-    \Drupal::state()->set('block_test_block_alter_create_placeholder', NULL);
-
-    // Restore the previous request method.
-    $request->setMethod($request_method);
-  }
-
-  /**
-   * Asserts that a block is built/rendered/cached with expected cacheability.
-   *
-   * @param string[] $expected_keys
-   *   The expected cache keys.
-   * @param string[] $expected_contexts
-   *   The expected cache contexts.
-   * @param string[] $expected_tags
-   *   The expected cache tags.
-   * @param int $expected_max_age
-   *   The expected max-age.
-   */
-  protected function assertBlockRenderedWithExpectedCacheability(array $expected_keys, array $expected_contexts, array $expected_tags, $expected_max_age) {
-    $required_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions'];
-
-    // Check that the expected cacheability metadata is present in:
-    // - the built render array;
-    $this->pass('Built render array');
-    $build = $this->getBlockRenderArray();
-    $this->assertIdentical($expected_keys, $build['#cache']['keys']);
-    $this->assertIdentical($expected_contexts, $build['#cache']['contexts']);
-    $this->assertIdentical($expected_tags, $build['#cache']['tags']);
-    $this->assertIdentical($expected_max_age, $build['#cache']['max-age']);
-    $this->assertFalse(isset($build['#create_placeholder']));
-    // - the rendered render array;
-    $this->pass('Rendered render array');
-    $this->renderer->renderRoot($build);
-    // - the render cache item.
-    $this->pass('Render cache item');
-    $final_cache_contexts = Cache::mergeContexts($expected_contexts, $required_cache_contexts);
-    $cid = implode(':', $expected_keys) . ':' . implode(':', \Drupal::service('cache_contexts_manager')->convertTokensToKeys($final_cache_contexts)->getKeys());
-    $cache_item = $this->container->get('cache.render')->get($cid);
-    $this->assertTrue($cache_item, 'The block render element has been cached with the expected cache ID.');
-    $this->assertIdentical(Cache::mergeTags($expected_tags, ['rendered']), $cache_item->tags);
-    $this->assertIdentical($final_cache_contexts, $cache_item->data['#cache']['contexts']);
-    $this->assertIdentical($expected_tags, $cache_item->data['#cache']['tags']);
-    $this->assertIdentical($expected_max_age, $cache_item->data['#cache']['max-age']);
-
-    $this->container->get('cache.render')->delete($cid);
-  }
-
-  /**
-   * Get a fully built render array for a block.
-   *
-   * @return array
-   *   The render array.
-   */
-  protected function getBlockRenderArray() {
-    return $this->container->get('entity.manager')->getViewBuilder('block')->view($this->block, 'block');
-  }
-
-}
diff --git a/core/modules/block/tests/src/Kernel/BlockConfigSchemaTest.php b/core/modules/block/tests/src/Kernel/BlockConfigSchemaTest.php
new file mode 100644
index 0000000..25b2c0d
--- /dev/null
+++ b/core/modules/block/tests/src/Kernel/BlockConfigSchemaTest.php
@@ -0,0 +1,98 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\Tests\BlockConfigSchemaTest.
+ */
+
+namespace Drupal\Tests\block\Kernel;
+
+use Drupal\block\Entity\Block;
+use Drupal\config\Tests\SchemaCheckTestTrait;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests the block config schema.
+ *
+ * @group block
+ */
+class BlockConfigSchemaTest extends KernelTestBase {
+
+  use SchemaCheckTestTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = array(
+    'block',
+    'aggregator',
+    'book',
+    'block_content',
+    'comment',
+    'forum',
+    'node',
+    'statistics',
+    // BlockManager->getModuleName() calls system_get_info().
+    'system',
+    'taxonomy',
+    'user',
+    'text',
+  );
+
+  /**
+   * The typed config manager.
+   *
+   * @var \Drupal\Core\Config\TypedConfigManagerInterface
+   */
+  protected $typedConfig;
+
+  /**
+   * The block manager.
+   *
+   * @var \Drupal\Core\Block\BlockManagerInterface
+   */
+  protected $blockManager;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->typedConfig = \Drupal::service('config.typed');
+    $this->blockManager = \Drupal::service('plugin.manager.block');
+    $this->installEntitySchema('block_content');
+    $this->installEntitySchema('taxonomy_term');
+    $this->installEntitySchema('node');
+    $this->installSchema('book', array('book'));
+  }
+
+  /**
+   * Tests the block config schema for block plugins.
+   */
+  public function testBlockConfigSchema() {
+    foreach ($this->blockManager->getDefinitions() as $block_id => $definition) {
+      $id = strtolower($this->randomMachineName());
+      $block = Block::create(array(
+        'id' => $id,
+        'theme' => 'classy',
+        'weight' => 00,
+        'status' => TRUE,
+        'region' => 'content',
+        'plugin' => $block_id,
+        'settings' => array(
+          'label' => $this->randomMachineName(),
+          'provider' => 'system',
+          'label_display' => FALSE,
+        ),
+        'visibility' => array(),
+      ));
+      $block->save();
+
+      $config = $this->config("block.block.$id");
+      $this->assertEqual($config->get('id'), $id);
+      $this->assertConfigSchema($this->typedConfig, $config->getName(), $config->get());
+    }
+  }
+
+}
diff --git a/core/modules/block/tests/src/Kernel/BlockStorageUnitTest.php b/core/modules/block/tests/src/Kernel/BlockStorageUnitTest.php
new file mode 100644
index 0000000..ef284f2
--- /dev/null
+++ b/core/modules/block/tests/src/Kernel/BlockStorageUnitTest.php
@@ -0,0 +1,160 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\Tests\BlockStorageUnitTest.
+ */
+
+namespace Drupal\Tests\block\Kernel;
+
+use Drupal\Core\Config\Entity\ConfigEntityStorage;
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\block_test\Plugin\Block\TestHtmlBlock;
+use Drupal\Component\Plugin\Exception\PluginException;
+use Drupal\block\Entity\Block;
+use Drupal\block\BlockInterface;
+
+/**
+ * Tests the storage of blocks.
+ *
+ * @group block
+ */
+class BlockStorageUnitTest extends KernelTestBase {
+
+  /**
+   * Modules to install.
+   *
+   * @var array
+   */
+  public static $modules = array('block', 'block_test');
+
+  /**
+   * The block storage.
+   *
+   * @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface.
+   */
+  protected $controller;
+
+  protected function setUp() {
+    parent::setUp();
+
+    $this->controller = $this->container->get('entity.manager')->getStorage('block');
+  }
+
+  /**
+   * Tests CRUD operations.
+   */
+  public function testBlockCRUD() {
+    $this->assertTrue($this->controller instanceof ConfigEntityStorage, 'The block storage is loaded.');
+
+    // Run each test method in the same installation.
+    $this->createTests();
+    $this->loadTests();
+    $this->deleteTests();
+  }
+
+  /**
+   * Tests the creation of blocks.
+   */
+  protected function createTests() {
+    // Attempt to create a block without a plugin.
+    try {
+      $entity = $this->controller->create(array());
+      $entity->getPlugin();
+      $this->fail('A block without a plugin was created with no exception thrown.');
+    }
+    catch (PluginException $e) {
+      $this->assertEqual('The block \'\' did not specify a plugin.', $e->getMessage(), 'An exception was thrown when a block was created without a plugin.');
+    }
+
+    // Create a block with only required values.
+    $entity = $this->controller->create(array(
+      'id' => 'test_block',
+      'theme' => 'stark',
+      'plugin' => 'test_html',
+    ));
+    $entity->save();
+
+    $this->assertTrue($entity instanceof Block, 'The newly created entity is a Block.');
+
+    // Verify all of the block properties.
+    $actual_properties = $this->config('block.block.test_block')->get();
+    $this->assertTrue(!empty($actual_properties['uuid']), 'The block UUID is set.');
+    unset($actual_properties['uuid']);
+
+    // Ensure that default values are filled in.
+    $expected_properties = array(
+      'langcode' => \Drupal::languageManager()->getDefaultLanguage()->getId(),
+      'status' => TRUE,
+      'dependencies' => array('module' => array('block_test'), 'theme' => array('stark')),
+      'id' => 'test_block',
+      'theme' => 'stark',
+      'region' => '-1',
+      'weight' => NULL,
+      'provider' => NULL,
+      'plugin' => 'test_html',
+      'settings' => array(
+        'id' => 'test_html',
+        'label' => '',
+        'provider' => 'block_test',
+        'label_display' => BlockInterface::BLOCK_LABEL_VISIBLE,
+      ),
+      'visibility' => array(),
+    );
+
+    $this->assertIdentical($actual_properties, $expected_properties);
+
+    $this->assertTrue($entity->getPlugin() instanceof TestHtmlBlock, 'The entity has an instance of the correct block plugin.');
+  }
+
+  /**
+   * Tests the loading of blocks.
+   */
+  protected function loadTests() {
+    $entity = $this->controller->load('test_block');
+
+    $this->assertTrue($entity instanceof Block, 'The loaded entity is a Block.');
+
+    // Verify several properties of the block.
+    $this->assertEqual($entity->getRegion(), '-1');
+    $this->assertTrue($entity->status());
+    $this->assertEqual($entity->getTheme(), 'stark');
+    $this->assertTrue($entity->uuid());
+  }
+
+  /**
+   * Tests the deleting of blocks.
+   */
+  protected function deleteTests() {
+    $entity = $this->controller->load('test_block');
+
+    // Ensure that the storage isn't currently empty.
+    $config_storage = $this->container->get('config.storage');
+    $config = $config_storage->listAll('block.block.');
+    $this->assertFalse(empty($config), 'There are blocks in config storage.');
+
+    // Delete the block.
+    $entity->delete();
+
+    // Ensure that the storage is now empty.
+    $config = $config_storage->listAll('block.block.');
+    $this->assertTrue(empty($config), 'There are no blocks in config storage.');
+  }
+
+  /**
+   * Tests the installation of default blocks.
+   */
+  public function testDefaultBlocks() {
+    \Drupal::service('theme_handler')->install(['classy']);
+    $entities = $this->controller->loadMultiple();
+    $this->assertTrue(empty($entities), 'There are no blocks initially.');
+
+    // Install the block_test.module, so that its default config is installed.
+    $this->installConfig(array('block_test'));
+
+    $entities = $this->controller->loadMultiple();
+    $entity = reset($entities);
+    $this->assertEqual($entity->id(), 'test_block', 'The default test block was loaded.');
+  }
+
+}
diff --git a/core/modules/block/tests/src/Kernel/BlockViewBuilderTest.php b/core/modules/block/tests/src/Kernel/BlockViewBuilderTest.php
new file mode 100644
index 0000000..9816605
--- /dev/null
+++ b/core/modules/block/tests/src/Kernel/BlockViewBuilderTest.php
@@ -0,0 +1,333 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\Tests\BlockViewBuilderTest.
+ */
+
+namespace Drupal\Tests\block\Kernel;
+
+use Drupal\Component\Utility\Html;
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Language\LanguageInterface;
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\block\Entity\Block;
+
+/**
+ * Tests the block view builder.
+ *
+ * @group block
+ */
+class BlockViewBuilderTest extends KernelTestBase {
+
+  /**
+   * Modules to install.
+   *
+   * @var array
+   */
+  public static $modules = array('block', 'block_test', 'system', 'user');
+
+  /**
+   * The block being tested.
+   *
+   * @var \Drupal\block\Entity\BlockInterface
+   */
+  protected $block;
+
+  /**
+   * The block storage.
+   *
+   * @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
+   */
+  protected $controller;
+
+  /**
+   * The renderer.
+   *
+   * @var \Drupal\Core\Render\RendererInterface
+   */
+  protected $renderer;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->controller = $this->container
+      ->get('entity.manager')
+      ->getStorage('block');
+
+    \Drupal::state()->set('block_test.content', 'Llamas &gt; unicorns!');
+
+    // Create a block with only required values.
+    $this->block = $this->controller->create(array(
+      'id' => 'test_block',
+      'theme' => 'stark',
+      'plugin' => 'test_cache',
+    ));
+    $this->block->save();
+
+    $this->container->get('cache.render')->deleteAll();
+
+    $this->renderer = $this->container->get('renderer');
+  }
+
+  /**
+   * Tests the rendering of blocks.
+   */
+  public function testBasicRendering() {
+    \Drupal::state()->set('block_test.content', '');
+
+    $entity = $this->controller->create(array(
+      'id' => 'test_block1',
+      'theme' => 'stark',
+      'plugin' => 'test_html',
+    ));
+    $entity->save();
+
+    // Test the rendering of a block.
+    $entity = Block::load('test_block1');
+    $output = entity_view($entity, 'block');
+    $expected = array();
+    $expected[] = '<div id="block-test-block1">';
+    $expected[] = '  ';
+    $expected[] = '    ';
+    $expected[] = '      ';
+    $expected[] = '  </div>';
+    $expected[] = '';
+    $expected_output = implode("\n", $expected);
+    $this->assertEqual($this->renderer->renderRoot($output), $expected_output);
+
+    // Reset the HTML IDs so that the next render is not affected.
+    Html::resetSeenIds();
+
+    // Test the rendering of a block with a given title.
+    $entity = $this->controller->create(array(
+      'id' => 'test_block2',
+      'theme' => 'stark',
+      'plugin' => 'test_html',
+      'settings' => array(
+        'label' => 'Powered by Bananas',
+      ),
+    ));
+    $entity->save();
+    $output = entity_view($entity, 'block');
+    $expected = array();
+    $expected[] = '<div id="block-test-block2">';
+    $expected[] = '  ';
+    $expected[] = '      <h2>Powered by Bananas</h2>';
+    $expected[] = '    ';
+    $expected[] = '      ';
+    $expected[] = '  </div>';
+    $expected[] = '';
+    $expected_output = implode("\n", $expected);
+    $this->assertEqual($this->renderer->renderRoot($output), $expected_output);
+  }
+
+  /**
+   * Tests block render cache handling.
+   */
+  public function testBlockViewBuilderCache() {
+    // Verify cache handling for a non-empty block.
+    $this->verifyRenderCacheHandling();
+
+    // Create an empty block.
+    $this->block = $this->controller->create(array(
+      'id' => 'test_block',
+      'theme' => 'stark',
+      'plugin' => 'test_cache',
+    ));
+    $this->block->save();
+    \Drupal::state()->set('block_test.content', NULL);
+
+    // Verify cache handling for an empty block.
+    $this->verifyRenderCacheHandling();
+  }
+
+  /**
+   * Verifies render cache handling of the block being tested.
+   *
+   * @see ::testBlockViewBuilderCache()
+   */
+  protected function verifyRenderCacheHandling() {
+    // Force a request via GET so we can test the render cache.
+    $request = \Drupal::request();
+    $request_method = $request->server->get('REQUEST_METHOD');
+    $request->setMethod('GET');
+
+    // Test that a cache entry is created.
+    $build = $this->getBlockRenderArray();
+    $cid = 'entity_view:block:test_block:' . implode(':', \Drupal::service('cache_contexts_manager')->convertTokensToKeys(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions'])->getKeys());
+    $this->renderer->renderRoot($build);
+    $this->assertTrue($this->container->get('cache.render')->get($cid), 'The block render element has been cached.');
+
+    // Re-save the block and check that the cache entry has been deleted.
+    $this->block->save();
+    $this->assertFalse($this->container->get('cache.render')->get($cid), 'The block render cache entry has been cleared when the block was saved.');
+
+    // Rebuild the render array (creating a new cache entry in the process) and
+    // delete the block to check the cache entry is deleted.
+    unset($build['#printed']);
+    // Re-add the block because \Drupal\block\BlockViewBuilder::buildBlock()
+    // removes it.
+    $build['#block'] = $this->block;
+
+    $this->renderer->renderRoot($build);
+    $this->assertTrue($this->container->get('cache.render')->get($cid), 'The block render element has been cached.');
+    $this->block->delete();
+    $this->assertFalse($this->container->get('cache.render')->get($cid), 'The block render cache entry has been cleared when the block was deleted.');
+
+    // Restore the previous request method.
+    $request->setMethod($request_method);
+  }
+
+  /**
+   * Tests block view altering.
+   *
+   * @see hook_block_view_alter()
+   * @see hook_block_view_BASE_BLOCK_ID_alter()
+   */
+  public function testBlockViewBuilderViewAlter() {
+    // Establish baseline.
+    $build = $this->getBlockRenderArray();
+    $this->setRawContent((string) $this->renderer->renderRoot($build));
+    $this->assertIdentical(trim((string) $this->cssSelect('div')[0]), 'Llamas > unicorns!');
+
+    // Enable the block view alter hook that adds a foo=bar attribute.
+    \Drupal::state()->set('block_test_view_alter_suffix', TRUE);
+    Cache::invalidateTags($this->block->getCacheTagsToInvalidate());
+    $build = $this->getBlockRenderArray();
+    $this->setRawContent((string) $this->renderer->renderRoot($build));
+    $this->assertIdentical(trim((string) $this->cssSelect('[foo=bar]')[0]), 'Llamas > unicorns!');
+    \Drupal::state()->set('block_test_view_alter_suffix', FALSE);
+
+    \Drupal::state()->set('block_test.content', NULL);
+    Cache::invalidateTags($this->block->getCacheTagsToInvalidate());
+
+    // Advanced: cached block, but an alter hook adds a #pre_render callback to
+    // alter the eventual content.
+    \Drupal::state()->set('block_test_view_alter_append_pre_render_prefix', TRUE);
+    $build = $this->getBlockRenderArray();
+    $this->assertFalse(isset($build['#prefix']), 'The appended #pre_render callback has not yet run before rendering.');
+    $this->assertIdentical((string) $this->renderer->renderRoot($build), 'Hiya!<br>');
+    $this->assertTrue(isset($build['#prefix']) && $build['#prefix'] === 'Hiya!<br>', 'A cached block without content is altered.');
+  }
+
+  /**
+   * Tests block build altering.
+   *
+   * @see hook_block_build_alter()
+   * @see hook_block_build_BASE_BLOCK_ID_alter()
+   */
+  public function testBlockViewBuilderBuildAlter() {
+    // Force a request via GET so we can test the render cache.
+    $request = \Drupal::request();
+    $request_method = $request->server->get('REQUEST_METHOD');
+    $request->setMethod('GET');
+
+    $default_keys = ['entity_view', 'block', 'test_block'];
+    $default_contexts = [];
+    $default_tags = ['block_view', 'config:block.block.test_block'];
+    $default_max_age = Cache::PERMANENT;
+
+    // hook_block_build_alter() adds an additional cache key.
+    $alter_add_key = $this->randomMachineName();
+    \Drupal::state()->set('block_test_block_alter_cache_key', $alter_add_key);
+    $this->assertBlockRenderedWithExpectedCacheability(array_merge($default_keys, [$alter_add_key]), $default_contexts, $default_tags, $default_max_age);
+    \Drupal::state()->set('block_test_block_alter_cache_key', NULL);
+
+    // hook_block_build_alter() adds an additional cache context.
+    $alter_add_context = 'url.query_args:' . $this->randomMachineName();
+    \Drupal::state()->set('block_test_block_alter_cache_context', $alter_add_context);
+    $this->assertBlockRenderedWithExpectedCacheability($default_keys, Cache::mergeContexts($default_contexts, [$alter_add_context]), $default_tags, $default_max_age);
+    \Drupal::state()->set('block_test_block_alter_cache_context', NULL);
+
+    // hook_block_build_alter() adds an additional cache tag.
+    $alter_add_tag = $this->randomMachineName();
+    \Drupal::state()->set('block_test_block_alter_cache_tag', $alter_add_tag);
+    $this->assertBlockRenderedWithExpectedCacheability($default_keys, $default_contexts, Cache::mergeTags($default_tags, [$alter_add_tag]), $default_max_age);
+    \Drupal::state()->set('block_test_block_alter_cache_tag', NULL);
+
+    // hook_block_build_alter() alters the max-age.
+    $alter_max_age = 300;
+    \Drupal::state()->set('block_test_block_alter_cache_max_age', $alter_max_age);
+    $this->assertBlockRenderedWithExpectedCacheability($default_keys, $default_contexts, $default_tags, $alter_max_age);
+    \Drupal::state()->set('block_test_block_alter_cache_max_age', NULL);
+
+    // hook_block_build_alter() alters cache keys, contexts, tags and max-age.
+    \Drupal::state()->set('block_test_block_alter_cache_key', $alter_add_key);
+    \Drupal::state()->set('block_test_block_alter_cache_context', $alter_add_context);
+    \Drupal::state()->set('block_test_block_alter_cache_tag', $alter_add_tag);
+    \Drupal::state()->set('block_test_block_alter_cache_max_age', $alter_max_age);
+    $this->assertBlockRenderedWithExpectedCacheability(array_merge($default_keys, [$alter_add_key]), Cache::mergeContexts($default_contexts, [$alter_add_context]), Cache::mergeTags($default_tags, [$alter_add_tag]), $alter_max_age);
+    \Drupal::state()->set('block_test_block_alter_cache_key', NULL);
+    \Drupal::state()->set('block_test_block_alter_cache_context', NULL);
+    \Drupal::state()->set('block_test_block_alter_cache_tag', NULL);
+    \Drupal::state()->set('block_test_block_alter_cache_max_age', NULL);
+
+    // hook_block_build_alter() sets #create_placeholder.
+    foreach ([TRUE, FALSE] as $value) {
+      \Drupal::state()->set('block_test_block_alter_create_placeholder', $value);
+      $build = $this->getBlockRenderArray();
+      $this->assertTrue(isset($build['#create_placeholder']));
+      $this->assertIdentical($value, $build['#create_placeholder']);
+    }
+    \Drupal::state()->set('block_test_block_alter_create_placeholder', NULL);
+
+    // Restore the previous request method.
+    $request->setMethod($request_method);
+  }
+
+  /**
+   * Asserts that a block is built/rendered/cached with expected cacheability.
+   *
+   * @param string[] $expected_keys
+   *   The expected cache keys.
+   * @param string[] $expected_contexts
+   *   The expected cache contexts.
+   * @param string[] $expected_tags
+   *   The expected cache tags.
+   * @param int $expected_max_age
+   *   The expected max-age.
+   */
+  protected function assertBlockRenderedWithExpectedCacheability(array $expected_keys, array $expected_contexts, array $expected_tags, $expected_max_age) {
+    $required_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions'];
+
+    // Check that the expected cacheability metadata is present in:
+    // - the built render array;
+    $this->pass('Built render array');
+    $build = $this->getBlockRenderArray();
+    $this->assertIdentical($expected_keys, $build['#cache']['keys']);
+    $this->assertIdentical($expected_contexts, $build['#cache']['contexts']);
+    $this->assertIdentical($expected_tags, $build['#cache']['tags']);
+    $this->assertIdentical($expected_max_age, $build['#cache']['max-age']);
+    $this->assertFalse(isset($build['#create_placeholder']));
+    // - the rendered render array;
+    $this->pass('Rendered render array');
+    $this->renderer->renderRoot($build);
+    // - the render cache item.
+    $this->pass('Render cache item');
+    $final_cache_contexts = Cache::mergeContexts($expected_contexts, $required_cache_contexts);
+    $cid = implode(':', $expected_keys) . ':' . implode(':', \Drupal::service('cache_contexts_manager')->convertTokensToKeys($final_cache_contexts)->getKeys());
+    $cache_item = $this->container->get('cache.render')->get($cid);
+    $this->assertTrue($cache_item, 'The block render element has been cached with the expected cache ID.');
+    $this->assertIdentical(Cache::mergeTags($expected_tags, ['rendered']), $cache_item->tags);
+    $this->assertIdentical($final_cache_contexts, $cache_item->data['#cache']['contexts']);
+    $this->assertIdentical($expected_tags, $cache_item->data['#cache']['tags']);
+    $this->assertIdentical($expected_max_age, $cache_item->data['#cache']['max-age']);
+
+    $this->container->get('cache.render')->delete($cid);
+  }
+
+  /**
+   * Get a fully built render array for a block.
+   *
+   * @return array
+   *   The render array.
+   */
+  protected function getBlockRenderArray() {
+    return $this->container->get('entity.manager')->getViewBuilder('block')->view($this->block, 'block');
+  }
+
+}
diff --git a/core/modules/book/src/Tests/BookUninstallTest.php b/core/modules/book/src/Tests/BookUninstallTest.php
deleted file mode 100644
index 0a18fb1..0000000
--- a/core/modules/book/src/Tests/BookUninstallTest.php
+++ /dev/null
@@ -1,99 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\book\Tests\BookUninstallTest.
- */
-
-namespace Drupal\book\Tests;
-
-use Drupal\node\Entity\Node;
-use Drupal\node\Entity\NodeType;
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests that the Book module cannot be uninstalled if books exist.
- *
- * @group book
- */
-class BookUninstallTest extends KernelTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['system', 'user', 'field', 'filter', 'text', 'node', 'book'];
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->installEntitySchema('user');
-    $this->installEntitySchema('node');
-    $this->installSchema('book', array('book'));
-    $this->installSchema('node', array('node_access'));
-    $this->installConfig(array('node', 'book', 'field'));
-    // For uninstall to work.
-    $this->installSchema('user', array('users_data'));
-  }
-
-  /**
-   * Tests the book_system_info_alter() method.
-   */
-  public function testBookUninstall() {
-    // No nodes exist.
-    $validation_reasons = \Drupal::service('module_installer')->validateUninstall(['book']);
-    $this->assertEqual([], $validation_reasons, 'The book module is not required.');
-
-    $content_type = NodeType::create(array(
-      'type' => $this->randomMachineName(),
-      'name' => $this->randomString(),
-    ));
-    $content_type->save();
-    $book_config = $this->config('book.settings');
-    $allowed_types = $book_config->get('allowed_types');
-    $allowed_types[] = $content_type->id();
-    $book_config->set('allowed_types', $allowed_types)->save();
-
-    $node = Node::create(array('title' => $this->randomString(), 'type' => $content_type->id()));
-    $node->book['bid'] = 'new';
-    $node->save();
-
-    // One node in a book but not of type book.
-    $validation_reasons = \Drupal::service('module_installer')->validateUninstall(['book']);
-    $this->assertEqual(['To uninstall Book, delete all content that is part of a book'], $validation_reasons['book']);
-
-    $book_node = Node::create(array('title' => $this->randomString(), 'type' => 'book'));
-    $book_node->book['bid'] = FALSE;
-    $book_node->save();
-
-    // Two nodes, one in a book but not of type book and one book node (which is
-    // not in a book).
-    $validation_reasons = \Drupal::service('module_installer')->validateUninstall(['book']);
-    $this->assertEqual(['To uninstall Book, delete all content that is part of a book'], $validation_reasons['book']);
-
-    $node->delete();
-    // One node of type book but not actually part of a book.
-    $validation_reasons = \Drupal::service('module_installer')->validateUninstall(['book']);
-    $this->assertEqual(['To uninstall Book, delete all content that has the Book content type'], $validation_reasons['book']);
-
-    $book_node->delete();
-    // No nodes exist therefore the book module is not required.
-    $module_data = _system_rebuild_module_data();
-    $this->assertFalse(isset($module_data['book']->info['required']), 'The book module is not required.');
-
-    $node = Node::create(array('title' => $this->randomString(), 'type' => $content_type->id()));
-    $node->save();
-    // One node exists but is not part of a book therefore the book module is
-    // not required.
-    $validation_reasons = \Drupal::service('module_installer')->validateUninstall(['book']);
-    $this->assertEqual([], $validation_reasons, 'The book module is not required.');
-
-    // Uninstall the Book module and check the node type is deleted.
-    \Drupal::service('module_installer')->uninstall(array('book'));
-    $this->assertNull(NodeType::load('book'), "The book node type does not exist.");
-  }
-
-}
diff --git a/core/modules/book/tests/src/Kernel/BookUninstallTest.php b/core/modules/book/tests/src/Kernel/BookUninstallTest.php
new file mode 100644
index 0000000..6dc0821
--- /dev/null
+++ b/core/modules/book/tests/src/Kernel/BookUninstallTest.php
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\book\Tests\BookUninstallTest.
+ */
+
+namespace Drupal\Tests\book\Kernel;
+
+use Drupal\node\Entity\Node;
+use Drupal\node\Entity\NodeType;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests that the Book module cannot be uninstalled if books exist.
+ *
+ * @group book
+ */
+class BookUninstallTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['system', 'user', 'field', 'filter', 'text', 'node', 'book'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->installEntitySchema('user');
+    $this->installEntitySchema('node');
+    $this->installSchema('book', array('book'));
+    $this->installSchema('node', array('node_access'));
+    $this->installConfig(array('node', 'book', 'field'));
+    // For uninstall to work.
+    $this->installSchema('user', array('users_data'));
+  }
+
+  /**
+   * Tests the book_system_info_alter() method.
+   */
+  public function testBookUninstall() {
+    // No nodes exist.
+    $validation_reasons = \Drupal::service('module_installer')->validateUninstall(['book']);
+    $this->assertEqual([], $validation_reasons, 'The book module is not required.');
+
+    $content_type = NodeType::create(array(
+      'type' => $this->randomMachineName(),
+      'name' => $this->randomString(),
+    ));
+    $content_type->save();
+    $book_config = $this->config('book.settings');
+    $allowed_types = $book_config->get('allowed_types');
+    $allowed_types[] = $content_type->id();
+    $book_config->set('allowed_types', $allowed_types)->save();
+
+    $node = Node::create(array('title' => $this->randomString(), 'type' => $content_type->id()));
+    $node->book['bid'] = 'new';
+    $node->save();
+
+    // One node in a book but not of type book.
+    $validation_reasons = \Drupal::service('module_installer')->validateUninstall(['book']);
+    $this->assertEqual(['To uninstall Book, delete all content that is part of a book'], $validation_reasons['book']);
+
+    $book_node = Node::create(array('title' => $this->randomString(), 'type' => 'book'));
+    $book_node->book['bid'] = FALSE;
+    $book_node->save();
+
+    // Two nodes, one in a book but not of type book and one book node (which is
+    // not in a book).
+    $validation_reasons = \Drupal::service('module_installer')->validateUninstall(['book']);
+    $this->assertEqual(['To uninstall Book, delete all content that is part of a book'], $validation_reasons['book']);
+
+    $node->delete();
+    // One node of type book but not actually part of a book.
+    $validation_reasons = \Drupal::service('module_installer')->validateUninstall(['book']);
+    $this->assertEqual(['To uninstall Book, delete all content that has the Book content type'], $validation_reasons['book']);
+
+    $book_node->delete();
+    // No nodes exist therefore the book module is not required.
+    $module_data = _system_rebuild_module_data();
+    $this->assertFalse(isset($module_data['book']->info['required']), 'The book module is not required.');
+
+    $node = Node::create(array('title' => $this->randomString(), 'type' => $content_type->id()));
+    $node->save();
+    // One node exists but is not part of a book therefore the book module is
+    // not required.
+    $validation_reasons = \Drupal::service('module_installer')->validateUninstall(['book']);
+    $this->assertEqual([], $validation_reasons, 'The book module is not required.');
+
+    // Uninstall the Book module and check the node type is deleted.
+    \Drupal::service('module_installer')->uninstall(array('book'));
+    $this->assertNull(NodeType::load('book'), "The book node type does not exist.");
+  }
+
+}
diff --git a/core/modules/breakpoint/src/Tests/BreakpointDiscoveryTest.php b/core/modules/breakpoint/src/Tests/BreakpointDiscoveryTest.php
deleted file mode 100644
index 942239b..0000000
--- a/core/modules/breakpoint/src/Tests/BreakpointDiscoveryTest.php
+++ /dev/null
@@ -1,206 +0,0 @@
-<?php
-/**
- * @file
- * Contains \Drupal\breakpoint\Tests\BreakpointDiscoveryTest.
- */
-
-namespace Drupal\breakpoint\Tests;
-
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests discovery of breakpoints provided by themes and modules.
- *
- * @group breakpoint
- */
-class BreakpointDiscoveryTest extends KernelTestBase {
-
-  /**
-   * Modules to install.
-   *
-   * @var array
-   */
-  public static $modules = array('system', 'breakpoint', 'breakpoint_module_test');
-
-  protected function setUp() {
-    parent::setUp();
-    $this->installSchema('system', array('router'));
-    \Drupal::service('theme_handler')->install(array('breakpoint_theme_test'));
-  }
-
-  /**
-   * Test the breakpoint group created for a theme.
-   */
-  public function testThemeBreakpoints() {
-    // Verify the breakpoint group for breakpoint_theme_test was created.
-    $expected_breakpoints = array(
-      'breakpoint_theme_test.mobile' => array(
-        'label' => 'mobile',
-        'mediaQuery' => '(min-width: 0px)',
-        'weight' => 0,
-        'multipliers' => array(
-          '1x',
-        ),
-        'provider' => 'breakpoint_theme_test',
-        'id' => 'breakpoint_theme_test.mobile',
-        'group' => 'breakpoint_theme_test',
-        'class' => 'Drupal\\breakpoint\\Breakpoint',
-      ),
-      'breakpoint_theme_test.narrow' => array(
-        'label' => 'narrow',
-        'mediaQuery' => '(min-width: 560px)',
-        'weight' => 1,
-        'multipliers' => array(
-          '1x',
-        ),
-        'provider' => 'breakpoint_theme_test',
-        'id' => 'breakpoint_theme_test.narrow',
-        'group' => 'breakpoint_theme_test',
-        'class' => 'Drupal\\breakpoint\\Breakpoint',
-      ),
-      'breakpoint_theme_test.wide' => array(
-        'label' => 'wide',
-        'mediaQuery' => '(min-width: 851px)',
-        'weight' => 2,
-        'multipliers' => array(
-          '1x',
-        ),
-        'provider' => 'breakpoint_theme_test',
-        'id' => 'breakpoint_theme_test.wide',
-        'group' => 'breakpoint_theme_test',
-        'class' => 'Drupal\\breakpoint\\Breakpoint',
-      ),
-      'breakpoint_theme_test.tv' => array(
-        'label' => 'tv',
-        'mediaQuery' => 'only screen and (min-width: 1220px)',
-        'weight' => 3,
-        'multipliers' => array(
-          '1x',
-        ),
-        'provider' => 'breakpoint_theme_test',
-        'id' => 'breakpoint_theme_test.tv',
-        'group' => 'breakpoint_theme_test',
-        'class' => 'Drupal\\breakpoint\\Breakpoint',
-      ),
-    );
-
-    $breakpoints = \Drupal::service('breakpoint.manager')->getBreakpointsByGroup('breakpoint_theme_test');
-    foreach ($expected_breakpoints as $id => $expected_breakpoint) {
-      $this->assertEqual($expected_breakpoint, $breakpoints[$id]->getPluginDefinition());
-    }
-
-    // Test that the order is as expected.
-    $this->assertIdentical(array_keys($expected_breakpoints), array_keys($breakpoints));
-  }
-
-  /**
-   * Test the custom breakpoint group provided by a theme and a module.
-   */
-  public function testCustomBreakpointGroups () {
-    // Verify the breakpoint group for breakpoint_theme_test.group2 was created.
-    $expected_breakpoints = array(
-      'breakpoint_theme_test.group2.narrow' => array(
-        'label' => 'narrow',
-        'mediaQuery' => '(min-width: 560px)',
-        'weight' => 0,
-        'multipliers' => array(
-          '1x',
-          '2x',
-        ),
-        'provider' => 'breakpoint_theme_test',
-        'id' => 'breakpoint_theme_test.group2.narrow',
-        'group' => 'breakpoint_theme_test.group2',
-        'class' => 'Drupal\\breakpoint\\Breakpoint',
-      ),
-      'breakpoint_theme_test.group2.wide' => array(
-        'label' => 'wide',
-        'mediaQuery' => '(min-width: 851px)',
-        'weight' => 1,
-        'multipliers' => array(
-          '1x',
-          '2x',
-        ),
-        'provider' => 'breakpoint_theme_test',
-        'id' => 'breakpoint_theme_test.group2.wide',
-        'group' => 'breakpoint_theme_test.group2',
-        'class' => 'Drupal\\breakpoint\\Breakpoint',
-      ),
-      'breakpoint_module_test.breakpoint_theme_test.group2.tv' => array(
-        'label' => 'tv',
-        'mediaQuery' => '(min-width: 6000px)',
-        'weight' => 2,
-        'multipliers' => array(
-          '1x',
-        ),
-        'provider' => 'breakpoint_module_test',
-        'id' => 'breakpoint_module_test.breakpoint_theme_test.group2.tv',
-        'group' => 'breakpoint_theme_test.group2',
-        'class' => 'Drupal\\breakpoint\\Breakpoint',
-      ),
-    );
-
-    $breakpoints = \Drupal::service('breakpoint.manager')->getBreakpointsByGroup('breakpoint_theme_test.group2');
-    foreach ($expected_breakpoints as $id => $expected_breakpoint) {
-      $this->assertEqual($expected_breakpoint, $breakpoints[$id]->getPluginDefinition());
-    }
-  }
-
-  /**
-   * Test the breakpoint group created for a module.
-   */
-  public function testModuleBreakpoints() {
-    $expected_breakpoints = array(
-      'breakpoint_module_test.mobile' => array(
-        'label' => 'mobile',
-        'mediaQuery' => '(min-width: 0px)',
-        'weight' => 0,
-        'multipliers' => array(
-          '1x',
-        ),
-        'provider' => 'breakpoint_module_test',
-        'id' => 'breakpoint_module_test.mobile',
-        'group' => 'breakpoint_module_test',
-        'class' => 'Drupal\\breakpoint\\Breakpoint',
-      ),
-      'breakpoint_module_test.standard' => array(
-        'label' => 'standard',
-        'mediaQuery' => '(min-width: 560px)',
-        'weight' => 1,
-        'multipliers' => array(
-          '1x',
-          '2x',
-        ),
-        'provider' => 'breakpoint_module_test',
-        'id' => 'breakpoint_module_test.standard',
-        'group' => 'breakpoint_module_test',
-        'class' => 'Drupal\\breakpoint\\Breakpoint',
-      ),
-    );
-
-    $breakpoints = \Drupal::service('breakpoint.manager')->getBreakpointsByGroup('breakpoint_module_test');
-    $this->assertEqual(array_keys($expected_breakpoints), array_keys($breakpoints));
-  }
-
-  /**
-   * Test the collection of breakpoint groups.
-   */
-  public function testBreakpointGroups() {
-    $expected = array(
-      'bartik' => 'Bartik',
-      'breakpoint_module_test' => 'Breakpoint test module',
-      'breakpoint_theme_test' => 'Breakpoint test theme',
-      'breakpoint_theme_test.group2' => 'breakpoint_theme_test.group2',
-    );
-    $breakpoint_groups = \Drupal::service('breakpoint.manager')->getGroups();
-    // Ensure the order is as expected. Should be sorted by label.
-    $this->assertIdentical($expected, $this->castSafeStrings($breakpoint_groups));
-
-    $expected = array(
-      'breakpoint_theme_test' => 'theme',
-      'breakpoint_module_test' => 'module',
-    );
-    $breakpoint_group_providers = \Drupal::service('breakpoint.manager')->getGroupProviders('breakpoint_theme_test.group2');
-    $this->assertEqual($expected, $breakpoint_group_providers);
-  }
-
-}
diff --git a/core/modules/breakpoint/tests/src/Kernel/BreakpointDiscoveryTest.php b/core/modules/breakpoint/tests/src/Kernel/BreakpointDiscoveryTest.php
new file mode 100644
index 0000000..1f13a2d
--- /dev/null
+++ b/core/modules/breakpoint/tests/src/Kernel/BreakpointDiscoveryTest.php
@@ -0,0 +1,206 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\breakpoint\Tests\BreakpointDiscoveryTest.
+ */
+
+namespace Drupal\Tests\breakpoint\Kernel;
+
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests discovery of breakpoints provided by themes and modules.
+ *
+ * @group breakpoint
+ */
+class BreakpointDiscoveryTest extends KernelTestBase {
+
+  /**
+   * Modules to install.
+   *
+   * @var array
+   */
+  public static $modules = array('system', 'breakpoint', 'breakpoint_module_test');
+
+  protected function setUp() {
+    parent::setUp();
+    $this->installSchema('system', array('router'));
+    \Drupal::service('theme_handler')->install(array('breakpoint_theme_test'));
+  }
+
+  /**
+   * Test the breakpoint group created for a theme.
+   */
+  public function testThemeBreakpoints() {
+    // Verify the breakpoint group for breakpoint_theme_test was created.
+    $expected_breakpoints = array(
+      'breakpoint_theme_test.mobile' => array(
+        'label' => 'mobile',
+        'mediaQuery' => '(min-width: 0px)',
+        'weight' => 0,
+        'multipliers' => array(
+          '1x',
+        ),
+        'provider' => 'breakpoint_theme_test',
+        'id' => 'breakpoint_theme_test.mobile',
+        'group' => 'breakpoint_theme_test',
+        'class' => 'Drupal\\breakpoint\\Breakpoint',
+      ),
+      'breakpoint_theme_test.narrow' => array(
+        'label' => 'narrow',
+        'mediaQuery' => '(min-width: 560px)',
+        'weight' => 1,
+        'multipliers' => array(
+          '1x',
+        ),
+        'provider' => 'breakpoint_theme_test',
+        'id' => 'breakpoint_theme_test.narrow',
+        'group' => 'breakpoint_theme_test',
+        'class' => 'Drupal\\breakpoint\\Breakpoint',
+      ),
+      'breakpoint_theme_test.wide' => array(
+        'label' => 'wide',
+        'mediaQuery' => '(min-width: 851px)',
+        'weight' => 2,
+        'multipliers' => array(
+          '1x',
+        ),
+        'provider' => 'breakpoint_theme_test',
+        'id' => 'breakpoint_theme_test.wide',
+        'group' => 'breakpoint_theme_test',
+        'class' => 'Drupal\\breakpoint\\Breakpoint',
+      ),
+      'breakpoint_theme_test.tv' => array(
+        'label' => 'tv',
+        'mediaQuery' => 'only screen and (min-width: 1220px)',
+        'weight' => 3,
+        'multipliers' => array(
+          '1x',
+        ),
+        'provider' => 'breakpoint_theme_test',
+        'id' => 'breakpoint_theme_test.tv',
+        'group' => 'breakpoint_theme_test',
+        'class' => 'Drupal\\breakpoint\\Breakpoint',
+      ),
+    );
+
+    $breakpoints = \Drupal::service('breakpoint.manager')->getBreakpointsByGroup('breakpoint_theme_test');
+    foreach ($expected_breakpoints as $id => $expected_breakpoint) {
+      $this->assertEqual($expected_breakpoint, $breakpoints[$id]->getPluginDefinition());
+    }
+
+    // Test that the order is as expected.
+    $this->assertIdentical(array_keys($expected_breakpoints), array_keys($breakpoints));
+  }
+
+  /**
+   * Test the custom breakpoint group provided by a theme and a module.
+   */
+  public function testCustomBreakpointGroups () {
+    // Verify the breakpoint group for breakpoint_theme_test.group2 was created.
+    $expected_breakpoints = array(
+      'breakpoint_theme_test.group2.narrow' => array(
+        'label' => 'narrow',
+        'mediaQuery' => '(min-width: 560px)',
+        'weight' => 0,
+        'multipliers' => array(
+          '1x',
+          '2x',
+        ),
+        'provider' => 'breakpoint_theme_test',
+        'id' => 'breakpoint_theme_test.group2.narrow',
+        'group' => 'breakpoint_theme_test.group2',
+        'class' => 'Drupal\\breakpoint\\Breakpoint',
+      ),
+      'breakpoint_theme_test.group2.wide' => array(
+        'label' => 'wide',
+        'mediaQuery' => '(min-width: 851px)',
+        'weight' => 1,
+        'multipliers' => array(
+          '1x',
+          '2x',
+        ),
+        'provider' => 'breakpoint_theme_test',
+        'id' => 'breakpoint_theme_test.group2.wide',
+        'group' => 'breakpoint_theme_test.group2',
+        'class' => 'Drupal\\breakpoint\\Breakpoint',
+      ),
+      'breakpoint_module_test.breakpoint_theme_test.group2.tv' => array(
+        'label' => 'tv',
+        'mediaQuery' => '(min-width: 6000px)',
+        'weight' => 2,
+        'multipliers' => array(
+          '1x',
+        ),
+        'provider' => 'breakpoint_module_test',
+        'id' => 'breakpoint_module_test.breakpoint_theme_test.group2.tv',
+        'group' => 'breakpoint_theme_test.group2',
+        'class' => 'Drupal\\breakpoint\\Breakpoint',
+      ),
+    );
+
+    $breakpoints = \Drupal::service('breakpoint.manager')->getBreakpointsByGroup('breakpoint_theme_test.group2');
+    foreach ($expected_breakpoints as $id => $expected_breakpoint) {
+      $this->assertEqual($expected_breakpoint, $breakpoints[$id]->getPluginDefinition());
+    }
+  }
+
+  /**
+   * Test the breakpoint group created for a module.
+   */
+  public function testModuleBreakpoints() {
+    $expected_breakpoints = array(
+      'breakpoint_module_test.mobile' => array(
+        'label' => 'mobile',
+        'mediaQuery' => '(min-width: 0px)',
+        'weight' => 0,
+        'multipliers' => array(
+          '1x',
+        ),
+        'provider' => 'breakpoint_module_test',
+        'id' => 'breakpoint_module_test.mobile',
+        'group' => 'breakpoint_module_test',
+        'class' => 'Drupal\\breakpoint\\Breakpoint',
+      ),
+      'breakpoint_module_test.standard' => array(
+        'label' => 'standard',
+        'mediaQuery' => '(min-width: 560px)',
+        'weight' => 1,
+        'multipliers' => array(
+          '1x',
+          '2x',
+        ),
+        'provider' => 'breakpoint_module_test',
+        'id' => 'breakpoint_module_test.standard',
+        'group' => 'breakpoint_module_test',
+        'class' => 'Drupal\\breakpoint\\Breakpoint',
+      ),
+    );
+
+    $breakpoints = \Drupal::service('breakpoint.manager')->getBreakpointsByGroup('breakpoint_module_test');
+    $this->assertEqual(array_keys($expected_breakpoints), array_keys($breakpoints));
+  }
+
+  /**
+   * Test the collection of breakpoint groups.
+   */
+  public function testBreakpointGroups() {
+    $expected = array(
+      'bartik' => 'Bartik',
+      'breakpoint_module_test' => 'Breakpoint test module',
+      'breakpoint_theme_test' => 'Breakpoint test theme',
+      'breakpoint_theme_test.group2' => 'breakpoint_theme_test.group2',
+    );
+    $breakpoint_groups = \Drupal::service('breakpoint.manager')->getGroups();
+    // Ensure the order is as expected. Should be sorted by label.
+    $this->assertIdentical($expected, $this->castSafeStrings($breakpoint_groups));
+
+    $expected = array(
+      'breakpoint_theme_test' => 'theme',
+      'breakpoint_module_test' => 'module',
+    );
+    $breakpoint_group_providers = \Drupal::service('breakpoint.manager')->getGroupProviders('breakpoint_theme_test.group2');
+    $this->assertEqual($expected, $breakpoint_group_providers);
+  }
+
+}
diff --git a/core/modules/ckeditor/src/Tests/CKEditorPluginManagerTest.php b/core/modules/ckeditor/src/Tests/CKEditorPluginManagerTest.php
deleted file mode 100644
index aec8dbb..0000000
--- a/core/modules/ckeditor/src/Tests/CKEditorPluginManagerTest.php
+++ /dev/null
@@ -1,126 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\ckeditor\Tests\CKEditorPluginManagerTest.
- */
-
-namespace Drupal\ckeditor\Tests;
-
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests different ways of enabling CKEditor plugins.
- *
- * @group ckeditor
- */
-class CKEditorPluginManagerTest extends KernelTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('system', 'user', 'filter', 'editor', 'ckeditor');
-
-  /**
-   * The manager for "CKEditor plugin" plugins.
-   *
-   * @var \Drupal\Component\Plugin\PluginManagerInterface
-   */
-  protected $manager;
-
-  protected function setUp() {
-    parent::setUp();
-
-    // Install the Filter module.
-    $this->installSchema('system', 'url_alias');
-
-    // Create text format, associate CKEditor.
-    $filtered_html_format = entity_create('filter_format', array(
-      'format' => 'filtered_html',
-      'name' => 'Filtered HTML',
-      'weight' => 0,
-      'filters' => array(),
-    ));
-    $filtered_html_format->save();
-    $editor = entity_create('editor', array(
-      'format' => 'filtered_html',
-      'editor' => 'ckeditor',
-    ));
-    $editor->save();
-  }
-
-  /**
-   * Tests the enabling of plugins.
-   */
-  function testEnabledPlugins() {
-    $this->manager = $this->container->get('plugin.manager.ckeditor.plugin');
-    $editor = entity_load('editor', 'filtered_html');
-
-    // Case 1: no CKEditor plugins.
-    $definitions = array_keys($this->manager->getDefinitions());
-    sort($definitions);
-    $this->assertIdentical(array('drupalimage', 'drupalimagecaption', 'drupallink', 'internal', 'stylescombo'), $definitions, 'No CKEditor plugins found besides the built-in ones.');
-    $enabled_plugins = array(
-      'drupalimage' => 'core/modules/ckeditor/js/plugins/drupalimage/plugin.js',
-      'drupallink' => 'core/modules/ckeditor/js/plugins/drupallink/plugin.js',
-    );
-    $this->assertIdentical($enabled_plugins, $this->manager->getEnabledPluginFiles($editor), 'Only built-in plugins are enabled.');
-    $this->assertIdentical(array('internal' => NULL) + $enabled_plugins, $this->manager->getEnabledPluginFiles($editor, TRUE), 'Only the "internal" plugin is enabled.');
-
-    // Enable the CKEditor Test module, which has the Llama plugin (plus three
-    // variations of it, to cover all possible ways a plugin can be enabled) and
-    // clear the editor manager's cache so it is picked up.
-    $this->enableModules(array('ckeditor_test'));
-    $this->manager = $this->container->get('plugin.manager.ckeditor.plugin');
-    $this->manager->clearCachedDefinitions();
-
-    // Case 2: CKEditor plugins are available.
-    $plugin_ids = array_keys($this->manager->getDefinitions());
-    sort($plugin_ids);
-    $this->assertIdentical(array('drupalimage', 'drupalimagecaption', 'drupallink', 'internal', 'llama', 'llama_button', 'llama_contextual', 'llama_contextual_and_button', 'stylescombo'), $plugin_ids, 'Additional CKEditor plugins found.');
-    $this->assertIdentical($enabled_plugins, $this->manager->getEnabledPluginFiles($editor), 'Only the internal plugins are enabled.');
-    $this->assertIdentical(array('internal' => NULL) + $enabled_plugins, $this->manager->getEnabledPluginFiles($editor, TRUE), 'Only the "internal" plugin is enabled.');
-
-    // Case 3: enable each of the newly available plugins, if possible:
-    // a. Llama: cannot be enabled, since it does not implement
-    //    CKEditorPluginContextualInterface nor CKEditorPluginButtonsInterface.
-    // b. LlamaContextual: enabled by adding the 'Strike' button, which is
-    //    part of another plugin!
-    // c. LlamaButton: automatically enabled by adding its 'Llama' button.
-    // d. LlamaContextualAndButton: enabled by either b or c.
-    // Below, we will first enable the "Llama" button, which will cause the
-    // LlamaButton and LlamaContextualAndButton plugins to be enabled. Then we
-    // will remove the "Llama" button and add the "Strike" button, which will
-    // cause the LlamaContextual and LlamaContextualAndButton plugins to be
-    // enabled. Finally, we will add the "Strike" button back again, which would
-    // cause all three plugins to be enabled.
-    $settings = $editor->getSettings();
-    $original_toolbar = $settings['toolbar'];
-    $settings['toolbar']['rows'][0][0]['items'][] = 'Llama';
-    $editor->setSettings($settings);
-    $editor->save();
-    $file = array();
-    $file['b'] = 'core/modules/ckeditor/tests/modules/js/llama_button.js';
-    $file['c'] = 'core/modules/ckeditor/tests/modules/js/llama_contextual.js';
-    $file['cb'] = 'core/modules/ckeditor/tests/modules/js/llama_contextual_and_button.js';
-    $expected = $enabled_plugins + array('llama_button' => $file['b'], 'llama_contextual_and_button' => $file['cb']);
-    $this->assertIdentical($expected, $this->manager->getEnabledPluginFiles($editor), 'The LlamaButton and LlamaContextualAndButton plugins are enabled.');
-    $this->assertIdentical(array('internal' => NULL) + $expected, $this->manager->getEnabledPluginFiles($editor, TRUE), 'The LlamaButton and LlamaContextualAndButton plugins are enabled.');
-    $settings['toolbar'] = $original_toolbar;
-    $settings['toolbar']['rows'][0][0]['items'][] = 'Strike';
-    $editor->setSettings($settings);
-    $editor->save();
-    $expected = $enabled_plugins + array('llama_contextual' => $file['c'], 'llama_contextual_and_button' => $file['cb']);
-    $this->assertIdentical($expected, $this->manager->getEnabledPluginFiles($editor), 'The  LLamaContextual and LlamaContextualAndButton plugins are enabled.');
-    $this->assertIdentical(array('internal' => NULL) + $expected, $this->manager->getEnabledPluginFiles($editor, TRUE), 'The LlamaContextual and LlamaContextualAndButton plugins are enabled.');
-    $settings['toolbar']['rows'][0][0]['items'][] = 'Llama';
-    $editor->setSettings($settings);
-    $editor->save();
-    $expected = $enabled_plugins + array('llama_button' => $file['b'], 'llama_contextual' => $file['c'], 'llama_contextual_and_button' => $file['cb']);
-    $this->assertIdentical($expected, $this->manager->getEnabledPluginFiles($editor), 'The LlamaButton, LlamaContextual and LlamaContextualAndButton plugins are enabled.');
-    $this->assertIdentical(array('internal' => NULL) + $expected, $this->manager->getEnabledPluginFiles($editor, TRUE), 'The LLamaButton, LlamaContextual and LlamaContextualAndButton plugins are enabled.');
-  }
-
-}
diff --git a/core/modules/ckeditor/src/Tests/CKEditorTest.php b/core/modules/ckeditor/src/Tests/CKEditorTest.php
deleted file mode 100644
index fb0e55a..0000000
--- a/core/modules/ckeditor/src/Tests/CKEditorTest.php
+++ /dev/null
@@ -1,487 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\ckeditor\Tests\CKEditorTest.
- */
-
-namespace Drupal\ckeditor\Tests;
-
-use Drupal\simpletest\KernelTestBase;
-use Drupal\language\Entity\ConfigurableLanguage;
-use Drupal\editor\Entity\Editor;
-
-/**
- * Tests for the 'CKEditor' text editor plugin.
- *
- * @group ckeditor
- */
-class CKEditorTest extends KernelTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('system', 'user', 'filter', 'editor', 'ckeditor', 'filter_test');
-
-  /**
-   * An instance of the "CKEditor" text editor plugin.
-   *
-   * @var \Drupal\ckeditor\Plugin\Editor\CKEditor;
-   */
-  protected $ckeditor;
-
-  /**
-   * The Editor Plugin Manager.
-   *
-   * @var \Drupal\editor\Plugin\EditorManager;
-   */
-  protected $manager;
-
-  protected function setUp() {
-    parent::setUp();
-
-    // Install the Filter module.
-    $this->installSchema('system', 'url_alias');
-
-    // Create text format, associate CKEditor.
-    $filtered_html_format = entity_create('filter_format', array(
-      'format' => 'filtered_html',
-      'name' => 'Filtered HTML',
-      'weight' => 0,
-      'filters' => array(
-        'filter_html' => array(
-          'status' => 1,
-          'settings' => array(
-            'allowed_html' => '<h2 id> <h3> <h4> <h5> <h6> <p> <br> <strong> <a href hreflang>',
-          )
-        ),
-      ),
-    ));
-    $filtered_html_format->save();
-    $editor = entity_create('editor', array(
-      'format' => 'filtered_html',
-      'editor' => 'ckeditor',
-    ));
-    $editor->save();
-
-    // Create "CKEditor" text editor plugin instance.
-    $this->ckeditor = $this->container->get('plugin.manager.editor')->createInstance('ckeditor');
-  }
-
-  /**
-   * Tests CKEditor::getJSSettings().
-   */
-  function testGetJSSettings() {
-    $editor = entity_load('editor', 'filtered_html');
-
-    // Default toolbar.
-    $expected_config = $this->getDefaultInternalConfig() + array(
-      'drupalImage_dialogTitleAdd' => 'Insert Image',
-      'drupalImage_dialogTitleEdit' => 'Edit Image',
-      'drupalLink_dialogTitleAdd' => 'Add Link',
-      'drupalLink_dialogTitleEdit' => 'Edit Link',
-      'allowedContent' => $this->getDefaultAllowedContentConfig(),
-      'disallowedContent' => $this->getDefaultDisallowedContentConfig(),
-      'toolbar' => $this->getDefaultToolbarConfig(),
-      'contentsCss' => $this->getDefaultContentsCssConfig(),
-      'extraPlugins' => 'drupalimage,drupallink',
-      'language' => 'en',
-      'stylesSet' => FALSE,
-      'drupalExternalPlugins' => array(
-        'drupalimage' => file_url_transform_relative(file_create_url('core/modules/ckeditor/js/plugins/drupalimage/plugin.js')),
-        'drupallink' => file_url_transform_relative(file_create_url('core/modules/ckeditor/js/plugins/drupallink/plugin.js')),
-      ),
-    );
-    $expected_config = $this->castSafeStrings($expected_config);
-    ksort($expected_config);
-    ksort($expected_config['allowedContent']);
-    $this->assertIdentical($expected_config, $this->castSafeStrings($this->ckeditor->getJSSettings($editor)), 'Generated JS settings are correct for default configuration.');
-
-    // Customize the configuration: add button, have two contextually enabled
-    // buttons, and configure a CKEditor plugin setting.
-    $this->enableModules(array('ckeditor_test'));
-    $this->container->get('plugin.manager.editor')->clearCachedDefinitions();
-    $this->ckeditor = $this->container->get('plugin.manager.editor')->createInstance('ckeditor');
-    $this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions();
-    $settings = $editor->getSettings();
-    $settings['toolbar']['rows'][0][0]['items'][] = 'Strike';
-    $settings['toolbar']['rows'][0][0]['items'][] = 'Format';
-    $editor->setSettings($settings);
-    $editor->save();
-    $expected_config['toolbar'][0]['items'][] = 'Strike';
-    $expected_config['toolbar'][0]['items'][] = 'Format';
-    $expected_config['format_tags'] = 'p;h2;h3;h4;h5;h6';
-    $expected_config['extraPlugins'] .= ',llama_contextual,llama_contextual_and_button';
-    $expected_config['drupalExternalPlugins']['llama_contextual'] = file_url_transform_relative(file_create_url('core/modules/ckeditor/tests/modules/js/llama_contextual.js'));
-    $expected_config['drupalExternalPlugins']['llama_contextual_and_button'] = file_url_transform_relative(file_create_url('core/modules/ckeditor/tests/modules/js/llama_contextual_and_button.js'));
-    $expected_config['contentsCss'][] = file_url_transform_relative(file_create_url('core/modules/ckeditor/tests/modules/ckeditor_test.css'));
-    ksort($expected_config);
-    $this->assertIdentical($expected_config, $this->castSafeStrings($this->ckeditor->getJSSettings($editor)), 'Generated JS settings are correct for customized configuration.');
-
-    // Change the allowed HTML tags; the "allowedContent" and "format_tags"
-    // settings for CKEditor should automatically be updated as well.
-    $format = $editor->getFilterFormat();
-    $format->filters('filter_html')->settings['allowed_html'] .= '<pre class> <h1> <blockquote class="*"> <address class="foo bar-* *">';
-    $format->save();
-
-    $expected_config['allowedContent']['pre'] = array('attributes' => 'class', 'styles' => FALSE, 'classes' => TRUE);
-    $expected_config['allowedContent']['h1'] = array('attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE);
-    $expected_config['allowedContent']['blockquote'] = array('attributes' => 'class', 'styles' => FALSE, 'classes' => TRUE);
-    $expected_config['allowedContent']['address'] = array('attributes' => 'class', 'styles' => FALSE, 'classes' => 'foo,bar-*');
-    $expected_config['format_tags'] = 'p;h1;h2;h3;h4;h5;h6;pre';
-    ksort($expected_config['allowedContent']);
-    $this->assertIdentical($expected_config, $this->castSafeStrings($this->ckeditor->getJSSettings($editor)), 'Generated JS settings are correct for customized configuration.');
-
-    // Disable the filter_html filter: allow *all *tags.
-    $format->setFilterConfig('filter_html', array('status' => 0));
-    $format->save();
-
-    $expected_config['allowedContent'] = TRUE;
-    $expected_config['disallowedContent'] = FALSE;
-    $expected_config['format_tags'] = 'p;h1;h2;h3;h4;h5;h6;pre';
-    $this->assertIdentical($expected_config, $this->castSafeStrings($this->ckeditor->getJSSettings($editor)), 'Generated JS settings are correct for customized configuration.');
-
-    // Enable the filter_test_restrict_tags_and_attributes filter.
-    $format->setFilterConfig('filter_test_restrict_tags_and_attributes', array(
-      'status' => 1,
-      'settings' => array(
-        'restrictions' => array(
-          'allowed' => array(
-            'p' => TRUE,
-            'a' => array(
-              'href' => TRUE,
-              'rel' => array('nofollow' => TRUE),
-              'class' => array('external' => TRUE),
-              'target' => array('_blank' => FALSE),
-            ),
-            'span' => array(
-              'class' => array('dodo' => FALSE),
-              'property' => array('dc:*' => TRUE),
-              'rel' => array('foaf:*' => FALSE),
-              'style' => array('underline' => FALSE, 'color' => FALSE, 'font-size' => TRUE),
-            ),
-            '*' => array(
-              'style' => FALSE,
-              'on*' => FALSE,
-              'class' => array('is-a-hipster-llama' => TRUE, 'and-more' => TRUE),
-              'data-*' => TRUE,
-            ),
-            'del' => FALSE,
-          ),
-        ),
-      ),
-    ));
-    $format->save();
-
-    $expected_config['allowedContent'] = array(
-      'p' => array(
-        'attributes' => TRUE,
-        'styles' => FALSE,
-        'classes' => 'is-a-hipster-llama,and-more',
-      ),
-      'a' => array(
-        'attributes' => 'href,rel,class,target',
-        'styles' => FALSE,
-        'classes' => 'external',
-      ),
-      'span' => array(
-        'attributes' => 'class,property,rel,style',
-        'styles' => 'font-size',
-        'classes' => FALSE,
-      ),
-      '*' => array(
-        'attributes' => 'class,data-*',
-        'styles' => FALSE,
-        'classes' => 'is-a-hipster-llama,and-more',
-      ),
-      'del' => array(
-        'attributes' => FALSE,
-        'styles' => FALSE,
-        'classes' => FALSE,
-      ),
-    );
-    $expected_config['disallowedContent'] = array(
-      'span' => array(
-        'styles' => 'underline,color',
-        'classes' => 'dodo',
-      ),
-      '*' => array(
-        'attributes' => 'on*',
-      ),
-    );
-    $expected_config['format_tags'] = 'p';
-    ksort($expected_config);
-    ksort($expected_config['allowedContent']);
-    ksort($expected_config['disallowedContent']);
-    $this->assertIdentical($expected_config, $this->castSafeStrings($this->ckeditor->getJSSettings($editor)), 'Generated JS settings are correct for customized configuration.');
-  }
-
-  /**
-   * Tests CKEditor::buildToolbarJSSetting().
-   */
-  function testBuildToolbarJSSetting() {
-    $editor = entity_load('editor', 'filtered_html');
-
-    // Default toolbar.
-    $expected = $this->getDefaultToolbarConfig();
-    $this->assertIdentical($expected, $this->castSafeStrings($this->ckeditor->buildToolbarJSSetting($editor)), '"toolbar" configuration part of JS settings built correctly for default toolbar.');
-
-    // Customize the configuration.
-    $settings = $editor->getSettings();
-    $settings['toolbar']['rows'][0][0]['items'][] = 'Strike';
-    $editor->setSettings($settings);
-    $editor->save();
-    $expected[0]['items'][] = 'Strike';
-    $this->assertIdentical($expected, $this->castSafeStrings($this->ckeditor->buildToolbarJSSetting($editor)), '"toolbar" configuration part of JS settings built correctly for customized toolbar.');
-
-    // Enable the editor_test module, customize further.
-    $this->enableModules(array('ckeditor_test'));
-    $this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions();
-    // Override the label of a toolbar component.
-    $settings['toolbar']['rows'][0][0]['name'] = 'JunkScience';
-    $settings['toolbar']['rows'][0][0]['items'][] = 'Llama';
-    $editor->setSettings($settings);
-    $editor->save();
-    $expected[0]['name'] = 'JunkScience';
-    $expected[0]['items'][] = 'Llama';
-    $this->assertIdentical($expected, $this->castSafeStrings($this->ckeditor->buildToolbarJSSetting($editor)), '"toolbar" configuration part of JS settings built correctly for customized toolbar with contrib module-provided CKEditor plugin.');
-  }
-
-  /**
-   * Tests CKEditor::buildContentsCssJSSetting().
-   */
-  function testBuildContentsCssJSSetting() {
-    $editor = entity_load('editor', 'filtered_html');
-
-    // Default toolbar.
-    $expected = $this->getDefaultContentsCssConfig();
-    $this->assertIdentical($expected, $this->ckeditor->buildContentsCssJSSetting($editor), '"contentsCss" configuration part of JS settings built correctly for default toolbar.');
-
-    // Enable the editor_test module, which implements hook_ckeditor_css_alter().
-    $this->enableModules(array('ckeditor_test'));
-    $expected[] = file_url_transform_relative(file_create_url('core/modules/ckeditor/tests/modules/ckeditor_test.css'));
-    $this->assertIdentical($expected, $this->ckeditor->buildContentsCssJSSetting($editor), '"contentsCss" configuration part of JS settings built correctly while a hook_ckeditor_css_alter() implementation exists.');
-
-    // Enable the Bartik theme, which specifies a CKEditor stylesheet.
-    \Drupal::service('theme_handler')->install(['bartik']);
-    $this->config('system.theme')->set('default', 'bartik')->save();
-    $expected[] = file_url_transform_relative(file_create_url('core/themes/bartik/css/base/elements.css'));
-    $expected[] = file_url_transform_relative(file_create_url('core/themes/bartik/css/components/captions.css'));
-    $expected[] = file_url_transform_relative(file_create_url('core/themes/bartik/css/components/table.css'));
-    $expected[] = file_url_transform_relative(file_create_url('core/themes/bartik/css/components/text-formatted.css'));
-    $this->assertIdentical($expected, $this->ckeditor->buildContentsCssJSSetting($editor), '"contentsCss" configuration part of JS settings built correctly while a theme providing a CKEditor stylesheet exists.');
-  }
-
-  /**
-   * Tests Internal::getConfig().
-   */
-  function testInternalGetConfig() {
-    $editor = entity_load('editor', 'filtered_html');
-    $internal_plugin = $this->container->get('plugin.manager.ckeditor.plugin')->createInstance('internal');
-
-    // Default toolbar.
-    $expected = $this->getDefaultInternalConfig();
-    $expected['disallowedContent'] = $this->getDefaultDisallowedContentConfig();
-    $expected['allowedContent'] = $this->getDefaultAllowedContentConfig();
-    $this->assertEqual($expected, $internal_plugin->getConfig($editor), '"Internal" plugin configuration built correctly for default toolbar.');
-
-    // Format dropdown/button enabled: new setting should be present.
-    $settings = $editor->getSettings();
-    $settings['toolbar']['rows'][0][0]['items'][] = 'Format';
-    $editor->setSettings($settings);
-    $expected['format_tags'] = 'p;h2;h3;h4;h5;h6';
-    $this->assertEqual($expected, $internal_plugin->getConfig($editor), '"Internal" plugin configuration built correctly for customized toolbar.');
-  }
-
-  /**
-   * Tests StylesCombo::getConfig().
-   */
-  function testStylesComboGetConfig() {
-    $editor = entity_load('editor', 'filtered_html');
-    $stylescombo_plugin = $this->container->get('plugin.manager.ckeditor.plugin')->createInstance('stylescombo');
-
-    // Styles dropdown/button enabled: new setting should be present.
-    $settings = $editor->getSettings();
-    $settings['toolbar']['rows'][0][0]['items'][] = 'Styles';
-    $settings['plugins']['stylescombo']['styles'] = '';
-    $editor->setSettings($settings);
-    $editor->save();
-    $expected['stylesSet'] = array();
-    $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
-
-    // Configure the optional "styles" setting in odd ways that shouldn't affect
-    // the end result.
-    $settings['plugins']['stylescombo']['styles'] = "   \n";
-    $editor->setSettings($settings);
-    $editor->save();
-    $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor));
-    $settings['plugins']['stylescombo']['styles'] = "\r\n  \n  \r  \n ";
-    $editor->setSettings($settings);
-    $editor->save();
-    $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
-
-    // Now configure it properly, the end result should change.
-    $settings['plugins']['stylescombo']['styles'] = "h1.title|Title\np.mAgical.Callout|Callout";
-    $editor->setSettings($settings);
-    $editor->save();
-    $expected['stylesSet'] = array(
-      array('name' => 'Title', 'element' => 'h1', 'attributes' => array('class' => 'title')),
-      array('name' => 'Callout', 'element' => 'p', 'attributes' => array('class' => 'mAgical Callout')),
-    );
-    $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
-
-    // Same configuration, but now interspersed with nonsense. Should yield the
-    // same result.
-    $settings['plugins']['stylescombo']['styles'] = "  h1 .title   |  Title \r \n\r  \np.mAgical  .Callout|Callout\r";
-    $editor->setSettings($settings);
-    $editor->save();
-    $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
-
-    // Slightly different configuration: class names are optional.
-    $settings['plugins']['stylescombo']['styles'] = "      h1 |  Title ";
-    $editor->setSettings($settings);
-    $editor->save();
-    $expected['stylesSet'] = array(array('name' => 'Title', 'element' => 'h1'));
-    $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
-
-    // Invalid syntax should cause stylesSet to be set to FALSE.
-    $settings['plugins']['stylescombo']['styles'] = "h1";
-    $editor->setSettings($settings);
-    $editor->save();
-    $expected['stylesSet'] = FALSE;
-    $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
-  }
-
-  /**
-   * Tests language list availability in CKEditor.
-   */
-  function testLanguages() {
-    // Get CKEditor supported language codes and spot-check.
-    $this->enableModules(array('language'));
-    $this->installConfig(array('language'));
-    $langcodes = $this->ckeditor->getLangcodes();
-
-    // Language codes transformed with browser mappings.
-    $this->assertTrue($langcodes['pt-pt'] == 'pt', '"pt" properly resolved');
-    $this->assertTrue($langcodes['zh-hans'] == 'zh-cn', '"zh-hans" properly resolved');
-
-    // Language code both in Drupal and CKEditor.
-    $this->assertTrue($langcodes['gl'] == 'gl', '"gl" properly resolved');
-
-    // Language codes only in CKEditor.
-    $this->assertTrue($langcodes['en-au'] == 'en-au', '"en-au" properly resolved');
-    $this->assertTrue($langcodes['sr-latn'] == 'sr-latn', '"sr-latn" properly resolved');
-
-    // No locale module, so even though languages are enabled, CKEditor should
-    // still be in English.
-    $this->assertCKEditorLanguage('en');
-  }
-
-  /**
-   * Tests that CKEditor plugins participate in JS translation.
-   */
-  function testJSTranslation() {
-    $this->enableModules(array('language', 'locale'));
-    $this->installSchema('locale', 'locales_source');
-    $this->installSchema('locale', 'locales_location');
-    $this->installSchema('locale', 'locales_target');
-    $editor = Editor::load('filtered_html');
-    $this->ckeditor->getJSSettings($editor);
-    $localeStorage = $this->container->get('locale.storage');
-    $string = $localeStorage->findString(array('source' => 'Edit Link', 'context' => ''));
-    $this->assertTrue(!empty($string), 'String from JavaScript file saved.');
-
-    // With locale module, CKEditor should not adhere to the language selected.
-    $this->assertCKEditorLanguage();
-  }
-
-  /**
-   * Assert that CKEditor picks the expected language when French is default.
-   *
-   * @param string $langcode
-   *   Language code to assert for. Defaults to French. That is the default
-   *   language set in this assertion.
-   */
-  protected function assertCKEditorLanguage($langcode = 'fr') {
-    // Set French as the site default language.
-    ConfigurableLanguage::createFromLangcode('fr')->save();
-    $this->config('system.site')->set('default_langcode', 'fr')->save();
-
-    // Reset the language manager so new negotiations attempts will fall back on
-    // French. Reinject the language manager CKEditor to use the current one.
-    $this->container->get('language_manager')->reset();
-    $this->ckeditor = $this->container->get('plugin.manager.editor')->createInstance('ckeditor');
-
-    // Test that we now get the expected language.
-    $editor = Editor::load('filtered_html');
-    $settings = $this->ckeditor->getJSSettings($editor);
-    $this->assertEqual($settings['language'], $langcode);
-  }
-
-  protected function getDefaultInternalConfig() {
-    return array(
-      'customConfig' => '',
-      'pasteFromWordPromptCleanup' => TRUE,
-      'resize_dir' => 'vertical',
-      'justifyClasses' => array('text-align-left', 'text-align-center', 'text-align-right', 'text-align-justify'),
-      'entities' => FALSE,
-    );
-  }
-
-  protected function getDefaultAllowedContentConfig() {
-    return [
-      'h2' => ['attributes' => 'id', 'styles' => FALSE, 'classes' => FALSE],
-      'h3' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
-      'h4' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
-      'h5' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
-      'h6' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
-      'p' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
-      'br' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
-      'strong' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
-      'a' => ['attributes' => 'href,hreflang', 'styles' => FALSE, 'classes' => FALSE],
-      '*' => ['attributes' => 'lang,dir', 'styles' => FALSE, 'classes' => FALSE],
-    ];
-  }
-
-  protected function getDefaultDisallowedContentConfig() {
-    return array(
-      '*' => array('attributes' => 'on*'),
-    );
-  }
-
-  protected function getDefaultToolbarConfig() {
-    return array(
-      array(
-        'name' => 'Formatting',
-        'items' => array('Bold', 'Italic',),
-      ),
-      array(
-        'name' => 'Links',
-        'items' => array('DrupalLink', 'DrupalUnlink',),
-      ),
-      array(
-        'name' => 'Lists',
-        'items' => array('BulletedList', 'NumberedList',),
-      ),
-      array(
-        'name' => 'Media',
-        'items' => array('Blockquote', 'DrupalImage',),
-      ),
-      array(
-        'name' => 'Tools',
-        'items' => array('Source',),
-      ),
-      '/',
-    );
-  }
-
-  protected function getDefaultContentsCssConfig() {
-    return array(
-      file_url_transform_relative(file_create_url('core/modules/ckeditor/css/ckeditor-iframe.css')),
-      file_url_transform_relative(file_create_url('core/modules/system/css/components/align.module.css')),
-    );
-  }
-
-}
diff --git a/core/modules/ckeditor/tests/modules/src/Kernel/CKEditorPluginManagerTest.php b/core/modules/ckeditor/tests/modules/src/Kernel/CKEditorPluginManagerTest.php
new file mode 100644
index 0000000..4ebb39a
--- /dev/null
+++ b/core/modules/ckeditor/tests/modules/src/Kernel/CKEditorPluginManagerTest.php
@@ -0,0 +1,126 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\ckeditor\Kernel\CKEditorPluginManagerTest.
+ */
+
+namespace Drupal\Tests\ckeditor\Kernel;
+
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests different ways of enabling CKEditor plugins.
+ *
+ * @group ckeditor
+ */
+class CKEditorPluginManagerTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('system', 'user', 'filter', 'editor', 'ckeditor');
+
+  /**
+   * The manager for "CKEditor plugin" plugins.
+   *
+   * @var \Drupal\Component\Plugin\PluginManagerInterface
+   */
+  protected $manager;
+
+  protected function setUp() {
+    parent::setUp();
+
+    // Install the Filter module.
+    $this->installSchema('system', 'url_alias');
+
+    // Create text format, associate CKEditor.
+    $filtered_html_format = entity_create('filter_format', array(
+      'format' => 'filtered_html',
+      'name' => 'Filtered HTML',
+      'weight' => 0,
+      'filters' => array(),
+    ));
+    $filtered_html_format->save();
+    $editor = entity_create('editor', array(
+      'format' => 'filtered_html',
+      'editor' => 'ckeditor',
+    ));
+    $editor->save();
+  }
+
+  /**
+   * Tests the enabling of plugins.
+   */
+  function testEnabledPlugins() {
+    $this->manager = $this->container->get('plugin.manager.ckeditor.plugin');
+    $editor = entity_load('editor', 'filtered_html');
+
+    // Case 1: no CKEditor plugins.
+    $definitions = array_keys($this->manager->getDefinitions());
+    sort($definitions);
+    $this->assertIdentical(array('drupalimage', 'drupalimagecaption', 'drupallink', 'internal', 'stylescombo'), $definitions, 'No CKEditor plugins found besides the built-in ones.');
+    $enabled_plugins = array(
+      'drupalimage' => 'core/modules/ckeditor/js/plugins/drupalimage/plugin.js',
+      'drupallink' => 'core/modules/ckeditor/js/plugins/drupallink/plugin.js',
+    );
+    $this->assertIdentical($enabled_plugins, $this->manager->getEnabledPluginFiles($editor), 'Only built-in plugins are enabled.');
+    $this->assertIdentical(array('internal' => NULL) + $enabled_plugins, $this->manager->getEnabledPluginFiles($editor, TRUE), 'Only the "internal" plugin is enabled.');
+
+    // Enable the CKEditor Test module, which has the Llama plugin (plus three
+    // variations of it, to cover all possible ways a plugin can be enabled) and
+    // clear the editor manager's cache so it is picked up.
+    $this->enableModules(array('ckeditor_test'));
+    $this->manager = $this->container->get('plugin.manager.ckeditor.plugin');
+    $this->manager->clearCachedDefinitions();
+
+    // Case 2: CKEditor plugins are available.
+    $plugin_ids = array_keys($this->manager->getDefinitions());
+    sort($plugin_ids);
+    $this->assertIdentical(array('drupalimage', 'drupalimagecaption', 'drupallink', 'internal', 'llama', 'llama_button', 'llama_contextual', 'llama_contextual_and_button', 'stylescombo'), $plugin_ids, 'Additional CKEditor plugins found.');
+    $this->assertIdentical($enabled_plugins, $this->manager->getEnabledPluginFiles($editor), 'Only the internal plugins are enabled.');
+    $this->assertIdentical(array('internal' => NULL) + $enabled_plugins, $this->manager->getEnabledPluginFiles($editor, TRUE), 'Only the "internal" plugin is enabled.');
+
+    // Case 3: enable each of the newly available plugins, if possible:
+    // a. Llama: cannot be enabled, since it does not implement
+    //    CKEditorPluginContextualInterface nor CKEditorPluginButtonsInterface.
+    // b. LlamaContextual: enabled by adding the 'Strike' button, which is
+    //    part of another plugin!
+    // c. LlamaButton: automatically enabled by adding its 'Llama' button.
+    // d. LlamaContextualAndButton: enabled by either b or c.
+    // Below, we will first enable the "Llama" button, which will cause the
+    // LlamaButton and LlamaContextualAndButton plugins to be enabled. Then we
+    // will remove the "Llama" button and add the "Strike" button, which will
+    // cause the LlamaContextual and LlamaContextualAndButton plugins to be
+    // enabled. Finally, we will add the "Strike" button back again, which would
+    // cause all three plugins to be enabled.
+    $settings = $editor->getSettings();
+    $original_toolbar = $settings['toolbar'];
+    $settings['toolbar']['rows'][0][0]['items'][] = 'Llama';
+    $editor->setSettings($settings);
+    $editor->save();
+    $file = array();
+    $file['b'] = 'core/modules/ckeditor/tests/modules/js/llama_button.js';
+    $file['c'] = 'core/modules/ckeditor/tests/modules/js/llama_contextual.js';
+    $file['cb'] = 'core/modules/ckeditor/tests/modules/js/llama_contextual_and_button.js';
+    $expected = $enabled_plugins + array('llama_button' => $file['b'], 'llama_contextual_and_button' => $file['cb']);
+    $this->assertIdentical($expected, $this->manager->getEnabledPluginFiles($editor), 'The LlamaButton and LlamaContextualAndButton plugins are enabled.');
+    $this->assertIdentical(array('internal' => NULL) + $expected, $this->manager->getEnabledPluginFiles($editor, TRUE), 'The LlamaButton and LlamaContextualAndButton plugins are enabled.');
+    $settings['toolbar'] = $original_toolbar;
+    $settings['toolbar']['rows'][0][0]['items'][] = 'Strike';
+    $editor->setSettings($settings);
+    $editor->save();
+    $expected = $enabled_plugins + array('llama_contextual' => $file['c'], 'llama_contextual_and_button' => $file['cb']);
+    $this->assertIdentical($expected, $this->manager->getEnabledPluginFiles($editor), 'The  LLamaContextual and LlamaContextualAndButton plugins are enabled.');
+    $this->assertIdentical(array('internal' => NULL) + $expected, $this->manager->getEnabledPluginFiles($editor, TRUE), 'The LlamaContextual and LlamaContextualAndButton plugins are enabled.');
+    $settings['toolbar']['rows'][0][0]['items'][] = 'Llama';
+    $editor->setSettings($settings);
+    $editor->save();
+    $expected = $enabled_plugins + array('llama_button' => $file['b'], 'llama_contextual' => $file['c'], 'llama_contextual_and_button' => $file['cb']);
+    $this->assertIdentical($expected, $this->manager->getEnabledPluginFiles($editor), 'The LlamaButton, LlamaContextual and LlamaContextualAndButton plugins are enabled.');
+    $this->assertIdentical(array('internal' => NULL) + $expected, $this->manager->getEnabledPluginFiles($editor, TRUE), 'The LLamaButton, LlamaContextual and LlamaContextualAndButton plugins are enabled.');
+  }
+
+}
diff --git a/core/modules/ckeditor/tests/modules/src/Kernel/CKEditorTest.php b/core/modules/ckeditor/tests/modules/src/Kernel/CKEditorTest.php
new file mode 100644
index 0000000..36e5e97
--- /dev/null
+++ b/core/modules/ckeditor/tests/modules/src/Kernel/CKEditorTest.php
@@ -0,0 +1,487 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\ckeditor\Kernel\CKEditorTest.
+ */
+
+namespace Drupal\Tests\ckeditor\Kernel;
+
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\editor\Entity\Editor;
+
+/**
+ * Tests for the 'CKEditor' text editor plugin.
+ *
+ * @group ckeditor
+ */
+class CKEditorTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('system', 'user', 'filter', 'editor', 'ckeditor', 'filter_test');
+
+  /**
+   * An instance of the "CKEditor" text editor plugin.
+   *
+   * @var \Drupal\ckeditor\Plugin\Editor\CKEditor;
+   */
+  protected $ckeditor;
+
+  /**
+   * The Editor Plugin Manager.
+   *
+   * @var \Drupal\editor\Plugin\EditorManager;
+   */
+  protected $manager;
+
+  protected function setUp() {
+    parent::setUp();
+
+    // Install the Filter module.
+    $this->installSchema('system', 'url_alias');
+
+    // Create text format, associate CKEditor.
+    $filtered_html_format = entity_create('filter_format', array(
+      'format' => 'filtered_html',
+      'name' => 'Filtered HTML',
+      'weight' => 0,
+      'filters' => array(
+        'filter_html' => array(
+          'status' => 1,
+          'settings' => array(
+            'allowed_html' => '<h2 id> <h3> <h4> <h5> <h6> <p> <br> <strong> <a href hreflang>',
+          )
+        ),
+      ),
+    ));
+    $filtered_html_format->save();
+    $editor = entity_create('editor', array(
+      'format' => 'filtered_html',
+      'editor' => 'ckeditor',
+    ));
+    $editor->save();
+
+    // Create "CKEditor" text editor plugin instance.
+    $this->ckeditor = $this->container->get('plugin.manager.editor')->createInstance('ckeditor');
+  }
+
+  /**
+   * Tests CKEditor::getJSSettings().
+   */
+  function testGetJSSettings() {
+    $editor = entity_load('editor', 'filtered_html');
+
+    // Default toolbar.
+    $expected_config = $this->getDefaultInternalConfig() + array(
+      'drupalImage_dialogTitleAdd' => 'Insert Image',
+      'drupalImage_dialogTitleEdit' => 'Edit Image',
+      'drupalLink_dialogTitleAdd' => 'Add Link',
+      'drupalLink_dialogTitleEdit' => 'Edit Link',
+      'allowedContent' => $this->getDefaultAllowedContentConfig(),
+      'disallowedContent' => $this->getDefaultDisallowedContentConfig(),
+      'toolbar' => $this->getDefaultToolbarConfig(),
+      'contentsCss' => $this->getDefaultContentsCssConfig(),
+      'extraPlugins' => 'drupalimage,drupallink',
+      'language' => 'en',
+      'stylesSet' => FALSE,
+      'drupalExternalPlugins' => array(
+        'drupalimage' => file_url_transform_relative(file_create_url('core/modules/ckeditor/js/plugins/drupalimage/plugin.js')),
+        'drupallink' => file_url_transform_relative(file_create_url('core/modules/ckeditor/js/plugins/drupallink/plugin.js')),
+      ),
+    );
+    $expected_config = $this->castSafeStrings($expected_config);
+    ksort($expected_config);
+    ksort($expected_config['allowedContent']);
+    $this->assertIdentical($expected_config, $this->castSafeStrings($this->ckeditor->getJSSettings($editor)), 'Generated JS settings are correct for default configuration.');
+
+    // Customize the configuration: add button, have two contextually enabled
+    // buttons, and configure a CKEditor plugin setting.
+    $this->enableModules(array('ckeditor_test'));
+    $this->container->get('plugin.manager.editor')->clearCachedDefinitions();
+    $this->ckeditor = $this->container->get('plugin.manager.editor')->createInstance('ckeditor');
+    $this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions();
+    $settings = $editor->getSettings();
+    $settings['toolbar']['rows'][0][0]['items'][] = 'Strike';
+    $settings['toolbar']['rows'][0][0]['items'][] = 'Format';
+    $editor->setSettings($settings);
+    $editor->save();
+    $expected_config['toolbar'][0]['items'][] = 'Strike';
+    $expected_config['toolbar'][0]['items'][] = 'Format';
+    $expected_config['format_tags'] = 'p;h2;h3;h4;h5;h6';
+    $expected_config['extraPlugins'] .= ',llama_contextual,llama_contextual_and_button';
+    $expected_config['drupalExternalPlugins']['llama_contextual'] = file_url_transform_relative(file_create_url('core/modules/ckeditor/tests/modules/js/llama_contextual.js'));
+    $expected_config['drupalExternalPlugins']['llama_contextual_and_button'] = file_url_transform_relative(file_create_url('core/modules/ckeditor/tests/modules/js/llama_contextual_and_button.js'));
+    $expected_config['contentsCss'][] = file_url_transform_relative(file_create_url('core/modules/ckeditor/tests/modules/ckeditor_test.css'));
+    ksort($expected_config);
+    $this->assertIdentical($expected_config, $this->castSafeStrings($this->ckeditor->getJSSettings($editor)), 'Generated JS settings are correct for customized configuration.');
+
+    // Change the allowed HTML tags; the "allowedContent" and "format_tags"
+    // settings for CKEditor should automatically be updated as well.
+    $format = $editor->getFilterFormat();
+    $format->filters('filter_html')->settings['allowed_html'] .= '<pre class> <h1> <blockquote class="*"> <address class="foo bar-* *">';
+    $format->save();
+
+    $expected_config['allowedContent']['pre'] = array('attributes' => 'class', 'styles' => FALSE, 'classes' => TRUE);
+    $expected_config['allowedContent']['h1'] = array('attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE);
+    $expected_config['allowedContent']['blockquote'] = array('attributes' => 'class', 'styles' => FALSE, 'classes' => TRUE);
+    $expected_config['allowedContent']['address'] = array('attributes' => 'class', 'styles' => FALSE, 'classes' => 'foo,bar-*');
+    $expected_config['format_tags'] = 'p;h1;h2;h3;h4;h5;h6;pre';
+    ksort($expected_config['allowedContent']);
+    $this->assertIdentical($expected_config, $this->castSafeStrings($this->ckeditor->getJSSettings($editor)), 'Generated JS settings are correct for customized configuration.');
+
+    // Disable the filter_html filter: allow *all *tags.
+    $format->setFilterConfig('filter_html', array('status' => 0));
+    $format->save();
+
+    $expected_config['allowedContent'] = TRUE;
+    $expected_config['disallowedContent'] = FALSE;
+    $expected_config['format_tags'] = 'p;h1;h2;h3;h4;h5;h6;pre';
+    $this->assertIdentical($expected_config, $this->castSafeStrings($this->ckeditor->getJSSettings($editor)), 'Generated JS settings are correct for customized configuration.');
+
+    // Enable the filter_test_restrict_tags_and_attributes filter.
+    $format->setFilterConfig('filter_test_restrict_tags_and_attributes', array(
+      'status' => 1,
+      'settings' => array(
+        'restrictions' => array(
+          'allowed' => array(
+            'p' => TRUE,
+            'a' => array(
+              'href' => TRUE,
+              'rel' => array('nofollow' => TRUE),
+              'class' => array('external' => TRUE),
+              'target' => array('_blank' => FALSE),
+            ),
+            'span' => array(
+              'class' => array('dodo' => FALSE),
+              'property' => array('dc:*' => TRUE),
+              'rel' => array('foaf:*' => FALSE),
+              'style' => array('underline' => FALSE, 'color' => FALSE, 'font-size' => TRUE),
+            ),
+            '*' => array(
+              'style' => FALSE,
+              'on*' => FALSE,
+              'class' => array('is-a-hipster-llama' => TRUE, 'and-more' => TRUE),
+              'data-*' => TRUE,
+            ),
+            'del' => FALSE,
+          ),
+        ),
+      ),
+    ));
+    $format->save();
+
+    $expected_config['allowedContent'] = array(
+      'p' => array(
+        'attributes' => TRUE,
+        'styles' => FALSE,
+        'classes' => 'is-a-hipster-llama,and-more',
+      ),
+      'a' => array(
+        'attributes' => 'href,rel,class,target',
+        'styles' => FALSE,
+        'classes' => 'external',
+      ),
+      'span' => array(
+        'attributes' => 'class,property,rel,style',
+        'styles' => 'font-size',
+        'classes' => FALSE,
+      ),
+      '*' => array(
+        'attributes' => 'class,data-*',
+        'styles' => FALSE,
+        'classes' => 'is-a-hipster-llama,and-more',
+      ),
+      'del' => array(
+        'attributes' => FALSE,
+        'styles' => FALSE,
+        'classes' => FALSE,
+      ),
+    );
+    $expected_config['disallowedContent'] = array(
+      'span' => array(
+        'styles' => 'underline,color',
+        'classes' => 'dodo',
+      ),
+      '*' => array(
+        'attributes' => 'on*',
+      ),
+    );
+    $expected_config['format_tags'] = 'p';
+    ksort($expected_config);
+    ksort($expected_config['allowedContent']);
+    ksort($expected_config['disallowedContent']);
+    $this->assertIdentical($expected_config, $this->castSafeStrings($this->ckeditor->getJSSettings($editor)), 'Generated JS settings are correct for customized configuration.');
+  }
+
+  /**
+   * Tests CKEditor::buildToolbarJSSetting().
+   */
+  function testBuildToolbarJSSetting() {
+    $editor = entity_load('editor', 'filtered_html');
+
+    // Default toolbar.
+    $expected = $this->getDefaultToolbarConfig();
+    $this->assertIdentical($expected, $this->castSafeStrings($this->ckeditor->buildToolbarJSSetting($editor)), '"toolbar" configuration part of JS settings built correctly for default toolbar.');
+
+    // Customize the configuration.
+    $settings = $editor->getSettings();
+    $settings['toolbar']['rows'][0][0]['items'][] = 'Strike';
+    $editor->setSettings($settings);
+    $editor->save();
+    $expected[0]['items'][] = 'Strike';
+    $this->assertIdentical($expected, $this->castSafeStrings($this->ckeditor->buildToolbarJSSetting($editor)), '"toolbar" configuration part of JS settings built correctly for customized toolbar.');
+
+    // Enable the editor_test module, customize further.
+    $this->enableModules(array('ckeditor_test'));
+    $this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions();
+    // Override the label of a toolbar component.
+    $settings['toolbar']['rows'][0][0]['name'] = 'JunkScience';
+    $settings['toolbar']['rows'][0][0]['items'][] = 'Llama';
+    $editor->setSettings($settings);
+    $editor->save();
+    $expected[0]['name'] = 'JunkScience';
+    $expected[0]['items'][] = 'Llama';
+    $this->assertIdentical($expected, $this->castSafeStrings($this->ckeditor->buildToolbarJSSetting($editor)), '"toolbar" configuration part of JS settings built correctly for customized toolbar with contrib module-provided CKEditor plugin.');
+  }
+
+  /**
+   * Tests CKEditor::buildContentsCssJSSetting().
+   */
+  function testBuildContentsCssJSSetting() {
+    $editor = entity_load('editor', 'filtered_html');
+
+    // Default toolbar.
+    $expected = $this->getDefaultContentsCssConfig();
+    $this->assertIdentical($expected, $this->ckeditor->buildContentsCssJSSetting($editor), '"contentsCss" configuration part of JS settings built correctly for default toolbar.');
+
+    // Enable the editor_test module, which implements hook_ckeditor_css_alter().
+    $this->enableModules(array('ckeditor_test'));
+    $expected[] = file_url_transform_relative(file_create_url('core/modules/ckeditor/tests/modules/ckeditor_test.css'));
+    $this->assertIdentical($expected, $this->ckeditor->buildContentsCssJSSetting($editor), '"contentsCss" configuration part of JS settings built correctly while a hook_ckeditor_css_alter() implementation exists.');
+
+    // Enable the Bartik theme, which specifies a CKEditor stylesheet.
+    \Drupal::service('theme_handler')->install(['bartik']);
+    $this->config('system.theme')->set('default', 'bartik')->save();
+    $expected[] = file_url_transform_relative(file_create_url('core/themes/bartik/css/base/elements.css'));
+    $expected[] = file_url_transform_relative(file_create_url('core/themes/bartik/css/components/captions.css'));
+    $expected[] = file_url_transform_relative(file_create_url('core/themes/bartik/css/components/table.css'));
+    $expected[] = file_url_transform_relative(file_create_url('core/themes/bartik/css/components/text-formatted.css'));
+    $this->assertIdentical($expected, $this->ckeditor->buildContentsCssJSSetting($editor), '"contentsCss" configuration part of JS settings built correctly while a theme providing a CKEditor stylesheet exists.');
+  }
+
+  /**
+   * Tests Internal::getConfig().
+   */
+  function testInternalGetConfig() {
+    $editor = entity_load('editor', 'filtered_html');
+    $internal_plugin = $this->container->get('plugin.manager.ckeditor.plugin')->createInstance('internal');
+
+    // Default toolbar.
+    $expected = $this->getDefaultInternalConfig();
+    $expected['disallowedContent'] = $this->getDefaultDisallowedContentConfig();
+    $expected['allowedContent'] = $this->getDefaultAllowedContentConfig();
+    $this->assertEqual($expected, $internal_plugin->getConfig($editor), '"Internal" plugin configuration built correctly for default toolbar.');
+
+    // Format dropdown/button enabled: new setting should be present.
+    $settings = $editor->getSettings();
+    $settings['toolbar']['rows'][0][0]['items'][] = 'Format';
+    $editor->setSettings($settings);
+    $expected['format_tags'] = 'p;h2;h3;h4;h5;h6';
+    $this->assertEqual($expected, $internal_plugin->getConfig($editor), '"Internal" plugin configuration built correctly for customized toolbar.');
+  }
+
+  /**
+   * Tests StylesCombo::getConfig().
+   */
+  function testStylesComboGetConfig() {
+    $editor = entity_load('editor', 'filtered_html');
+    $stylescombo_plugin = $this->container->get('plugin.manager.ckeditor.plugin')->createInstance('stylescombo');
+
+    // Styles dropdown/button enabled: new setting should be present.
+    $settings = $editor->getSettings();
+    $settings['toolbar']['rows'][0][0]['items'][] = 'Styles';
+    $settings['plugins']['stylescombo']['styles'] = '';
+    $editor->setSettings($settings);
+    $editor->save();
+    $expected['stylesSet'] = array();
+    $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
+
+    // Configure the optional "styles" setting in odd ways that shouldn't affect
+    // the end result.
+    $settings['plugins']['stylescombo']['styles'] = "   \n";
+    $editor->setSettings($settings);
+    $editor->save();
+    $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor));
+    $settings['plugins']['stylescombo']['styles'] = "\r\n  \n  \r  \n ";
+    $editor->setSettings($settings);
+    $editor->save();
+    $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
+
+    // Now configure it properly, the end result should change.
+    $settings['plugins']['stylescombo']['styles'] = "h1.title|Title\np.mAgical.Callout|Callout";
+    $editor->setSettings($settings);
+    $editor->save();
+    $expected['stylesSet'] = array(
+      array('name' => 'Title', 'element' => 'h1', 'attributes' => array('class' => 'title')),
+      array('name' => 'Callout', 'element' => 'p', 'attributes' => array('class' => 'mAgical Callout')),
+    );
+    $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
+
+    // Same configuration, but now interspersed with nonsense. Should yield the
+    // same result.
+    $settings['plugins']['stylescombo']['styles'] = "  h1 .title   |  Title \r \n\r  \np.mAgical  .Callout|Callout\r";
+    $editor->setSettings($settings);
+    $editor->save();
+    $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
+
+    // Slightly different configuration: class names are optional.
+    $settings['plugins']['stylescombo']['styles'] = "      h1 |  Title ";
+    $editor->setSettings($settings);
+    $editor->save();
+    $expected['stylesSet'] = array(array('name' => 'Title', 'element' => 'h1'));
+    $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
+
+    // Invalid syntax should cause stylesSet to be set to FALSE.
+    $settings['plugins']['stylescombo']['styles'] = "h1";
+    $editor->setSettings($settings);
+    $editor->save();
+    $expected['stylesSet'] = FALSE;
+    $this->assertIdentical($expected, $stylescombo_plugin->getConfig($editor), '"StylesCombo" plugin configuration built correctly for customized toolbar.');
+  }
+
+  /**
+   * Tests language list availability in CKEditor.
+   */
+  function testLanguages() {
+    // Get CKEditor supported language codes and spot-check.
+    $this->enableModules(array('language'));
+    $this->installConfig(array('language'));
+    $langcodes = $this->ckeditor->getLangcodes();
+
+    // Language codes transformed with browser mappings.
+    $this->assertTrue($langcodes['pt-pt'] == 'pt', '"pt" properly resolved');
+    $this->assertTrue($langcodes['zh-hans'] == 'zh-cn', '"zh-hans" properly resolved');
+
+    // Language code both in Drupal and CKEditor.
+    $this->assertTrue($langcodes['gl'] == 'gl', '"gl" properly resolved');
+
+    // Language codes only in CKEditor.
+    $this->assertTrue($langcodes['en-au'] == 'en-au', '"en-au" properly resolved');
+    $this->assertTrue($langcodes['sr-latn'] == 'sr-latn', '"sr-latn" properly resolved');
+
+    // No locale module, so even though languages are enabled, CKEditor should
+    // still be in English.
+    $this->assertCKEditorLanguage('en');
+  }
+
+  /**
+   * Tests that CKEditor plugins participate in JS translation.
+   */
+  function testJSTranslation() {
+    $this->enableModules(array('language', 'locale'));
+    $this->installSchema('locale', 'locales_source');
+    $this->installSchema('locale', 'locales_location');
+    $this->installSchema('locale', 'locales_target');
+    $editor = Editor::load('filtered_html');
+    $this->ckeditor->getJSSettings($editor);
+    $localeStorage = $this->container->get('locale.storage');
+    $string = $localeStorage->findString(array('source' => 'Edit Link', 'context' => ''));
+    $this->assertTrue(!empty($string), 'String from JavaScript file saved.');
+
+    // With locale module, CKEditor should not adhere to the language selected.
+    $this->assertCKEditorLanguage();
+  }
+
+  /**
+   * Assert that CKEditor picks the expected language when French is default.
+   *
+   * @param string $langcode
+   *   Language code to assert for. Defaults to French. That is the default
+   *   language set in this assertion.
+   */
+  protected function assertCKEditorLanguage($langcode = 'fr') {
+    // Set French as the site default language.
+    ConfigurableLanguage::createFromLangcode('fr')->save();
+    $this->config('system.site')->set('default_langcode', 'fr')->save();
+
+    // Reset the language manager so new negotiations attempts will fall back on
+    // French. Reinject the language manager CKEditor to use the current one.
+    $this->container->get('language_manager')->reset();
+    $this->ckeditor = $this->container->get('plugin.manager.editor')->createInstance('ckeditor');
+
+    // Test that we now get the expected language.
+    $editor = Editor::load('filtered_html');
+    $settings = $this->ckeditor->getJSSettings($editor);
+    $this->assertEqual($settings['language'], $langcode);
+  }
+
+  protected function getDefaultInternalConfig() {
+    return array(
+      'customConfig' => '',
+      'pasteFromWordPromptCleanup' => TRUE,
+      'resize_dir' => 'vertical',
+      'justifyClasses' => array('text-align-left', 'text-align-center', 'text-align-right', 'text-align-justify'),
+      'entities' => FALSE,
+    );
+  }
+
+  protected function getDefaultAllowedContentConfig() {
+    return [
+      'h2' => ['attributes' => 'id', 'styles' => FALSE, 'classes' => FALSE],
+      'h3' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
+      'h4' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
+      'h5' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
+      'h6' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
+      'p' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
+      'br' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
+      'strong' => ['attributes' => FALSE, 'styles' => FALSE, 'classes' => FALSE],
+      'a' => ['attributes' => 'href,hreflang', 'styles' => FALSE, 'classes' => FALSE],
+      '*' => ['attributes' => 'lang,dir', 'styles' => FALSE, 'classes' => FALSE],
+    ];
+  }
+
+  protected function getDefaultDisallowedContentConfig() {
+    return array(
+      '*' => array('attributes' => 'on*'),
+    );
+  }
+
+  protected function getDefaultToolbarConfig() {
+    return array(
+      array(
+        'name' => 'Formatting',
+        'items' => array('Bold', 'Italic',),
+      ),
+      array(
+        'name' => 'Links',
+        'items' => array('DrupalLink', 'DrupalUnlink',),
+      ),
+      array(
+        'name' => 'Lists',
+        'items' => array('BulletedList', 'NumberedList',),
+      ),
+      array(
+        'name' => 'Media',
+        'items' => array('Blockquote', 'DrupalImage',),
+      ),
+      array(
+        'name' => 'Tools',
+        'items' => array('Source',),
+      ),
+      '/',
+    );
+  }
+
+  protected function getDefaultContentsCssConfig() {
+    return array(
+      file_url_transform_relative(file_create_url('core/modules/ckeditor/css/ckeditor-iframe.css')),
+      file_url_transform_relative(file_create_url('core/modules/system/css/components/align.module.css')),
+    );
+  }
+
+}
diff --git a/core/modules/comment/src/Tests/CommentStringIdEntitiesTest.php b/core/modules/comment/src/Tests/CommentStringIdEntitiesTest.php
deleted file mode 100644
index 0285432..0000000
--- a/core/modules/comment/src/Tests/CommentStringIdEntitiesTest.php
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\comment\Tests\CommentStringIdEntitiesTest.
- */
-
-namespace Drupal\comment\Tests;
-
-use Drupal\comment\Entity\CommentType;
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests that comment fields cannot be added to entities with non-integer IDs.
- *
- * @group comment
- */
-class CommentStringIdEntitiesTest extends KernelTestBase {
-
-  /**
-   * Modules to install.
-   *
-   * @var array
-   */
-  public static $modules = array(
-    'comment',
-    'user',
-    'field',
-    'field_ui',
-    'entity_test',
-    'text',
-  );
-
-  protected function setUp() {
-    parent::setUp();
-    $this->installEntitySchema('comment');
-    $this->installSchema('comment', array('comment_entity_statistics'));
-    // Create the comment body field storage.
-    $this->installConfig(array('field'));
-  }
-
-  /**
-   * Tests that comment fields cannot be added entities with non-integer IDs.
-   */
-  public function testCommentFieldNonStringId() {
-    try {
-      $bundle = CommentType::create(array(
-        'id' => 'foo',
-        'label' => 'foo',
-        'description' => '',
-        'target_entity_type_id' => 'entity_test_string_id',
-      ));
-      $bundle->save();
-      $field_storage = entity_create('field_storage_config', array(
-        'field_name' => 'foo',
-        'entity_type' => 'entity_test_string_id',
-        'settings' => array(
-          'comment_type' => 'entity_test_string_id',
-        ),
-        'type' => 'comment',
-      ));
-      $field_storage->save();
-      $this->fail('Did not throw an exception as expected.');
-    }
-    catch (\UnexpectedValueException $e) {
-      $this->pass('Exception thrown when trying to create comment field on Entity Type with string ID.');
-    }
-  }
-
-}
diff --git a/core/modules/comment/tests/src/Kernel/CommentStringIdEntitiesTest.php b/core/modules/comment/tests/src/Kernel/CommentStringIdEntitiesTest.php
new file mode 100644
index 0000000..0c5776d
--- /dev/null
+++ b/core/modules/comment/tests/src/Kernel/CommentStringIdEntitiesTest.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\comment\Tests\CommentStringIdEntitiesTest.
+ */
+
+namespace Drupal\Tests\comment\Kernel;
+
+use Drupal\comment\Entity\CommentType;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests that comment fields cannot be added to entities with non-integer IDs.
+ *
+ * @group comment
+ */
+class CommentStringIdEntitiesTest extends KernelTestBase {
+
+  /**
+   * Modules to install.
+   *
+   * @var array
+   */
+  public static $modules = array(
+    'comment',
+    'user',
+    'field',
+    'field_ui',
+    'entity_test',
+    'text',
+  );
+
+  protected function setUp() {
+    parent::setUp();
+    $this->installEntitySchema('comment');
+    $this->installSchema('comment', array('comment_entity_statistics'));
+    // Create the comment body field storage.
+    $this->installConfig(array('field'));
+  }
+
+  /**
+   * Tests that comment fields cannot be added entities with non-integer IDs.
+   */
+  public function testCommentFieldNonStringId() {
+    try {
+      $bundle = CommentType::create(array(
+        'id' => 'foo',
+        'label' => 'foo',
+        'description' => '',
+        'target_entity_type_id' => 'entity_test_string_id',
+      ));
+      $bundle->save();
+      $field_storage = entity_create('field_storage_config', array(
+        'field_name' => 'foo',
+        'entity_type' => 'entity_test_string_id',
+        'settings' => array(
+          'comment_type' => 'entity_test_string_id',
+        ),
+        'type' => 'comment',
+      ));
+      $field_storage->save();
+      $this->fail('Did not throw an exception as expected.');
+    }
+    catch (\UnexpectedValueException $e) {
+      $this->pass('Exception thrown when trying to create comment field on Entity Type with string ID.');
+    }
+  }
+
+}
diff --git a/core/modules/config/src/Tests/CacheabilityMetadataConfigOverrideTest.php b/core/modules/config/src/Tests/CacheabilityMetadataConfigOverrideTest.php
deleted file mode 100644
index e559d80..0000000
--- a/core/modules/config/src/Tests/CacheabilityMetadataConfigOverrideTest.php
+++ /dev/null
@@ -1,95 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\config\Tests\CacheabilityMetadataConfigOverrideTest.
- */
-
-namespace Drupal\config\Tests;
-
-use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\config_override_test\Cache\PirateDayCacheContext;
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests if configuration overrides correctly affect cacheability metadata.
- *
- * @group config
- */
-class CacheabilityMetadataConfigOverrideTest extends KernelTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = [
-    'block',
-    'block_content',
-    'config',
-    'config_override_test',
-    'system',
-  ];
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->installEntitySchema('block_content');
-    $this->installConfig(['config_override_test']);
-  }
-
-  /**
-   * Tests if config overrides correctly set cacheability metadata.
-   */
-  public function testConfigOverride() {
-    // It's pirate day today!
-    $GLOBALS['it_is_pirate_day'] = TRUE;
-
-    $config_factory = $this->container->get('config.factory');
-    $config = $config_factory->get('system.theme');
-
-    // Check that we are using the Pirate theme.
-    $theme = $config->get('default');
-    $this->assertEqual('pirate', $theme);
-
-    // Check that the cacheability metadata is correct.
-    $this->assertEqual(['pirate_day'], $config->getCacheContexts());
-    $this->assertEqual(['config:system.theme', 'pirate-day-tag'], $config->getCacheTags());
-    $this->assertEqual(PirateDayCacheContext::PIRATE_DAY_MAX_AGE, $config->getCacheMaxAge());
-  }
-
-  /**
-   * Tests if config overrides set cacheability metadata on config entities.
-   */
-  public function testConfigEntityOverride() {
-    // It's pirate day today!
-    $GLOBALS['it_is_pirate_day'] = TRUE;
-
-    // Load the User login block and check that its cacheability metadata is
-    // overridden correctly. This verifies that the metadata is correctly
-    // applied to config entities.
-    /** @var EntityManagerInterface $entity_manager */
-    $entity_manager = $this->container->get('entity.manager');
-    $block = $entity_manager->getStorage('block')->load('call_to_action');
-
-    // Check that our call to action message is appealing to filibusters.
-    $this->assertEqual($block->label(), 'Draw yer cutlasses!');
-
-    // Check that the cacheability metadata is correct.
-    $this->assertEqual(['pirate_day'], $block->getCacheContexts());
-    $this->assertEqual(['config:block.block.call_to_action', 'pirate-day-tag'], $block->getCacheTags());
-    $this->assertEqual(PirateDayCacheContext::PIRATE_DAY_MAX_AGE, $block->getCacheMaxAge());
-
-    // Check that duplicating a config entity does not have the original config
-    // entity's cache tag.
-    $this->assertEqual(['config:block.block.', 'pirate-day-tag'], $block->createDuplicate()->getCacheTags());
-
-    // Check that renaming a config entity does not have the original config
-    // entity's cache tag.
-    $block->set('id', 'call_to_looting')->save();
-    $this->assertEqual(['pirate_day'], $block->getCacheContexts());
-    $this->assertEqual(['config:block.block.call_to_looting', 'pirate-day-tag'], $block->getCacheTags());
-    $this->assertEqual(PirateDayCacheContext::PIRATE_DAY_MAX_AGE, $block->getCacheMaxAge());
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigEntityNormalizeTest.php b/core/modules/config/src/Tests/ConfigEntityNormalizeTest.php
deleted file mode 100644
index 7e0acef..0000000
--- a/core/modules/config/src/Tests/ConfigEntityNormalizeTest.php
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\config\Tests\ConfigEntityNormalizeTest.
- */
-
-namespace Drupal\config\Tests;
-
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests the listing of configuration entities.
- *
- * @group config
- */
-class ConfigEntityNormalizeTest extends KernelTestBase {
-
-  /**
-   * Modules to install.
-   *
-   * @var array
-   */
-  public static $modules = array('config_test');
-
-  protected function setUp() {
-    parent::setUp();
-    $this->installConfig(static::$modules);
-  }
-
-  public function testNormalize() {
-    $config_entity = entity_create('config_test', array('id' => 'system', 'label' => 'foobar', 'weight' => 1));
-    $config_entity->save();
-
-    // Modify stored config entity, this is comparable with a schema change.
-    $config = $this->config('config_test.dynamic.system');
-    $data = array(
-      'label' => 'foobar',
-      'additional_key' => TRUE
-    ) + $config->getRawData();
-    $config->setData($data)->save();
-    $this->assertNotIdentical($config_entity->toArray(), $config->getRawData(), 'Stored config entity is not is equivalent to config schema.');
-
-    $config_entity = entity_load('config_test', 'system', TRUE);
-    $config_entity->save();
-
-    $config = $this->config('config_test.dynamic.system');
-    $this->assertIdentical($config_entity->toArray(), $config->getRawData(), 'Stored config entity is equivalent to config schema.');
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigEntityStaticCacheTest.php b/core/modules/config/src/Tests/ConfigEntityStaticCacheTest.php
deleted file mode 100644
index 6b30269..0000000
--- a/core/modules/config/src/Tests/ConfigEntityStaticCacheTest.php
+++ /dev/null
@@ -1,110 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\config\Tests\ConfigEntityStaticCacheTest.
- */
-
-namespace Drupal\config\Tests;
-
-use Drupal\config_entity_static_cache_test\ConfigOverrider;
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests the entity static cache when used by config entities.
- *
- * @group config
- */
-class ConfigEntityStaticCacheTest extends KernelTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('config_test', 'config_entity_static_cache_test');
-
-  /**
-   * The type ID of the entity under test.
-   *
-   * @var string
-   */
-  protected $entityTypeId;
-
-  /**
-   * The entity ID of the entity under test.
-   *
-   * @var string
-   */
-  protected $entityId;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->entityTypeId = 'config_test';
-    $this->entityId = 'test_1';
-    entity_create($this->entityTypeId, array('id' => $this->entityId, 'label' => 'Original label'))->save();
-  }
-
-  /**
-   * Tests that the static cache is working.
-   */
-  public function testCacheHit() {
-    $entity_1 = entity_load($this->entityTypeId, $this->entityId);
-    $entity_2 = entity_load($this->entityTypeId, $this->entityId);
-    // config_entity_static_cache_test_config_test_load() sets _loadStamp to a
-    // random string. If they match, it means $entity_2 was retrieved from the
-    // static cache rather than going through a separate load sequence.
-    $this->assertIdentical($entity_1->_loadStamp, $entity_2->_loadStamp);
-  }
-
-  /**
-   * Tests that the static cache is reset on entity save and delete.
-   */
-  public function testReset() {
-    $entity = entity_load($this->entityTypeId, $this->entityId);
-
-    // Ensure loading after a save retrieves the updated entity rather than an
-    // obsolete cached one.
-    $entity->label = 'New label';
-    $entity->save();
-    $entity = entity_load($this->entityTypeId, $this->entityId);
-    $this->assertIdentical($entity->label, 'New label');
-
-    // Ensure loading after a delete retrieves NULL rather than an obsolete
-    // cached one.
-    $entity->delete();
-    $this->assertNull(entity_load($this->entityTypeId, $this->entityId));
-  }
-
-  /**
-   * Tests that the static cache is sensitive to config overrides.
-   */
-  public function testConfigOverride() {
-    /** @var \Drupal\Core\Config\Entity\ConfigEntityStorage $storage */
-    $storage = \Drupal::entityManager()->getStorage($this->entityTypeId);
-    // Prime the cache prior to adding a config override.
-    $storage->load($this->entityId);
-
-    // Add the config override, and ensure that what is loaded is correct
-    // despite the prior cache priming.
-    \Drupal::configFactory()->addOverride(new ConfigOverrider());
-    $entity_override = $storage->load($this->entityId);
-    $this->assertIdentical($entity_override->label, 'Overridden label');
-
-    // Load override free to ensure that loading the config entity again does
-    // not return the overridden value.
-    $entity_no_override = $storage->loadOverrideFree($this->entityId);
-    $this->assertNotIdentical($entity_no_override->label, 'Overridden label');
-    $this->assertNotIdentical($entity_override->_loadStamp, $entity_no_override->_loadStamp);
-
-    // Reload the entity and ensure the cache is used.
-    $this->assertIdentical($storage->loadOverrideFree($this->entityId)->_loadStamp, $entity_no_override->_loadStamp);
-
-    // Enable overrides and reload the entity and ensure the cache is used.
-    $this->assertIdentical($storage->load($this->entityId)->_loadStamp, $entity_override->_loadStamp);
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigEntityUnitTest.php b/core/modules/config/src/Tests/ConfigEntityUnitTest.php
deleted file mode 100644
index dd6a586..0000000
--- a/core/modules/config/src/Tests/ConfigEntityUnitTest.php
+++ /dev/null
@@ -1,116 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\config\Tests\ConfigEntityUnitTest.
- */
-
-namespace Drupal\config\Tests;
-
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Unit tests for configuration entity base methods.
- *
- * @group config
- */
-class ConfigEntityUnitTest extends KernelTestBase {
-
-  /**
-   * Exempt from strict schema checking.
-   *
-   * @see \Drupal\Core\Config\Testing\ConfigSchemaChecker
-   *
-   * @var bool
-   */
-  protected $strictConfigSchema = FALSE;
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('config_test');
-
-  /**
-   * The config_test entity storage.
-   *
-   * @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
-   */
-  protected $storage;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->storage = $this->container->get('entity.manager')->getStorage('config_test');
-  }
-
-  /**
-   * Tests storage methods.
-   */
-  public function testStorageMethods() {
-    $entity_type = \Drupal::entityManager()->getDefinition('config_test');
-
-    // Test the static extractID() method.
-    $expected_id = 'test_id';
-    $config_name = $entity_type->getConfigPrefix() . '.' . $expected_id;
-    $storage = $this->storage;
-    $this->assertIdentical($storage::getIDFromConfigName($config_name, $entity_type->getConfigPrefix()), $expected_id);
-
-    // Create three entities, two with the same style.
-    $style = $this->randomMachineName(8);
-    for ($i = 0; $i < 2; $i++) {
-      $entity = $this->storage->create(array(
-        'id' => $this->randomMachineName(),
-        'label' => $this->randomString(),
-        'style' => $style,
-      ));
-      $entity->save();
-    }
-    $entity = $this->storage->create(array(
-      'id' => $this->randomMachineName(),
-      'label' => $this->randomString(),
-      // Use a different length for the entity to ensure uniqueness.
-      'style' => $this->randomMachineName(9),
-    ));
-    $entity->save();
-
-    // Ensure that the configuration entity can be loaded by UUID.
-    $entity_loaded_by_uuid = \Drupal::entityManager()->loadEntityByUuid($entity_type->id(), $entity->uuid());
-    if (!$entity_loaded_by_uuid) {
-      $this->fail(sprintf("Failed to load '%s' entity ID '%s' by UUID '%s'.", $entity_type->id(), $entity->id(), $entity->uuid()));
-    }
-    // Compare UUIDs as the objects are not identical since
-    // $entity->enforceIsNew is FALSE and $entity_loaded_by_uuid->enforceIsNew
-    // is NULL.
-    $this->assertIdentical($entity->uuid(), $entity_loaded_by_uuid->uuid());
-
-    $entities = $this->storage->loadByProperties();
-    $this->assertEqual(count($entities), 3, 'Three entities are loaded when no properties are specified.');
-
-    $entities = $this->storage->loadByProperties(array('style' => $style));
-    $this->assertEqual(count($entities), 2, 'Two entities are loaded when the style property is specified.');
-
-    // Assert that both returned entities have a matching style property.
-    foreach ($entities as $entity) {
-      $this->assertIdentical($entity->get('style'), $style, 'The loaded entity has the correct style value specified.');
-    }
-
-    // Test that schema type enforcement can be overridden by trusting the data.
-    $entity = $this->storage->create(array(
-      'id' => $this->randomMachineName(),
-      'label' => $this->randomString(),
-      'style' => 999
-    ));
-    $entity->save();
-    $this->assertIdentical('999', $entity->style);
-    $entity->style = 999;
-    $entity->trustData()->save();
-    $this->assertIdentical(999, $entity->style);
-    $entity->save();
-    $this->assertIdentical('999', $entity->style);
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigImportRecreateTest.php b/core/modules/config/src/Tests/ConfigImportRecreateTest.php
deleted file mode 100644
index 34aa441..0000000
--- a/core/modules/config/src/Tests/ConfigImportRecreateTest.php
+++ /dev/null
@@ -1,110 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\config\Tests\ConfigImportRecreateTest.
- */
-
-namespace Drupal\config\Tests;
-
-use Drupal\Component\Utility\Unicode;
-use Drupal\Core\Config\ConfigImporter;
-use Drupal\Core\Config\StorageComparer;
-use Drupal\node\Entity\NodeType;
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests importing recreated configuration entities.
- *
- * @group config
- */
-class ConfigImportRecreateTest extends KernelTestBase {
-
-  /**
-   * Config Importer object used for testing.
-   *
-   * @var \Drupal\Core\Config\ConfigImporter
-   */
-  protected $configImporter;
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['system', 'field', 'text', 'user', 'node'];
-
-  protected function setUp() {
-    parent::setUp();
-
-    $this->installEntitySchema('node');
-    $this->installConfig(array('field', 'node'));
-
-    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
-
-    // Set up the ConfigImporter object for testing.
-    $storage_comparer = new StorageComparer(
-      $this->container->get('config.storage.sync'),
-      $this->container->get('config.storage'),
-      $this->container->get('config.manager')
-    );
-    $this->configImporter = new ConfigImporter(
-      $storage_comparer->createChangelist(),
-      $this->container->get('event_dispatcher'),
-      $this->container->get('config.manager'),
-      $this->container->get('lock'),
-      $this->container->get('config.typed'),
-      $this->container->get('module_handler'),
-      $this->container->get('module_installer'),
-      $this->container->get('theme_handler'),
-      $this->container->get('string_translation')
-    );
-  }
-
-  public function testRecreateEntity() {
-    $type_name = Unicode::strtolower($this->randomMachineName(16));
-    $content_type = entity_create('node_type', array(
-      'type' => $type_name,
-      'name' => 'Node type one',
-    ));
-    $content_type->save();
-    node_add_body_field($content_type);
-    /** @var \Drupal\Core\Config\StorageInterface $active */
-    $active = $this->container->get('config.storage');
-    /** @var \Drupal\Core\Config\StorageInterface $sync */
-    $sync = $this->container->get('config.storage.sync');
-
-    $config_name = $content_type->getEntityType()->getConfigPrefix() . '.' . $content_type->id();
-    $this->copyConfig($active, $sync);
-
-    // Delete the content type. This will also delete a field storage, a field,
-    // an entity view display and an entity form display.
-    $content_type->delete();
-    $this->assertFalse($active->exists($config_name), 'Content type\'s old name does not exist active store.');
-    // Recreate with the same type - this will have a different UUID.
-    $content_type = entity_create('node_type', array(
-      'type' => $type_name,
-      'name' => 'Node type two',
-    ));
-    $content_type->save();
-    node_add_body_field($content_type);
-
-    $this->configImporter->reset();
-    // A node type, a field, an entity view display and an entity form display
-    // will be recreated.
-    $creates = $this->configImporter->getUnprocessedConfiguration('create');
-    $deletes = $this->configImporter->getUnprocessedConfiguration('delete');
-    $this->assertEqual(5, count($creates), 'There are 5 configuration items to create.');
-    $this->assertEqual(5, count($deletes), 'There are 5 configuration items to delete.');
-    $this->assertEqual(0, count($this->configImporter->getUnprocessedConfiguration('update')), 'There are no configuration items to update.');
-    $this->assertIdentical($creates, array_reverse($deletes), 'Deletes and creates contain the same configuration names in opposite orders due to dependencies.');
-
-    $this->configImporter->import();
-
-    // Verify that there is nothing more to import.
-    $this->assertFalse($this->configImporter->reset()->hasUnprocessedConfigurationChanges());
-    $content_type = NodeType::load($type_name);
-    $this->assertEqual('Node type one', $content_type->label());
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigImportRenameValidationTest.php b/core/modules/config/src/Tests/ConfigImportRenameValidationTest.php
deleted file mode 100644
index c461f30..0000000
--- a/core/modules/config/src/Tests/ConfigImportRenameValidationTest.php
+++ /dev/null
@@ -1,162 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\config\Tests\ConfigImportRenameValidationTest.
- */
-
-namespace Drupal\config\Tests;
-
-use Drupal\Component\Utility\SafeMarkup;
-use Drupal\Component\Utility\Unicode;
-use Drupal\Component\Uuid\Php;
-use Drupal\Core\Config\ConfigImporter;
-use Drupal\Core\Config\ConfigImporterException;
-use Drupal\Core\Config\StorageComparer;
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests validating renamed configuration in a configuration import.
- *
- * @group config
- */
-class ConfigImportRenameValidationTest extends KernelTestBase {
-
-  /**
-   * Config Importer object used for testing.
-   *
-   * @var \Drupal\Core\Config\ConfigImporter
-   */
-  protected $configImporter;
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['system', 'user', 'node', 'field', 'text', 'config_test'];
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    $this->installEntitySchema('user');
-    $this->installEntitySchema('node');
-    $this->installConfig(array('field'));
-
-    // Set up the ConfigImporter object for testing.
-    $storage_comparer = new StorageComparer(
-      $this->container->get('config.storage.sync'),
-      $this->container->get('config.storage'),
-      $this->container->get('config.manager')
-    );
-    $this->configImporter = new ConfigImporter(
-      $storage_comparer->createChangelist(),
-      $this->container->get('event_dispatcher'),
-      $this->container->get('config.manager'),
-      $this->container->get('lock.persistent'),
-      $this->container->get('config.typed'),
-      $this->container->get('module_handler'),
-      $this->container->get('module_installer'),
-      $this->container->get('theme_handler'),
-      $this->container->get('string_translation')
-    );
-  }
-
-  /**
-   * Tests configuration renaming validation.
-   */
-  public function testRenameValidation() {
-    // Create a test entity.
-    $test_entity_id = $this->randomMachineName();
-    $test_entity = entity_create('config_test', array(
-      'id' => $test_entity_id,
-      'label' => $this->randomMachineName(),
-    ));
-    $test_entity->save();
-    $uuid = $test_entity->uuid();
-
-    // Stage the test entity and then delete it from the active storage.
-    $active = $this->container->get('config.storage');
-    $sync = $this->container->get('config.storage.sync');
-    $this->copyConfig($active, $sync);
-    $test_entity->delete();
-
-    // Create a content type with a matching UUID in the active storage.
-    $content_type = entity_create('node_type', array(
-      'type' => Unicode::strtolower($this->randomMachineName(16)),
-      'name' => $this->randomMachineName(),
-      'uuid' => $uuid,
-    ));
-    $content_type->save();
-
-    // Confirm that the staged configuration is detected as a rename since the
-    // UUIDs match.
-    $this->configImporter->reset();
-    $expected = array(
-      'node.type.' . $content_type->id() . '::config_test.dynamic.' . $test_entity_id,
-    );
-    $renames = $this->configImporter->getUnprocessedConfiguration('rename');
-    $this->assertIdentical($expected, $renames);
-
-    // Try to import the configuration. We expect an exception to be thrown
-    // because the staged entity is of a different type.
-    try {
-      $this->configImporter->import();
-      $this->fail('Expected ConfigImporterException thrown when a renamed configuration entity does not match the existing entity type.');
-    }
-    catch (ConfigImporterException $e) {
-      $this->pass('Expected ConfigImporterException thrown when a renamed configuration entity does not match the existing entity type.');
-      $expected = array(
-        SafeMarkup::format('Entity type mismatch on rename. @old_type not equal to @new_type for existing configuration @old_name and staged configuration @new_name.', array('@old_type' => 'node_type', '@new_type' => 'config_test', '@old_name' => 'node.type.' . $content_type->id(), '@new_name' => 'config_test.dynamic.' . $test_entity_id))
-      );
-      $this->assertEqual($expected, $this->configImporter->getErrors());
-    }
-  }
-
-  /**
-   * Tests configuration renaming validation for simple configuration.
-   */
-  public function testRenameSimpleConfigValidation() {
-    $uuid = new Php();
-    // Create a simple configuration with a UUID.
-    $config = $this->config('config_test.new');
-    $uuid_value = $uuid->generate();
-    $config->set('uuid', $uuid_value)->save();
-
-    $active = $this->container->get('config.storage');
-    $sync = $this->container->get('config.storage.sync');
-    $this->copyConfig($active, $sync);
-    $config->delete();
-
-    // Create another simple configuration with the same UUID.
-    $config = $this->config('config_test.old');
-    $config->set('uuid', $uuid_value)->save();
-
-    // Confirm that the staged configuration is detected as a rename since the
-    // UUIDs match.
-    $this->configImporter->reset();
-    $expected = array(
-      'config_test.old::config_test.new'
-    );
-    $renames = $this->configImporter->getUnprocessedConfiguration('rename');
-    $this->assertIdentical($expected, $renames);
-
-    // Try to import the configuration. We expect an exception to be thrown
-    // because the rename is for simple configuration.
-    try {
-      $this->configImporter->import();
-      $this->fail('Expected ConfigImporterException thrown when simple configuration is renamed.');
-    }
-    catch (ConfigImporterException $e) {
-      $this->pass('Expected ConfigImporterException thrown when simple configuration is renamed.');
-      $expected = array(
-        SafeMarkup::format('Rename operation for simple configuration. Existing configuration @old_name and staged configuration @new_name.', array('@old_name' => 'config_test.old', '@new_name' => 'config_test.new'))
-      );
-      $this->assertEqual($expected, $this->configImporter->getErrors());
-    }
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigImporterMissingContentTest.php b/core/modules/config/src/Tests/ConfigImporterMissingContentTest.php
deleted file mode 100644
index cb5522d..0000000
--- a/core/modules/config/src/Tests/ConfigImporterMissingContentTest.php
+++ /dev/null
@@ -1,105 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\config\Tests\ConfigImporterMissingContentTest.
- */
-
-namespace Drupal\config\Tests;
-
-use Drupal\Core\Config\ConfigImporter;
-use Drupal\Core\Config\StorageComparer;
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests importing configuration which has missing content dependencies.
- *
- * @group config
- */
-class ConfigImporterMissingContentTest extends KernelTestBase {
-
-  /**
-   * Config Importer object used for testing.
-   *
-   * @var \Drupal\Core\Config\ConfigImporter
-   */
-  protected $configImporter;
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('system', 'user', 'entity_test', 'config_test', 'config_import_test');
-
-  protected function setUp() {
-    parent::setUp();
-    $this->installSchema('system', 'sequences');
-    $this->installEntitySchema('entity_test');
-    $this->installEntitySchema('user');
-    $this->installConfig(array('config_test'));
-    // Installing config_test's default configuration pollutes the global
-    // variable being used for recording hook invocations by this test already,
-    // so it has to be cleared out manually.
-    unset($GLOBALS['hook_config_test']);
-
-    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
-
-    // Set up the ConfigImporter object for testing.
-    $storage_comparer = new StorageComparer(
-      $this->container->get('config.storage.sync'),
-      $this->container->get('config.storage'),
-      $this->container->get('config.manager')
-    );
-    $this->configImporter = new ConfigImporter(
-      $storage_comparer->createChangelist(),
-      $this->container->get('event_dispatcher'),
-      $this->container->get('config.manager'),
-      $this->container->get('lock'),
-      $this->container->get('config.typed'),
-      $this->container->get('module_handler'),
-      $this->container->get('module_installer'),
-      $this->container->get('theme_handler'),
-      $this->container->get('string_translation')
-    );
-  }
-
-  /**
-   * Tests the missing content event is fired.
-   *
-   * @see \Drupal\Core\Config\ConfigImporter::processMissingContent()
-   * @see \Drupal\config_import_test\EventSubscriber
-   */
-  function testMissingContent() {
-    \Drupal::state()->set('config_import_test.config_import_missing_content', TRUE);
-
-    // Update a configuration entity in the sync directory to have a dependency
-    // on two content entities that do not exist.
-    $storage = $this->container->get('config.storage');
-    $sync = $this->container->get('config.storage.sync');
-    $entity_one = entity_create('entity_test', array('name' => 'one'));
-    $entity_two = entity_create('entity_test', array('name' => 'two'));
-    $entity_three = entity_create('entity_test', array('name' => 'three'));
-    $dynamic_name = 'config_test.dynamic.dotted.default';
-    $original_dynamic_data = $storage->read($dynamic_name);
-    // Entity one will be resolved by
-    // \Drupal\config_import_test\EventSubscriber::onConfigImporterMissingContentOne().
-    $original_dynamic_data['dependencies']['content'][] = $entity_one->getConfigDependencyName();
-    // Entity two will be resolved by
-    // \Drupal\config_import_test\EventSubscriber::onConfigImporterMissingContentTwo().
-    $original_dynamic_data['dependencies']['content'][] = $entity_two->getConfigDependencyName();
-    // Entity three will be resolved by
-    // \Drupal\Core\Config\Importer\FinalMissingContentSubscriber.
-    $original_dynamic_data['dependencies']['content'][] = $entity_three->getConfigDependencyName();
-    $sync->write($dynamic_name, $original_dynamic_data);
-
-    // Import.
-    $this->configImporter->reset()->import();
-    $this->assertEqual([], $this->configImporter->getErrors(), 'There were no errors during the import.');
-    $this->assertEqual($entity_one->uuid(), \Drupal::state()->get('config_import_test.config_import_missing_content_one'), 'The missing content event is fired during configuration import.');
-    $this->assertEqual($entity_two->uuid(), \Drupal::state()->get('config_import_test.config_import_missing_content_two'), 'The missing content event is fired during configuration import.');
-    $original_dynamic_data = $storage->read($dynamic_name);
-    $this->assertEqual([$entity_one->getConfigDependencyName(), $entity_two->getConfigDependencyName(), $entity_three->getConfigDependencyName()], $original_dynamic_data['dependencies']['content'], 'The imported configuration entity has the missing content entity dependency.');
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigImporterTest.php b/core/modules/config/src/Tests/ConfigImporterTest.php
deleted file mode 100644
index 3fca8c0..0000000
--- a/core/modules/config/src/Tests/ConfigImporterTest.php
+++ /dev/null
@@ -1,693 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\config\Tests\ConfigImporterTest.
- */
-
-namespace Drupal\config\Tests;
-
-use Drupal\Component\Utility\Html;
-use Drupal\Component\Utility\SafeMarkup;
-use Drupal\Core\Config\ConfigImporter;
-use Drupal\Core\Config\ConfigImporterException;
-use Drupal\Core\Config\StorageComparer;
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests importing configuration from files into active configuration.
- *
- * @group config
- */
-class ConfigImporterTest extends KernelTestBase {
-
-  /**
-   * Config Importer object used for testing.
-   *
-   * @var \Drupal\Core\Config\ConfigImporter
-   */
-  protected $configImporter;
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('config_test', 'system', 'config_import_test');
-
-  protected function setUp() {
-    parent::setUp();
-
-    $this->installConfig(array('config_test'));
-    // Installing config_test's default configuration pollutes the global
-    // variable being used for recording hook invocations by this test already,
-    // so it has to be cleared out manually.
-    unset($GLOBALS['hook_config_test']);
-
-    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
-
-    // Set up the ConfigImporter object for testing.
-    $storage_comparer = new StorageComparer(
-      $this->container->get('config.storage.sync'),
-      $this->container->get('config.storage'),
-      $this->container->get('config.manager')
-    );
-    $this->configImporter = new ConfigImporter(
-      $storage_comparer->createChangelist(),
-      $this->container->get('event_dispatcher'),
-      $this->container->get('config.manager'),
-      $this->container->get('lock'),
-      $this->container->get('config.typed'),
-      $this->container->get('module_handler'),
-      $this->container->get('module_installer'),
-      $this->container->get('theme_handler'),
-      $this->container->get('string_translation')
-    );
-  }
-
-  /**
-   * Tests omission of module APIs for bare configuration operations.
-   */
-  function testNoImport() {
-    $dynamic_name = 'config_test.dynamic.dotted.default';
-
-    // Verify the default configuration values exist.
-    $config = $this->config($dynamic_name);
-    $this->assertIdentical($config->get('id'), 'dotted.default');
-
-    // Verify that a bare $this->config() does not involve module APIs.
-    $this->assertFalse(isset($GLOBALS['hook_config_test']));
-  }
-
-  /**
-   * Tests that trying to import from an empty sync configuration directory
-   * fails.
-   */
-  function testEmptyImportFails() {
-    try {
-      $this->container->get('config.storage.sync')->deleteAll();
-      $this->configImporter->reset()->import();
-      $this->fail('ConfigImporterException thrown, successfully stopping an empty import.');
-    }
-    catch (ConfigImporterException $e) {
-      $this->pass('ConfigImporterException thrown, successfully stopping an empty import.');
-    }
-  }
-
-  /**
-   * Tests verification of site UUID before importing configuration.
-   */
-  function testSiteUuidValidate() {
-    $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);
-    try {
-      $this->configImporter->reset()->import();
-      $this->fail('ConfigImporterException not thrown, invalid import was not stopped due to mis-matching site UUID.');
-    }
-    catch (ConfigImporterException $e) {
-      $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.');
-      $error_log = $this->configImporter->getErrors();
-      $expected = array('Site UUID in source storage does not match the target storage.');
-      $this->assertEqual($expected, $error_log);
-    }
-  }
-
-  /**
-   * Tests deletion of configuration during import.
-   */
-  function testDeleted() {
-    $dynamic_name = 'config_test.dynamic.dotted.default';
-    $storage = $this->container->get('config.storage');
-    $sync = $this->container->get('config.storage.sync');
-
-    // Verify the default configuration values exist.
-    $config = $this->config($dynamic_name);
-    $this->assertIdentical($config->get('id'), 'dotted.default');
-
-    // Delete the file from the sync directory.
-    $sync->delete($dynamic_name);
-
-    // Import.
-    $this->configImporter->reset()->import();
-
-    // Verify the file has been removed.
-    $this->assertIdentical($storage->read($dynamic_name), FALSE);
-
-    $config = $this->config($dynamic_name);
-    $this->assertIdentical($config->get('id'), NULL);
-
-    // Verify that appropriate module API hooks have been invoked.
-    $this->assertTrue(isset($GLOBALS['hook_config_test']['load']));
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['presave']));
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['insert']));
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['update']));
-    $this->assertTrue(isset($GLOBALS['hook_config_test']['predelete']));
-    $this->assertTrue(isset($GLOBALS['hook_config_test']['delete']));
-
-    $this->assertFalse($this->configImporter->hasUnprocessedConfigurationChanges());
-    $logs = $this->configImporter->getErrors();
-    $this->assertEqual(count($logs), 0);
-  }
-
-  /**
-   * Tests creation of configuration during import.
-   */
-  function testNew() {
-    $dynamic_name = 'config_test.dynamic.new';
-    $storage = $this->container->get('config.storage');
-    $sync = $this->container->get('config.storage.sync');
-
-    // Verify the configuration to create does not exist yet.
-    $this->assertIdentical($storage->exists($dynamic_name), FALSE, $dynamic_name . ' not found.');
-
-    // Create new config entity.
-    $original_dynamic_data = array(
-      'uuid' => '30df59bd-7b03-4cf7-bb35-d42fc49f0651',
-      'langcode' => \Drupal::languageManager()->getDefaultLanguage()->getId(),
-      'status' => TRUE,
-      'dependencies' => array(),
-      '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.');
-
-    // Import.
-    $this->configImporter->reset()->import();
-
-    // Verify the values appeared.
-    $config = $this->config($dynamic_name);
-    $this->assertIdentical($config->get('label'), $original_dynamic_data['label']);
-
-    // Verify that appropriate module API hooks have been invoked.
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['load']));
-    $this->assertTrue(isset($GLOBALS['hook_config_test']['presave']));
-    $this->assertTrue(isset($GLOBALS['hook_config_test']['insert']));
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['update']));
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['predelete']));
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['delete']));
-
-    // Verify that hook_config_import_steps_alter() can add steps to
-    // configuration synchronization.
-    $this->assertTrue(isset($GLOBALS['hook_config_test']['config_import_steps_alter']));
-
-    // Verify that there is nothing more to import.
-    $this->assertFalse($this->configImporter->hasUnprocessedConfigurationChanges());
-    $logs = $this->configImporter->getErrors();
-    $this->assertEqual(count($logs), 0);
-  }
-
-  /**
-   * Tests that secondary writes are overwritten.
-   */
-  function testSecondaryWritePrimaryFirst() {
-    $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 = array(
-      'id' => 'primary',
-      'label' => 'Primary',
-      'weight' => 0,
-      'uuid' => $uuid->generate(),
-    );
-    $sync->write($name_primary, $values_primary);
-    $values_secondary = array(
-      'id' => 'secondary',
-      'label' => 'Secondary Sync',
-      'weight' => 0,
-      'uuid' => $uuid->generate(),
-      // Add a dependency on primary, to ensure that is synced first.
-      'dependencies' => array(
-        'config' => array($name_primary),
-      )
-    );
-    $sync->write($name_secondary, $values_secondary);
-
-    // Import.
-    $this->configImporter->reset()->import();
-
-    $entity_storage = \Drupal::entityManager()->getStorage('config_test');
-    $primary = $entity_storage->load('primary');
-    $this->assertEqual($primary->id(), 'primary');
-    $this->assertEqual($primary->uuid(), $values_primary['uuid']);
-    $this->assertEqual($primary->label(), $values_primary['label']);
-    $secondary = $entity_storage->load('secondary');
-    $this->assertEqual($secondary->id(), 'secondary');
-    $this->assertEqual($secondary->uuid(), $values_secondary['uuid']);
-    $this->assertEqual($secondary->label(), $values_secondary['label']);
-
-    $logs = $this->configImporter->getErrors();
-    $this->assertEqual(count($logs), 1);
-    $this->assertEqual($logs[0], SafeMarkup::format('Deleted and replaced configuration entity "@name"', array('@name' => $name_secondary)));
-  }
-
-  /**
-   * Tests that secondary writes are overwritten.
-   */
-  function testSecondaryWriteSecondaryFirst() {
-    $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 = array(
-      'id' => 'primary',
-      'label' => 'Primary',
-      'weight' => 0,
-      'uuid' => $uuid->generate(),
-      // Add a dependency on secondary, so that is synced first.
-      'dependencies' => array(
-        'config' => array($name_secondary),
-      )
-    );
-    $sync->write($name_primary, $values_primary);
-    $values_secondary = array(
-      'id' => 'secondary',
-      'label' => 'Secondary Sync',
-      'weight' => 0,
-      'uuid' => $uuid->generate(),
-    );
-    $sync->write($name_secondary, $values_secondary);
-
-    // Import.
-    $this->configImporter->reset()->import();
-
-    $entity_storage = \Drupal::entityManager()->getStorage('config_test');
-    $primary = $entity_storage->load('primary');
-    $this->assertEqual($primary->id(), 'primary');
-    $this->assertEqual($primary->uuid(), $values_primary['uuid']);
-    $this->assertEqual($primary->label(), $values_primary['label']);
-    $secondary = $entity_storage->load('secondary');
-    $this->assertEqual($secondary->id(), 'secondary');
-    $this->assertEqual($secondary->uuid(), $values_secondary['uuid']);
-    $this->assertEqual($secondary->label(), $values_secondary['label']);
-
-    $logs = $this->configImporter->getErrors();
-    $this->assertEqual(count($logs), 1);
-    $this->assertEqual($logs[0], Html::escape("Unexpected error during import with operation create for $name_primary: 'config_test' entity with ID 'secondary' already exists."));
-  }
-
-  /**
-   * Tests that secondary updates for deleted files work as expected.
-   */
-  function testSecondaryUpdateDeletedDeleterFirst() {
-    $name_deleter = 'config_test.dynamic.deleter';
-    $name_deletee = 'config_test.dynamic.deletee';
-    $name_other = 'config_test.dynamic.other';
-    $storage = $this->container->get('config.storage');
-    $sync = $this->container->get('config.storage.sync');
-    $uuid = $this->container->get('uuid');
-
-    $values_deleter = array(
-      'id' => 'deleter',
-      'label' => 'Deleter',
-      'weight' => 0,
-      'uuid' => $uuid->generate(),
-    );
-    $storage->write($name_deleter, $values_deleter);
-    $values_deleter['label'] = 'Updated Deleter';
-    $sync->write($name_deleter, $values_deleter);
-    $values_deletee = array(
-      'id' => 'deletee',
-      'label' => 'Deletee',
-      'weight' => 0,
-      'uuid' => $uuid->generate(),
-      // Add a dependency on deleter, to make sure that is synced first.
-      'dependencies' => array(
-        'config' => array($name_deleter),
-      )
-    );
-    $storage->write($name_deletee, $values_deletee);
-    $values_deletee['label'] = 'Updated Deletee';
-    $sync->write($name_deletee, $values_deletee);
-
-    // Ensure that import will continue after the error.
-    $values_other = array(
-      'id' => 'other',
-      'label' => 'Other',
-      'weight' => 0,
-      'uuid' => $uuid->generate(),
-      // Add a dependency on deleter, to make sure that is synced first. This
-      // will also be synced after the deletee due to alphabetical ordering.
-      'dependencies' => array(
-        'config' => array($name_deleter),
-      )
-    );
-    $storage->write($name_other, $values_other);
-    $values_other['label'] = 'Updated other';
-    $sync->write($name_other, $values_other);
-
-    // Check update changelist order.
-    $updates = $this->configImporter->reset()->getStorageComparer()->getChangelist('update');
-    $expected = array(
-      $name_deleter,
-      $name_deletee,
-      $name_other,
-    );
-    $this->assertIdentical($expected, $updates);
-
-    // Import.
-    $this->configImporter->import();
-
-    $entity_storage = \Drupal::entityManager()->getStorage('config_test');
-    $deleter = $entity_storage->load('deleter');
-    $this->assertEqual($deleter->id(), 'deleter');
-    $this->assertEqual($deleter->uuid(), $values_deleter['uuid']);
-    $this->assertEqual($deleter->label(), $values_deleter['label']);
-
-    // The deletee was deleted in
-    // \Drupal\config_test\Entity\ConfigTest::postSave().
-    $this->assertFalse($entity_storage->load('deletee'));
-
-    $other = $entity_storage->load('other');
-    $this->assertEqual($other->id(), 'other');
-    $this->assertEqual($other->uuid(), $values_other['uuid']);
-    $this->assertEqual($other->label(), $values_other['label']);
-
-    $logs = $this->configImporter->getErrors();
-    $this->assertEqual(count($logs), 1);
-    $this->assertEqual($logs[0], SafeMarkup::format('Update target "@name" is missing.', array('@name' => $name_deletee)));
-  }
-
-  /**
-   * Tests that secondary updates for deleted files work as expected.
-   *
-   * This test is completely hypothetical since we only support full
-   * configuration tree imports. Therefore, any configuration updates that cause
-   * secondary deletes should be reflected already in the staged configuration.
-   */
-  function testSecondaryUpdateDeletedDeleteeFirst() {
-    $name_deleter = 'config_test.dynamic.deleter';
-    $name_deletee = 'config_test.dynamic.deletee';
-    $storage = $this->container->get('config.storage');
-    $sync = $this->container->get('config.storage.sync');
-    $uuid = $this->container->get('uuid');
-
-    $values_deleter = array(
-      'id' => 'deleter',
-      'label' => 'Deleter',
-      'weight' => 0,
-      'uuid' => $uuid->generate(),
-      // Add a dependency on deletee, to make sure that is synced first.
-      'dependencies' => array(
-        'config' => array($name_deletee),
-      ),
-    );
-    $storage->write($name_deleter, $values_deleter);
-    $values_deleter['label'] = 'Updated Deleter';
-    $sync->write($name_deleter, $values_deleter);
-    $values_deletee = array(
-      'id' => 'deletee',
-      'label' => 'Deletee',
-      'weight' => 0,
-      'uuid' => $uuid->generate(),
-    );
-    $storage->write($name_deletee, $values_deletee);
-    $values_deletee['label'] = 'Updated Deletee';
-    $sync->write($name_deletee, $values_deletee);
-
-    // Import.
-    $this->configImporter->reset()->import();
-
-    $entity_storage = \Drupal::entityManager()->getStorage('config_test');
-    // Both entities are deleted. ConfigTest::postSave() causes updates of the
-    // deleter entity to delete the deletee entity. Since the deleter depends on
-    // the deletee, removing the deletee causes the deleter to be removed.
-    $this->assertFalse($entity_storage->load('deleter'));
-    $this->assertFalse($entity_storage->load('deletee'));
-    $logs = $this->configImporter->getErrors();
-    $this->assertEqual(count($logs), 0);
-  }
-
-  /**
-   * Tests that secondary deletes for deleted files work as expected.
-   */
-  function testSecondaryDeletedDeleteeSecond() {
-    $name_deleter = 'config_test.dynamic.deleter';
-    $name_deletee = 'config_test.dynamic.deletee';
-    $storage = $this->container->get('config.storage');
-
-    $uuid = $this->container->get('uuid');
-
-    $values_deleter = array(
-      'id' => 'deleter',
-      'label' => 'Deleter',
-      'weight' => 0,
-      'uuid' => $uuid->generate(),
-      // Add a dependency on deletee, to make sure this delete is synced first.
-      'dependencies' => array(
-        'config' => array($name_deletee),
-      ),
-    );
-    $storage->write($name_deleter, $values_deleter);
-    $values_deletee = array(
-      'id' => 'deletee',
-      'label' => 'Deletee',
-      'weight' => 0,
-      'uuid' => $uuid->generate(),
-    );
-    $storage->write($name_deletee, $values_deletee);
-
-    // Import.
-    $this->configImporter->reset()->import();
-
-    $entity_storage = \Drupal::entityManager()->getStorage('config_test');
-    $this->assertFalse($entity_storage->load('deleter'));
-    $this->assertFalse($entity_storage->load('deletee'));
-    // The deletee entity does not exist as the delete worked and although the
-    // delete occurred in \Drupal\config_test\Entity\ConfigTest::postDelete()
-    // this does not matter.
-    $logs = $this->configImporter->getErrors();
-    $this->assertEqual(count($logs), 0);
-  }
-
-  /**
-   * Tests updating of configuration during import.
-   */
-  function testUpdated() {
-    $name = 'config_test.system';
-    $dynamic_name = 'config_test.dynamic.dotted.default';
-    $storage = $this->container->get('config.storage');
-    $sync = $this->container->get('config.storage.sync');
-
-    // Verify that the configuration objects to import exist.
-    $this->assertIdentical($storage->exists($name), TRUE, $name . ' found.');
-    $this->assertIdentical($storage->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
-
-    // Replace the file content of the existing configuration objects in the
-    // sync directory.
-    $original_name_data = array(
-      'foo' => 'beer',
-    );
-    $sync->write($name, $original_name_data);
-    $original_dynamic_data = $storage->read($dynamic_name);
-    $original_dynamic_data['label'] = 'Updated';
-    $sync->write($dynamic_name, $original_dynamic_data);
-
-    // Verify the active configuration still returns the default values.
-    $config = $this->config($name);
-    $this->assertIdentical($config->get('foo'), 'bar');
-    $config = $this->config($dynamic_name);
-    $this->assertIdentical($config->get('label'), 'Default');
-
-    // Import.
-    $this->configImporter->reset()->import();
-
-    // Verify the values were updated.
-    \Drupal::configFactory()->reset($name);
-    $config = $this->config($name);
-    $this->assertIdentical($config->get('foo'), 'beer');
-    $config = $this->config($dynamic_name);
-    $this->assertIdentical($config->get('label'), 'Updated');
-
-    // Verify that the original file content is still the same.
-    $this->assertIdentical($sync->read($name), $original_name_data);
-    $this->assertIdentical($sync->read($dynamic_name), $original_dynamic_data);
-
-    // Verify that appropriate module API hooks have been invoked.
-    $this->assertTrue(isset($GLOBALS['hook_config_test']['load']));
-    $this->assertTrue(isset($GLOBALS['hook_config_test']['presave']));
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['insert']));
-    $this->assertTrue(isset($GLOBALS['hook_config_test']['update']));
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['predelete']));
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['delete']));
-
-    // Verify that there is nothing more to import.
-    $this->assertFalse($this->configImporter->hasUnprocessedConfigurationChanges());
-    $logs = $this->configImporter->getErrors();
-    $this->assertEqual(count($logs), 0);
-  }
-
-  /**
-   * Tests the isInstallable method()
-   */
-  function testIsInstallable() {
-    $config_name = 'config_test.dynamic.isinstallable';
-    $this->assertFalse($this->container->get('config.storage')->exists($config_name));
-    \Drupal::state()->set('config_test.isinstallable', TRUE);
-    $this->installConfig(array('config_test'));
-    $this->assertTrue($this->container->get('config.storage')->exists($config_name));
-  }
-
-  /**
-   * Tests dependency validation during configuration import.
-   *
-   * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber
-   * @see \Drupal\Core\Config\ConfigImporter::createExtensionChangelist()
-   */
-  public function testUnmetDependency() {
-    $storage = $this->container->get('config.storage');
-    $sync = $this->container->get('config.storage.sync');
-
-    // Test an unknown configuration owner.
-    $sync->write('unknown.config', ['test' => 'test']);
-
-    // Make a config entity have unmet dependencies.
-    $config_entity_data = $sync->read('config_test.dynamic.dotted.default');
-    $config_entity_data['dependencies'] = ['module' => ['unknown']];
-    $sync->write('config_test.dynamic.dotted.module', $config_entity_data);
-    $config_entity_data['dependencies'] = ['theme' => ['unknown']];
-    $sync->write('config_test.dynamic.dotted.theme', $config_entity_data);
-    $config_entity_data['dependencies'] = ['config' => ['unknown']];
-    $sync->write('config_test.dynamic.dotted.config', $config_entity_data);
-
-    // Make an active config depend on something that is missing in sync.
-    // The whole configuration needs to be consistent, not only the updated one.
-    $config_entity_data['dependencies'] = [];
-    $storage->write('config_test.dynamic.dotted.deleted', $config_entity_data);
-    $config_entity_data['dependencies'] = ['config' => ['config_test.dynamic.dotted.deleted']];
-    $storage->write('config_test.dynamic.dotted.existing', $config_entity_data);
-    $sync->write('config_test.dynamic.dotted.existing', $config_entity_data);
-
-    $extensions = $sync->read('core.extension');
-    // Add a module and a theme that do not exist.
-    $extensions['module']['unknown_module'] = 0;
-    $extensions['theme']['unknown_theme'] = 0;
-    // Add a module and a theme that depend on uninstalled extensions.
-    $extensions['module']['book'] = 0;
-    $extensions['theme']['bartik'] = 0;
-
-    $sync->write('core.extension', $extensions);
-    try {
-      $this->configImporter->reset()->import();
-      $this->fail('ConfigImporterException not thrown; an invalid import was not stopped due to missing dependencies.');
-    }
-    catch (ConfigImporterException $e) {
-      $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.');
-      $error_log = $this->configImporter->getErrors();
-      $expected = [
-        'Unable to install the <em class="placeholder">unknown_module</em> module since it does not exist.',
-        'Unable to install the <em class="placeholder">Book</em> module since it requires the <em class="placeholder">Node, Text, Field, Filter, User</em> modules.',
-        'Unable to install the <em class="placeholder">unknown_theme</em> theme since it does not exist.',
-        'Unable to install the <em class="placeholder">Bartik</em> theme since it requires the <em class="placeholder">Classy</em> theme.',
-        'Configuration <em class="placeholder">config_test.dynamic.dotted.config</em> depends on the <em class="placeholder">unknown</em> configuration that will not exist after import.',
-        'Configuration <em class="placeholder">config_test.dynamic.dotted.existing</em> depends on the <em class="placeholder">config_test.dynamic.dotted.deleted</em> configuration that will not exist after import.',
-        'Configuration <em class="placeholder">config_test.dynamic.dotted.module</em> depends on the <em class="placeholder">unknown</em> module that will not be installed after import.',
-        'Configuration <em class="placeholder">config_test.dynamic.dotted.theme</em> depends on the <em class="placeholder">unknown</em> theme that will not be installed after import.',
-        'Configuration <em class="placeholder">unknown.config</em> depends on the <em class="placeholder">unknown</em> extension that will not be installed after import.',
-      ];
-      foreach ($expected as $expected_message) {
-        $this->assertTrue(in_array($expected_message, $error_log), $expected_message);
-      }
-    }
-
-    // Make a config entity have mulitple unmet dependencies.
-    $config_entity_data = $sync->read('config_test.dynamic.dotted.default');
-    $config_entity_data['dependencies'] = ['module' => ['unknown', 'dblog']];
-    $sync->write('config_test.dynamic.dotted.module', $config_entity_data);
-    $config_entity_data['dependencies'] = ['theme' => ['unknown', 'seven']];
-    $sync->write('config_test.dynamic.dotted.theme', $config_entity_data);
-    $config_entity_data['dependencies'] = ['config' => ['unknown', 'unknown2']];
-    $sync->write('config_test.dynamic.dotted.config', $config_entity_data);
-    try {
-      $this->configImporter->reset()->import();
-      $this->fail('ConfigImporterException not thrown, invalid import was not stopped due to missing dependencies.');
-    }
-    catch (ConfigImporterException $e) {
-      $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.');
-      $error_log = $this->configImporter->getErrors();
-      $expected = [
-        'Configuration <em class="placeholder">config_test.dynamic.dotted.config</em> depends on configuration (<em class="placeholder">unknown, unknown2</em>) that will not exist after import.',
-        'Configuration <em class="placeholder">config_test.dynamic.dotted.module</em> depends on modules (<em class="placeholder">unknown, Database Logging</em>) that will not be installed after import.',
-        'Configuration <em class="placeholder">config_test.dynamic.dotted.theme</em> depends on themes (<em class="placeholder">unknown, Seven</em>) that will not be installed after import.',
-      ];
-      foreach ($expected as $expected_message) {
-        $this->assertTrue(in_array($expected_message, $error_log), $expected_message);
-      }
-    }
-  }
-
-  /**
-   * Tests missing core.extension during configuration import.
-   *
-   * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber
-   */
-  public function testMissingCoreExtension() {
-    $sync = $this->container->get('config.storage.sync');
-    $sync->delete('core.extension');
-    try {
-      $this->configImporter->reset()->import();
-      $this->fail('ConfigImporterException not thrown, invalid import was not stopped due to missing dependencies.');
-    }
-    catch (ConfigImporterException $e) {
-      $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.');
-      $error_log = $this->configImporter->getErrors();
-      $this->assertEqual(['The core.extension configuration does not exist.'], $error_log);
-    }
-  }
-
-  /**
-   * Tests install profile validation during configuration import.
-   *
-   * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber
-   */
-  public function testInstallProfile() {
-    $sync = $this->container->get('config.storage.sync');
-
-    $extensions = $sync->read('core.extension');
-    // Add an install profile.
-    $extensions['module']['standard'] = 0;
-
-    $sync->write('core.extension', $extensions);
-    try {
-      $this->configImporter->reset()->import();
-      $this->fail('ConfigImporterException not thrown; an invalid import was not stopped due to missing dependencies.');
-    }
-    catch (ConfigImporterException $e) {
-      $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.');
-      $error_log = $this->configImporter->getErrors();
-      // Install profiles should not even be scanned at this point.
-      $this->assertEqual(['Unable to install the <em class="placeholder">standard</em> module since it does not exist.'], $error_log);
-    }
-  }
-
-  /**
-   * Tests config_get_config_directory().
-   */
-  public function testConfigGetConfigDirectory() {
-    $directory = config_get_config_directory(CONFIG_SYNC_DIRECTORY);
-    $this->assertEqual($this->configDirectories[CONFIG_SYNC_DIRECTORY], $directory);
-
-    $message = 'Calling config_get_config_directory() with CONFIG_ACTIVE_DIRECTORY results in an exception.';
-    try {
-      config_get_config_directory(CONFIG_ACTIVE_DIRECTORY);
-      $this->fail($message);
-    }
-    catch (\Exception $e) {
-      $this->pass($message);
-    }
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigInstallTest.php b/core/modules/config/src/Tests/ConfigInstallTest.php
deleted file mode 100644
index e5ac68d..0000000
--- a/core/modules/config/src/Tests/ConfigInstallTest.php
+++ /dev/null
@@ -1,254 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\config\Tests\ConfigInstallTest.
- */
-
-namespace Drupal\config\Tests;
-
-use Drupal\Core\Config\InstallStorage;
-use Drupal\Core\Config\PreExistingConfigException;
-use Drupal\Core\Config\UnmetDependenciesException;
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests installation of configuration objects in installation functionality.
- *
- * @group config
- * @see \Drupal\Core\Config\ConfigInstaller
- */
-class ConfigInstallTest extends KernelTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = ['system'];
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->installSchema('system', ['router']);
-
-    // 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 installation.
-   */
-  function testModuleInstallation() {
-    $default_config = 'config_test.system';
-    $default_configuration_entity = 'config_test.dynamic.dotted.default';
-
-    // Verify that default module config does not exist before installation yet.
-    $config = $this->config($default_config);
-    $this->assertIdentical($config->isNew(), TRUE);
-    $config = $this->config($default_configuration_entity);
-    $this->assertIdentical($config->isNew(), TRUE);
-
-    // Ensure that schema provided by modules that are not installed is not
-    // available.
-    $this->assertFalse(\Drupal::service('config.typed')->hasConfigSchema('config_schema_test.someschema'), 'Configuration schema for config_schema_test.someschema does not exist.');
-
-    // Install the test module.
-    $this->installModules(array('config_test'));
-
-    // Verify that default module config exists.
-    \Drupal::configFactory()->reset($default_config);
-    \Drupal::configFactory()->reset($default_configuration_entity);
-    $config = $this->config($default_config);
-    $this->assertIdentical($config->isNew(), FALSE);
-    $config = $this->config($default_configuration_entity);
-    $this->assertIdentical($config->isNew(), FALSE);
-
-    // Verify that config_test API hooks were invoked for the dynamic default
-    // configuration entity.
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['load']));
-    $this->assertTrue(isset($GLOBALS['hook_config_test']['presave']));
-    $this->assertTrue(isset($GLOBALS['hook_config_test']['insert']));
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['update']));
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['predelete']));
-    $this->assertFalse(isset($GLOBALS['hook_config_test']['delete']));
-
-    // Install the schema test module.
-    $this->enableModules(array('config_schema_test'));
-    $this->installConfig(array('config_schema_test'));
-
-    // After module installation the new schema should exist.
-    $this->assertTrue(\Drupal::service('config.typed')->hasConfigSchema('config_schema_test.someschema'), 'Configuration schema for config_schema_test.someschema exists.');
-
-    // Test that uninstalling configuration removes configuration schema.
-    $this->config('core.extension')->set('module', array())->save();
-    \Drupal::service('config.manager')->uninstall('module', 'config_test');
-    $this->assertFalse(\Drupal::service('config.typed')->hasConfigSchema('config_schema_test.someschema'), 'Configuration schema for config_schema_test.someschema does not exist.');
-  }
-
-  /**
-   * Tests that collections are ignored if the event does not return anything.
-   */
-  public function testCollectionInstallationNoCollections() {
-    // Install the test module.
-    $this->enableModules(array('config_collection_install_test'));
-    $this->installConfig(array('config_collection_install_test'));
-    /** @var \Drupal\Core\Config\StorageInterface $active_storage */
-    $active_storage = \Drupal::service('config.storage');
-    $this->assertEqual(array(), $active_storage->getAllCollectionNames());
-  }
-
-  /**
-   * Tests config objects in collections are installed as expected.
-   */
-  public function testCollectionInstallationCollections() {
-    $collections = array(
-      'another_collection',
-      'collection.test1',
-      'collection.test2',
-    );
-    // Set the event listener to return three possible collections.
-    // @see \Drupal\config_collection_install_test\EventSubscriber
-    \Drupal::state()->set('config_collection_install_test.collection_names', $collections);
-    // Install the test module.
-    $this->enableModules(array('config_collection_install_test'));
-    $this->installConfig(array('config_collection_install_test'));
-    /** @var \Drupal\Core\Config\StorageInterface $active_storage */
-    $active_storage = \Drupal::service('config.storage');
-    $this->assertEqual($collections, $active_storage->getAllCollectionNames());
-    foreach ($collections as $collection) {
-      $collection_storage = $active_storage->createCollection($collection);
-      $data = $collection_storage->read('config_collection_install_test.test');
-      $this->assertEqual($collection, $data['collection']);
-    }
-
-    // Tests that clashing configuration in collections is detected.
-    try {
-      \Drupal::service('module_installer')->install(['config_collection_clash_install_test']);
-      $this->fail('Expected PreExistingConfigException not thrown.');
-    }
-    catch (PreExistingConfigException $e) {
-      $this->assertEqual($e->getExtension(), 'config_collection_clash_install_test');
-      $this->assertEqual($e->getConfigObjects(), [
-        'another_collection' => ['config_collection_install_test.test'],
-        'collection.test1' => ['config_collection_install_test.test'],
-        'collection.test2' => ['config_collection_install_test.test'],
-      ]);
-      $this->assertEqual($e->getMessage(), 'Configuration objects (another_collection/config_collection_install_test.test, collection/test1/config_collection_install_test.test, collection/test2/config_collection_install_test.test) provided by config_collection_clash_install_test already exist in active configuration');
-    }
-
-    // Test that the we can use the config installer to install all the
-    // available default configuration in a particular collection for enabled
-    // extensions.
-    \Drupal::service('config.installer')->installCollectionDefaultConfig('entity');
-    // The 'entity' collection will not exist because the 'config_test' module
-    // is not enabled.
-    $this->assertEqual($collections, $active_storage->getAllCollectionNames());
-    // Enable the 'config_test' module and try again.
-    $this->enableModules(array('config_test'));
-    \Drupal::service('config.installer')->installCollectionDefaultConfig('entity');
-    $collections[] = 'entity';
-    $this->assertEqual($collections, $active_storage->getAllCollectionNames());
-    $collection_storage = $active_storage->createCollection('entity');
-    $data = $collection_storage->read('config_test.dynamic.dotted.default');
-    $this->assertIdentical(array('label' => 'entity'), $data);
-
-    // Test that the config manager uninstalls configuration from collections
-    // as expected.
-    \Drupal::service('config.manager')->uninstall('module', 'config_collection_install_test');
-    $this->assertEqual(array('entity'), $active_storage->getAllCollectionNames());
-    \Drupal::service('config.manager')->uninstall('module', 'config_test');
-    $this->assertEqual(array(), $active_storage->getAllCollectionNames());
-  }
-
-  /**
-   * Tests collections which do not support config entities install correctly.
-   *
-   * Config entity detection during config installation is done by matching
-   * config name prefixes. If a collection provides a configuration with a
-   * matching name but does not support config entities it should be created
-   * using simple configuration.
-   */
-  public function testCollectionInstallationCollectionConfigEntity() {
-    $collections = array(
-      'entity',
-    );
-    \Drupal::state()->set('config_collection_install_test.collection_names', $collections);
-    // Install the test module.
-    $this->installModules(array('config_test', 'config_collection_install_test'));
-    /** @var \Drupal\Core\Config\StorageInterface $active_storage */
-    $active_storage = \Drupal::service('config.storage');
-    $this->assertEqual($collections, $active_storage->getAllCollectionNames());
-    $collection_storage = $active_storage->createCollection('entity');
-
-    // The config_test.dynamic.dotted.default configuration object saved in the
-    // active store should be a configuration entity complete with UUID. Because
-    // the entity collection does not support configuration entities the
-    // configuration object stored there with the same name should only contain
-    // a label.
-    $name = 'config_test.dynamic.dotted.default';
-    $data = $active_storage->read($name);
-    $this->assertTrue(isset($data['uuid']));
-    $data = $collection_storage->read($name);
-    $this->assertIdentical(array('label' => 'entity'), $data);
-  }
-
-  /**
-   * Tests the configuration with unmet dependencies is not installed.
-   */
-  public function testDependencyChecking() {
-    $this->installModules(['config_test']);
-    try {
-      $this->installModules(['config_install_dependency_test']);
-      $this->fail('Expected UnmetDependenciesException not thrown.');
-    }
-    catch (UnmetDependenciesException $e) {
-      $this->assertEqual($e->getExtension(), 'config_install_dependency_test');
-      $this->assertEqual($e->getConfigObjects(), ['config_test.dynamic.other_module_test_with_dependency']);
-      $this->assertEqual($e->getMessage(), 'Configuration objects (config_test.dynamic.other_module_test_with_dependency) provided by config_install_dependency_test have unmet dependencies');
-    }
-    $this->installModules(['config_other_module_config_test']);
-    $this->installModules(['config_install_dependency_test']);
-    $entity = \Drupal::entityManager()->getStorage('config_test')->load('other_module_test_with_dependency');
-    $this->assertTrue($entity, 'The config_test.dynamic.other_module_test_with_dependency configuration has been created during install.');
-    // Ensure that dependencies can be added during module installation by
-    // hooks.
-    $this->assertIdentical('config_install_dependency_test', $entity->getDependencies()['module'][0]);
-  }
-
-  /**
-   * Tests imported configuration entities with and without language information.
-   */
-  function testLanguage() {
-    $this->installModules(['config_test_language']);
-    // Test imported configuration with implicit language code.
-    $storage = new InstallStorage();
-    $data = $storage->read('config_test.dynamic.dotted.english');
-    $this->assertTrue(!isset($data['langcode']));
-    $this->assertEqual(
-      $this->config('config_test.dynamic.dotted.english')->get('langcode'),
-      'en'
-    );
-
-    // Test imported configuration with explicit language code.
-    $data = $storage->read('config_test.dynamic.dotted.french');
-    $this->assertEqual($data['langcode'], 'fr');
-    $this->assertEqual(
-      $this->config('config_test.dynamic.dotted.french')->get('langcode'),
-      'fr'
-    );
-  }
-
-  /**
-   * Installs a module.
-   *
-   * @param array $modules
-   *   The module names.
-   */
-  protected function installModules(array $modules) {
-    $this->container->get('module_installer')->install($modules);
-    $this->container = \Drupal::getContainer();
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigLanguageOverrideTest.php b/core/modules/config/src/Tests/ConfigLanguageOverrideTest.php
deleted file mode 100644
index 8cbb695..0000000
--- a/core/modules/config/src/Tests/ConfigLanguageOverrideTest.php
+++ /dev/null
@@ -1,125 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\config\Tests\ConfigLanguageOverrideTest.
- */
-
-namespace Drupal\config\Tests;
-
-use Drupal\language\Entity\ConfigurableLanguage;
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Confirm that language overrides work.
- *
- * @group config
- */
-class ConfigLanguageOverrideTest extends KernelTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('user', 'language', 'config_test', 'system', 'field');
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->installConfig(array('config_test'));
-  }
-
-  /**
-   * Tests locale override based on language.
-   */
-  function testConfigLanguageOverride() {
-    // The language module implements a config factory override object that
-    // overrides configuration when the Language module is enabled. This test ensures that
-    // English overrides work.
-    \Drupal::languageManager()->setConfigOverrideLanguage(\Drupal::languageManager()->getLanguage('en'));
-    $config = \Drupal::config('config_test.system');
-    $this->assertIdentical($config->get('foo'), 'en bar');
-
-    // Ensure that the raw data is not translated.
-    $raw = $config->getRawData();
-    $this->assertIdentical($raw['foo'], 'bar');
-
-    ConfigurableLanguage::createFromLangcode('fr')->save();
-    ConfigurableLanguage::createFromLangcode('de')->save();
-
-    \Drupal::languageManager()->setConfigOverrideLanguage(\Drupal::languageManager()->getLanguage('fr'));
-    $config = \Drupal::config('config_test.system');
-    $this->assertIdentical($config->get('foo'), 'fr bar');
-
-    \Drupal::languageManager()->setConfigOverrideLanguage(\Drupal::languageManager()->getLanguage('de'));
-    $config = \Drupal::config('config_test.system');
-    $this->assertIdentical($config->get('foo'), 'de bar');
-
-    // Test overrides of completely new configuration objects. In normal runtime
-    // this should only happen for configuration entities as we should not be
-    // creating simple configuration objects on the fly.
-    \Drupal::languageManager()
-      ->getLanguageConfigOverride('de', 'config_test.new')
-      ->set('language', 'override')
-      ->save();
-    $config = \Drupal::config('config_test.new');
-    $this->assertTrue($config->isNew(), 'The configuration object config_test.new is new');
-    $this->assertIdentical($config->get('language'), 'override');
-    $this->assertIdentical($config->getOriginal('language', FALSE), NULL);
-
-    // Test how overrides react to base configuration changes. Set up some base
-    // values.
-    \Drupal::configFactory()->getEditable('config_test.foo')
-      ->set('value', array('key' => 'original'))
-      ->set('label', 'Original')
-      ->save();
-    \Drupal::languageManager()
-      ->getLanguageConfigOverride('de', 'config_test.foo')
-      ->set('value', array('key' => 'override'))
-      ->set('label', 'Override')
-      ->save();
-    \Drupal::languageManager()
-      ->getLanguageConfigOverride('fr', 'config_test.foo')
-      ->set('value', array('key' => 'override'))
-      ->save();
-    \Drupal::configFactory()->clearStaticCache();
-    $config = \Drupal::config('config_test.foo');
-    $this->assertIdentical($config->get('value'), array('key' => 'override'));
-
-    // Ensure renaming the config will rename the override.
-    \Drupal::languageManager()->setConfigOverrideLanguage(\Drupal::languageManager()->getLanguage('en'));
-    \Drupal::configFactory()->rename('config_test.foo', 'config_test.bar');
-    $config = \Drupal::config('config_test.bar');
-    $this->assertEqual($config->get('value'), array('key' => 'original'));
-    $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.foo');
-    $this->assertTrue($override->isNew());
-    $this->assertEqual($override->get('value'), NULL);
-    $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.bar');
-    $this->assertFalse($override->isNew());
-    $this->assertEqual($override->get('value'), array('key' => 'override'));
-    $override = \Drupal::languageManager()->getLanguageConfigOverride('fr', 'config_test.bar');
-    $this->assertFalse($override->isNew());
-    $this->assertEqual($override->get('value'), array('key' => 'override'));
-
-    // Ensure changing data in the config will update the overrides.
-    $config = \Drupal::configFactory()->getEditable('config_test.bar')->clear('value.key')->save();
-    $this->assertEqual($config->get('value'), array());
-    $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.bar');
-    $this->assertFalse($override->isNew());
-    $this->assertEqual($override->get('value'), NULL);
-    // The French override will become empty and therefore removed.
-    $override = \Drupal::languageManager()->getLanguageConfigOverride('fr', 'config_test.bar');
-    $this->assertTrue($override->isNew());
-    $this->assertEqual($override->get('value'), NULL);
-
-    // Ensure deleting the config will delete the override.
-    \Drupal::configFactory()->getEditable('config_test.bar')->delete();
-    $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.bar');
-    $this->assertTrue($override->isNew());
-    $this->assertEqual($override->get('value'), NULL);
-  }
-}
-
diff --git a/core/modules/config/src/Tests/ConfigOverrideTest.php b/core/modules/config/src/Tests/ConfigOverrideTest.php
deleted file mode 100644
index b9a262d..0000000
--- a/core/modules/config/src/Tests/ConfigOverrideTest.php
+++ /dev/null
@@ -1,143 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\config\Tests\ConfigOverrideTest.
- */
-
-namespace Drupal\config\Tests;
-
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests configuration overrides via $config in settings.php.
- *
- * @group config
- */
-class ConfigOverrideTest extends KernelTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('system', 'config_test');
-
-  protected function setUp() {
-    parent::setUp();
-    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
-  }
-
-  /**
-   * Tests configuration override.
-   */
-  function testConfOverride() {
-    $expected_original_data = array(
-      'foo' => 'bar',
-      'baz' => NULL,
-      '404' => 'herp',
-    );
-
-    // Set globals before installing to prove that the installed file does not
-    // contain these values.
-    $overrides['config_test.system']['foo'] = 'overridden';
-    $overrides['config_test.system']['baz'] = 'injected';
-    $overrides['config_test.system']['404'] = 'derp';
-    $GLOBALS['config'] = $overrides;
-
-    $this->installConfig(array('config_test'));
-
-    // Verify that the original configuration data exists. Have to read storage
-    // directly otherwise overrides will apply.
-    $active = $this->container->get('config.storage');
-    $data = $active->read('config_test.system');
-    $this->assertIdentical($data['foo'], $expected_original_data['foo']);
-    $this->assertFalse(isset($data['baz']));
-    $this->assertIdentical($data['404'], $expected_original_data['404']);
-
-    // Get the configuration object with overrides.
-    $config = \Drupal::configFactory()->get('config_test.system');
-
-    // Verify that it contains the overridden data from $config.
-    $this->assertIdentical($config->get('foo'), $overrides['config_test.system']['foo']);
-    $this->assertIdentical($config->get('baz'), $overrides['config_test.system']['baz']);
-    $this->assertIdentical($config->get('404'), $overrides['config_test.system']['404']);
-
-    // Get the configuration object which does not have overrides.
-    $config = \Drupal::configFactory()->getEditable('config_test.system');
-
-    // Verify that it does not contains the overridden data from $config.
-    $this->assertIdentical($config->get('foo'), $expected_original_data['foo']);
-    $this->assertIdentical($config->get('baz'), NULL);
-    $this->assertIdentical($config->get('404'), $expected_original_data['404']);
-
-    // Set the value for 'baz' (on the original data).
-    $expected_original_data['baz'] = 'original baz';
-    $config->set('baz', $expected_original_data['baz']);
-
-    // Set the value for '404' (on the original data).
-    $expected_original_data['404'] = 'original 404';
-    $config->set('404', $expected_original_data['404']);
-
-    // Save the configuration object (having overrides applied).
-    $config->save();
-
-    // Reload it and verify that it still contains overridden data from $config.
-    $config = \Drupal::config('config_test.system');
-    $this->assertIdentical($config->get('foo'), $overrides['config_test.system']['foo']);
-    $this->assertIdentical($config->get('baz'), $overrides['config_test.system']['baz']);
-    $this->assertIdentical($config->get('404'), $overrides['config_test.system']['404']);
-
-    // Verify that raw config data has changed.
-    $this->assertIdentical($config->getOriginal('foo', FALSE), $expected_original_data['foo']);
-    $this->assertIdentical($config->getOriginal('baz', FALSE), $expected_original_data['baz']);
-    $this->assertIdentical($config->getOriginal('404', FALSE), $expected_original_data['404']);
-
-    // Write file to sync.
-    $sync = $this->container->get('config.storage.sync');
-    $expected_new_data = array(
-      'foo' => 'barbar',
-      '404' => 'herpderp',
-    );
-    $sync->write('config_test.system', $expected_new_data);
-
-    // Import changed data from sync to active.
-    $this->configImporter()->import();
-    $data = $active->read('config_test.system');
-
-    // Verify that the new configuration data exists. Have to read storage
-    // directly otherwise overrides will apply.
-    $this->assertIdentical($data['foo'], $expected_new_data['foo']);
-    $this->assertFalse(isset($data['baz']));
-    $this->assertIdentical($data['404'], $expected_new_data['404']);
-
-    // Verify that the overrides are still working.
-    $config = \Drupal::config('config_test.system');
-    $this->assertIdentical($config->get('foo'), $overrides['config_test.system']['foo']);
-    $this->assertIdentical($config->get('baz'), $overrides['config_test.system']['baz']);
-    $this->assertIdentical($config->get('404'), $overrides['config_test.system']['404']);
-
-    // Test overrides of completely new configuration objects. In normal runtime
-    // this should only happen for configuration entities as we should not be
-    // creating simple configuration objects on the fly.
-    $GLOBALS['config']['config_test.new']['key'] = 'override';
-    $config = \Drupal::config('config_test.new');
-    $this->assertTrue($config->isNew(), 'The configuration object config_test.new is new');
-    $this->assertIdentical($config->get('key'), 'override');
-    $config_raw = \Drupal::configFactory()->getEditable('config_test.new');
-    $this->assertIdentical($config_raw->get('key'), NULL);
-    $config_raw
-      ->set('key', 'raw')
-      ->set('new_key', 'new_value')
-      ->save();
-    // Ensure override is preserved but all other data has been updated
-    // accordingly.
-    $config = \Drupal::config('config_test.new');
-    $this->assertFalse($config->isNew(), 'The configuration object config_test.new is not new');
-    $this->assertIdentical($config->get('key'), 'override');
-    $this->assertIdentical($config->get('new_key'), 'new_value');
-    $raw_data = $config->getRawData();
-    $this->assertIdentical($raw_data['key'], 'raw');
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigSchemaTest.php b/core/modules/config/src/Tests/ConfigSchemaTest.php
deleted file mode 100644
index a34e6a6..0000000
--- a/core/modules/config/src/Tests/ConfigSchemaTest.php
+++ /dev/null
@@ -1,575 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\config\Tests\ConfigSchemaTest.
- */
-
-namespace Drupal\config\Tests;
-
-use Drupal\Core\Config\FileStorage;
-use Drupal\Core\Config\InstallStorage;
-use Drupal\Core\Config\Schema\ConfigSchemaAlterException;
-use Drupal\Core\TypedData\Type\IntegerInterface;
-use Drupal\Core\TypedData\Type\StringInterface;
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests schema for configuration objects.
- *
- * @group config
- */
-class ConfigSchemaTest extends KernelTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('system', 'language', 'field', 'image', 'config_test', 'config_schema_test');
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->installConfig(array('system', 'image', 'config_schema_test'));
-  }
-
-  /**
-   * Tests the basic metadata retrieval layer.
-   */
-  function testSchemaMapping() {
-    // Nonexistent configuration key will have Undefined as metadata.
-    $this->assertIdentical(FALSE, \Drupal::service('config.typed')->hasConfigSchema('config_schema_test.no_such_key'));
-    $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.no_such_key');
-    $expected = array();
-    $expected['label'] = 'Undefined';
-    $expected['class'] = '\Drupal\Core\Config\Schema\Undefined';
-    $expected['type'] = 'undefined';
-    $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
-    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for nonexistent configuration.');
-
-    // Configuration file without schema will return Undefined as well.
-    $this->assertIdentical(FALSE, \Drupal::service('config.typed')->hasConfigSchema('config_schema_test.noschema'));
-    $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.noschema');
-    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for configuration with no schema.');
-
-    // Configuration file with only some schema.
-    $this->assertIdentical(TRUE, \Drupal::service('config.typed')->hasConfigSchema('config_schema_test.someschema'));
-    $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.someschema');
-    $expected = array();
-    $expected['label'] = 'Schema test data';
-    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
-    $expected['mapping']['langcode']['type'] = 'string';
-    $expected['mapping']['langcode']['label'] = 'Language code';
-    $expected['mapping']['_core']['type'] = '_core_config_info';
-    $expected['mapping']['testitem'] = array('label' => 'Test item');
-    $expected['mapping']['testlist'] = array('label' => 'Test list');
-    $expected['type'] = 'config_schema_test.someschema';
-    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
-    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for configuration with only some schema.');
-
-    // Check type detection on elements with undefined types.
-    $config = \Drupal::service('config.typed')->get('config_schema_test.someschema');
-    $definition = $config->get('testitem')->getDataDefinition()->toArray();
-    $expected = array();
-    $expected['label'] = 'Test item';
-    $expected['class'] = '\Drupal\Core\Config\Schema\Undefined';
-    $expected['type'] = 'undefined';
-    $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
-    $this->assertEqual($definition, $expected, 'Automatic type detected for a scalar is undefined.');
-    $definition = $config->get('testlist')->getDataDefinition()->toArray();
-    $expected = array();
-    $expected['label'] = 'Test list';
-    $expected['class'] = '\Drupal\Core\Config\Schema\Undefined';
-    $expected['type'] = 'undefined';
-    $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
-    $this->assertEqual($definition, $expected, 'Automatic type detected for a list is undefined.');
-    $definition = $config->get('testnoschema')->getDataDefinition()->toArray();
-    $expected = array();
-    $expected['label'] = 'Undefined';
-    $expected['class'] = '\Drupal\Core\Config\Schema\Undefined';
-    $expected['type'] = 'undefined';
-    $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
-    $this->assertEqual($definition, $expected, 'Automatic type detected for an undefined integer is undefined.');
-
-    // Simple case, straight metadata.
-    $definition = \Drupal::service('config.typed')->getDefinition('system.maintenance');
-    $expected = array();
-    $expected['label'] = 'Maintenance mode';
-    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
-    $expected['mapping']['message'] = array(
-      'label' =>  'Message to display when in maintenance mode',
-      'type' => 'text',
-    );
-    $expected['mapping']['langcode'] = array(
-      'label' => 'Language code',
-      'type' => 'string',
-    );
-    $expected['mapping']['_core']['type'] = '_core_config_info';
-    $expected['type'] = 'system.maintenance';
-    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
-    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for system.maintenance');
-
-    // Mixed schema with ignore elements.
-    $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.ignore');
-    $expected = array();
-    $expected['label'] = 'Ignore test';
-    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
-    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
-    $expected['mapping']['langcode'] = array(
-      'type' => 'string',
-      'label' => 'Language code',
-    );
-    $expected['mapping']['_core']['type'] = '_core_config_info';
-    $expected['mapping']['label'] = array(
-      'label' =>  'Label',
-      'type' => 'label',
-    );
-    $expected['mapping']['irrelevant'] = array(
-      'label' => 'Irrelevant',
-      'type' => 'ignore',
-    );
-    $expected['mapping']['indescribable'] = array(
-      'label' => 'Indescribable',
-      'type' => 'ignore',
-    );
-    $expected['mapping']['weight'] = array(
-      'label' => 'Weight',
-      'type' => 'integer',
-    );
-    $expected['type'] = 'config_schema_test.ignore';
-
-    $this->assertEqual($definition, $expected);
-
-    // The ignore elements themselves.
-    $definition = \Drupal::service('config.typed')->get('config_schema_test.ignore')->get('irrelevant')->getDataDefinition()->toArray();
-    $expected = array();
-    $expected['type'] = 'ignore';
-    $expected['label'] = 'Irrelevant';
-    $expected['class'] = '\Drupal\Core\Config\Schema\Ignore';
-    $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
-    $this->assertEqual($definition, $expected);
-    $definition = \Drupal::service('config.typed')->get('config_schema_test.ignore')->get('indescribable')->getDataDefinition()->toArray();
-    $expected['label'] = 'Indescribable';
-    $this->assertEqual($definition, $expected);
-
-    // More complex case, generic type. Metadata for image style.
-    $definition = \Drupal::service('config.typed')->getDefinition('image.style.large');
-    $expected = array();
-    $expected['label'] = 'Image style';
-    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
-    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
-    $expected['mapping']['name']['type'] = 'string';
-    $expected['mapping']['uuid']['type'] = 'string';
-    $expected['mapping']['uuid']['label'] = 'UUID';
-    $expected['mapping']['langcode']['type'] = 'string';
-    $expected['mapping']['langcode']['label'] = 'Language code';
-    $expected['mapping']['status']['type'] = 'boolean';
-    $expected['mapping']['status']['label'] = 'Status';
-    $expected['mapping']['dependencies']['type'] = 'config_dependencies';
-    $expected['mapping']['dependencies']['label'] = 'Dependencies';
-    $expected['mapping']['name']['type'] = 'string';
-    $expected['mapping']['label']['type'] = 'label';
-    $expected['mapping']['label']['label'] = 'Label';
-    $expected['mapping']['effects']['type'] = 'sequence';
-    $expected['mapping']['effects']['sequence']['type'] = 'mapping';
-    $expected['mapping']['effects']['sequence']['mapping']['id']['type'] = 'string';
-    $expected['mapping']['effects']['sequence']['mapping']['data']['type'] = 'image.effect.[%parent.id]';
-    $expected['mapping']['effects']['sequence']['mapping']['weight']['type'] = 'integer';
-    $expected['mapping']['effects']['sequence']['mapping']['uuid']['type'] = 'string';
-    $expected['mapping']['third_party_settings']['type'] = 'sequence';
-    $expected['mapping']['third_party_settings']['label'] = 'Third party settings';
-    $expected['mapping']['third_party_settings']['sequence']['type'] = '[%parent.%parent.%type].third_party.[%key]';
-    $expected['mapping']['_core']['type'] = '_core_config_info';
-    $expected['type'] = 'image.style.*';
-
-    $this->assertEqual($definition, $expected);
-
-    // More complex, type based on a complex one.
-    $definition = \Drupal::service('config.typed')->getDefinition('image.effect.image_scale');
-    // This should be the schema for image.effect.image_scale.
-    $expected = array();
-    $expected['label'] = 'Image scale';
-    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
-    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
-    $expected['mapping']['width']['type'] = 'integer';
-    $expected['mapping']['width']['label'] = 'Width';
-    $expected['mapping']['height']['type'] = 'integer';
-    $expected['mapping']['height']['label'] = 'Height';
-    $expected['mapping']['upscale']['type'] = 'boolean';
-    $expected['mapping']['upscale']['label'] = 'Upscale';
-    $expected['type'] = 'image.effect.image_scale';
-
-
-    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for image.effect.image_scale');
-
-    // Most complex case, get metadata for actual configuration element.
-    $effects = \Drupal::service('config.typed')->get('image.style.medium')->get('effects');
-    $definition = $effects->get('bddf0d06-42f9-4c75-a700-a33cafa25ea0')->get('data')->getDataDefinition()->toArray();
-    // This should be the schema for image.effect.image_scale, reuse previous one.
-    $expected['type'] =  'image.effect.image_scale';
-
-    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for the first effect of image.style.medium');
-
-    $a = \Drupal::config('config_test.dynamic.third_party');
-    $test = \Drupal::service('config.typed')->get('config_test.dynamic.third_party')->get('third_party_settings.config_schema_test');
-    $definition = $test->getDataDefinition()->toArray();
-    $expected = array();
-    $expected['type'] = 'config_test.dynamic.*.third_party.config_schema_test';
-    $expected['label'] = 'Mapping';
-    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
-    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
-    $expected['mapping'] = [
-      'integer' => ['type' => 'integer'],
-      'string' => ['type' => 'string'],
-    ];
-    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_test.dynamic.third_party:third_party_settings.config_schema_test');
-
-    // More complex, several level deep test.
-    $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.someschema.somemodule.section_one.subsection');
-    // This should be the schema of config_schema_test.someschema.somemodule.*.*.
-    $expected = array();
-    $expected['label'] = 'Schema multiple filesystem marker test';
-    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
-    $expected['mapping']['langcode']['type'] = 'string';
-    $expected['mapping']['langcode']['label'] = 'Language code';
-    $expected['mapping']['_core']['type'] = '_core_config_info';
-    $expected['mapping']['testid']['type'] = 'string';
-    $expected['mapping']['testid']['label'] = 'ID';
-    $expected['mapping']['testdescription']['type'] = 'text';
-    $expected['mapping']['testdescription']['label'] = 'Description';
-    $expected['type'] = 'config_schema_test.someschema.somemodule.*.*';
-    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
-
-    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_schema_test.someschema.somemodule.section_one.subsection');
-
-    $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.someschema.somemodule.section_two.subsection');
-    // The other file should have the same schema.
-    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_schema_test.someschema.somemodule.section_two.subsection');
-  }
-
-  /**
-   * Tests metadata retrieval with several levels of %parent indirection.
-   */
-  function testSchemaMappingWithParents() {
-    $config_data = \Drupal::service('config.typed')->get('config_schema_test.someschema.with_parents');
-
-    // Test fetching parent one level up.
-    $entry = $config_data->get('one_level');
-    $definition = $entry->get('testitem')->getDataDefinition()->toArray();
-    $expected = array(
-      'type' => 'config_schema_test.someschema.with_parents.key_1',
-      'label' => 'Test item nested one level',
-      'class' => '\Drupal\Core\TypedData\Plugin\DataType\StringData',
-      'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
-    );
-    $this->assertEqual($definition, $expected);
-
-    // Test fetching parent two levels up.
-    $entry = $config_data->get('two_levels');
-    $definition = $entry->get('wrapper')->get('testitem')->getDataDefinition()->toArray();
-    $expected = array(
-      'type' => 'config_schema_test.someschema.with_parents.key_2',
-      'label' => 'Test item nested two levels',
-      'class' => '\Drupal\Core\TypedData\Plugin\DataType\StringData',
-      'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
-    );
-    $this->assertEqual($definition, $expected);
-
-    // Test fetching parent three levels up.
-    $entry = $config_data->get('three_levels');
-    $definition = $entry->get('wrapper_1')->get('wrapper_2')->get('testitem')->getDataDefinition()->toArray();
-    $expected = array(
-      'type' => 'config_schema_test.someschema.with_parents.key_3',
-      'label' => 'Test item nested three levels',
-      'class' => '\Drupal\Core\TypedData\Plugin\DataType\StringData',
-      'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
-    );
-    $this->assertEqual($definition, $expected);
-  }
-
-  /**
-   * Tests metadata applied to configuration objects.
-   */
-  function testSchemaData() {
-    // Try a simple property.
-    $meta = \Drupal::service('config.typed')->get('system.site');
-    $property = $meta->get('page')->get('front');
-    $this->assertTrue($property instanceof StringInterface, 'Got the right wrapper fo the page.front property.');
-    $this->assertEqual($property->getValue(), '/user/login', 'Got the right value for page.front data.');
-    $definition = $property->getDataDefinition();
-    $this->assertTrue(empty($definition['translatable']), 'Got the right translatability setting for page.front data.');
-
-    // Check nested array of properties.
-    $list = $meta->get('page')->getElements();
-    $this->assertEqual(count($list), 3, 'Got a list with the right number of properties for site page data');
-    $this->assertTrue(isset($list['front']) && isset($list['403']) && isset($list['404']), 'Got a list with the right properties for site page data.');
-    $this->assertEqual($list['front']->getValue(), '/user/login', 'Got the right value for page.front data from the list.');
-
-    // And test some TypedConfigInterface methods.
-    $properties = $list;
-    $this->assertTrue(count($properties) == 3 && $properties['front'] == $list['front'], 'Got the right properties for site page.');
-    $values = $meta->get('page')->toArray();
-    $this->assertTrue(count($values) == 3 && $values['front'] == '/user/login', 'Got the right property values for site page.');
-
-    // Now let's try something more complex, with nested objects.
-    $wrapper = \Drupal::service('config.typed')->get('image.style.large');
-    $effects = $wrapper->get('effects');
-    $this->assertTrue(count($effects->toArray()) == 1, 'Got an array with effects for image.style.large data');
-    $uuid = key($effects->getValue());
-    $effect = $effects->get($uuid)->getElements();
-    $this->assertTrue(!$effect['data']->isEmpty() && $effect['id']->getValue() == 'image_scale', 'Got data for the image scale effect from metadata.');
-    $this->assertTrue($effect['data']->get('width') instanceof IntegerInterface, 'Got the right type for the scale effect width.');
-    $this->assertEqual($effect['data']->get('width')->getValue(), 480, 'Got the right value for the scale effect width.' );
-  }
-
-  /**
-   * Test configuration value data type enforcement using schemas.
-   */
-  public function testConfigSaveWithSchema() {
-    $untyped_values = array(
-      'string' => 1,
-      'empty_string' => '',
-      'null_string' => NULL,
-      'integer' => '100',
-      'null_integer' => '',
-      'boolean' => 1,
-      // If the config schema doesn't have a type it shouldn't be casted.
-      'no_type' => 1,
-      'mapping' => array(
-        'string' => 1
-      ),
-      'float' => '3.14',
-      'null_float' => '',
-      'sequence' => array (1, 0, 1),
-      'sequence_bc' => array(1, 0, 1),
-      // Not in schema and therefore should be left untouched.
-      'not_present_in_schema' => TRUE,
-      // Test a custom type.
-      'config_schema_test_integer' => '1',
-      'config_schema_test_integer_empty_string' => '',
-    );
-    $untyped_to_typed = $untyped_values;
-
-    $typed_values = array(
-      'string' => '1',
-      'empty_string' => '',
-      'null_string' => NULL,
-      'integer' => 100,
-      'null_integer' => NULL,
-      'boolean' => TRUE,
-      'no_type' => 1,
-      'mapping' => array(
-        'string' => '1'
-      ),
-      'float' => 3.14,
-      'null_float' => NULL,
-      'sequence' => array (TRUE, FALSE, TRUE),
-      'sequence_bc' => array(TRUE, FALSE, TRUE),
-      'not_present_in_schema' => TRUE,
-      'config_schema_test_integer' => 1,
-      'config_schema_test_integer_empty_string' => NULL,
-    );
-
-    // Save config which has a schema that enforces types.
-    $this->config('config_schema_test.schema_data_types')
-      ->setData($untyped_to_typed)
-      ->save();
-    $this->assertIdentical($this->config('config_schema_test.schema_data_types')->get(), $typed_values);
-
-    // Save config which does not have a schema that enforces types.
-    $this->config('config_schema_test.no_schema_data_types')
-      ->setData($untyped_values)
-      ->save();
-    $this->assertIdentical($this->config('config_schema_test.no_schema_data_types')->get(), $untyped_values);
-
-    // Ensure that configuration objects with keys marked as ignored are not
-    // changed when saved. The 'config_schema_test.ignore' will have been saved
-    // during the installation of configuration in the setUp method.
-    $extension_path = drupal_get_path('module', 'config_schema_test');
-    $install_storage = new FileStorage($extension_path . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY);
-    $original_data = $install_storage->read('config_schema_test.ignore');
-    $installed_data = $this->config('config_schema_test.ignore')->get();
-    unset($installed_data['_core']);
-    $this->assertIdentical($installed_data, $original_data);
-  }
-
-  /**
-   * Tests fallback to a greedy wildcard.
-   */
-  function testSchemaFallback() {
-    $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.wildcard_fallback.something');
-    // This should be the schema of config_schema_test.wildcard_fallback.*.
-    $expected = array();
-    $expected['label'] = 'Schema wildcard fallback test';
-    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
-    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
-    $expected['mapping']['langcode']['type'] = 'string';
-    $expected['mapping']['langcode']['label'] = 'Language code';
-    $expected['mapping']['_core']['type'] = '_core_config_info';
-    $expected['mapping']['testid']['type'] = 'string';
-    $expected['mapping']['testid']['label'] = 'ID';
-    $expected['mapping']['testdescription']['type'] = 'text';
-    $expected['mapping']['testdescription']['label'] = 'Description';
-    $expected['type'] = 'config_schema_test.wildcard_fallback.*';
-
-    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_schema_test.wildcard_fallback.something');
-
-    $definition2 = \Drupal::service('config.typed')->getDefinition('config_schema_test.wildcard_fallback.something.something');
-    // This should be the schema of config_schema_test.wildcard_fallback.* as
-    //well.
-    $this->assertIdentical($definition, $definition2);
-  }
-
-  /**
-   * Tests use of colons in schema type determination.
-   *
-   * @see \Drupal\Core\Config\TypedConfigManager::getFallbackName()
-   */
-  function testColonsInSchemaTypeDetermination() {
-    $tests = \Drupal::service('config.typed')->get('config_schema_test.plugin_types')->get('tests')->getElements();
-    $definition = $tests[0]->getDataDefinition()->toArray();
-    $this->assertEqual($definition['type'], 'test.plugin_types.boolean');
-
-    $definition = $tests[1]->getDataDefinition()->toArray();
-    $this->assertEqual($definition['type'], 'test.plugin_types.boolean:*');
-
-    $definition = $tests[2]->getDataDefinition()->toArray();
-    $this->assertEqual($definition['type'], 'test.plugin_types.*');
-
-    $definition = $tests[3]->getDataDefinition()->toArray();
-    $this->assertEqual($definition['type'], 'test.plugin_types.*');
-
-    $tests = \Drupal::service('config.typed')->get('config_schema_test.plugin_types')->get('test_with_parents')->getElements();
-    $definition = $tests[0]->get('settings')->getDataDefinition()->toArray();
-    $this->assertEqual($definition['type'], 'test_with_parents.plugin_types.boolean');
-
-    $definition = $tests[1]->get('settings')->getDataDefinition()->toArray();
-    $this->assertEqual($definition['type'], 'test_with_parents.plugin_types.boolean:*');
-
-    $definition = $tests[2]->get('settings')->getDataDefinition()->toArray();
-    $this->assertEqual($definition['type'], 'test_with_parents.plugin_types.*');
-
-    $definition = $tests[3]->get('settings')->getDataDefinition()->toArray();
-    $this->assertEqual($definition['type'], 'test_with_parents.plugin_types.*');
-  }
-
-  /**
-   * Tests hook_config_schema_info_alter().
-   */
-  public function testConfigSchemaInfoAlter() {
-    /** @var \Drupal\Core\Config\TypedConfigManagerInterface $typed_config */
-    $typed_config = \Drupal::service('config.typed');
-    $typed_config->clearCachedDefinitions();
-
-    // Ensure that keys can not be added or removed by
-    // hook_config_schema_info_alter().
-    \Drupal::state()->set('config_schema_test_exception_remove', TRUE);
-    $message = 'Expected ConfigSchemaAlterException thrown.';
-    try {
-      $typed_config->getDefinitions();
-      $this->fail($message);
-    }
-    catch (ConfigSchemaAlterException $e) {
-      $this->pass($message);
-      $this->assertEqual($e->getMessage(), 'Invoking hook_config_schema_info_alter() has removed (config_schema_test.hook) schema definitions');
-    }
-
-    \Drupal::state()->set('config_schema_test_exception_add', TRUE);
-    $message = 'Expected ConfigSchemaAlterException thrown.';
-    try {
-      $typed_config->getDefinitions();
-      $this->fail($message);
-    }
-    catch (ConfigSchemaAlterException $e) {
-      $this->pass($message);
-      $this->assertEqual($e->getMessage(), 'Invoking hook_config_schema_info_alter() has added (config_schema_test.hook_added_defintion) and removed (config_schema_test.hook) schema definitions');
-    }
-
-    \Drupal::state()->set('config_schema_test_exception_remove', FALSE);
-    $message = 'Expected ConfigSchemaAlterException thrown.';
-    try {
-      $typed_config->getDefinitions();
-      $this->fail($message);
-    }
-    catch (ConfigSchemaAlterException $e) {
-      $this->pass($message);
-      $this->assertEqual($e->getMessage(), 'Invoking hook_config_schema_info_alter() has added (config_schema_test.hook_added_defintion) schema definitions');
-    }
-
-    // Tests that hook_config_schema_info_alter() can add additional metadata to
-    // existing configuration schema.
-    \Drupal::state()->set('config_schema_test_exception_add', FALSE);
-    $definitions = $typed_config->getDefinitions();
-    $this->assertEqual($definitions['config_schema_test.hook']['additional_metadata'], 'new schema info');
-  }
-
-  /**
-   * Tests saving config when the type is wrapped by a dynamic type.
-   */
-  public function testConfigSaveWithWrappingSchema() {
-    $untyped_values = [
-      'tests' => [
-        [
-          'wrapper_value' => 'foo',
-          'plugin_id' => 'wrapper:foo',
-          'internal_value' => 100,
-        ],
-      ],
-    ];
-
-    $typed_values = [
-      'tests' => [
-        [
-          'wrapper_value' => 'foo',
-          'plugin_id' => 'wrapper:foo',
-          'internal_value' => '100',
-        ],
-      ],
-    ];
-
-    // Save config which has a schema that enforces types.
-    \Drupal::configFactory()->getEditable('wrapping.config_schema_test.plugin_types')
-      ->setData($untyped_values)
-      ->save();
-    $this->assertIdentical(\Drupal::config('wrapping.config_schema_test.plugin_types')
-      ->get(), $typed_values);
-  }
-
-  /**
-   * Tests dynamic config schema type with multiple sub-key references.
-   */
-  public function testConfigSaveWithWrappingSchemaDoubleBrackets() {
-    $untyped_values = [
-      'tests' => [
-        [
-          'wrapper_value' => 'foo',
-          'foo' => 'cat',
-          'bar' => 'dog',
-          'another_key' => 100,
-        ],
-      ],
-    ];
-
-    $typed_values = [
-      'tests' => [
-        [
-          'wrapper_value' => 'foo',
-          'foo' => 'cat',
-          'bar' => 'dog',
-          'another_key' => '100',
-        ],
-      ],
-    ];
-
-    // Save config which has a schema that enforces types.
-    \Drupal::configFactory()->getEditable('wrapping.config_schema_test.double_brackets')
-      ->setData($untyped_values)
-      ->save();
-    $this->assertIdentical(\Drupal::config('wrapping.config_schema_test.double_brackets')
-      ->get(), $typed_values);
-  }
-
-}
diff --git a/core/modules/config/src/Tests/ConfigSnapshotTest.php b/core/modules/config/src/Tests/ConfigSnapshotTest.php
deleted file mode 100644
index cbb67b7..0000000
--- a/core/modules/config/src/Tests/ConfigSnapshotTest.php
+++ /dev/null
@@ -1,91 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\config\Tests\ConfigSnapshotTest.
- */
-
-namespace Drupal\config\Tests;
-
-use Drupal\Core\Config\StorageComparer;
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests config snapshot creation and updating.
- *
- * @group config
- */
-class ConfigSnapshotTest extends KernelTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('config_test', 'system');
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    // Update the config snapshot. This allows the parent::setUp() to write
-    // configuration files.
-    \Drupal::service('config.manager')->createSnapshot(\Drupal::service('config.storage'), \Drupal::service('config.storage.snapshot'));
-    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
-  }
-
-  /**
-   * Tests config snapshot creation and updating.
-   */
-  function testSnapshot() {
-    $active = $this->container->get('config.storage');
-    $sync = $this->container->get('config.storage.sync');
-    $snapshot = $this->container->get('config.storage.snapshot');
-    $config_manager = $this->container->get('config.manager');
-    $config_name = 'config_test.system';
-    $config_key = 'foo';
-    $new_data = 'foobar';
-
-    $active_snapshot_comparer = new StorageComparer($active, $snapshot, $config_manager);
-    $sync_snapshot_comparer = new StorageComparer($sync, $snapshot, $config_manager);
-
-    // Verify that we have an initial snapshot that matches the active
-    // configuration. This has to be true as no config should be installed.
-    $this->assertFalse($active_snapshot_comparer->createChangelist()->hasChanges());
-
-    // Install the default config.
-    $this->installConfig(array('config_test'));
-    // Although we have imported config this has not affected the snapshot.
-    $this->assertTrue($active_snapshot_comparer->reset()->hasChanges());
-
-    // Update the config snapshot.
-    \Drupal::service('config.manager')->createSnapshot($active, $snapshot);
-
-    // The snapshot and active config should now contain the same config
-    // objects.
-    $this->assertFalse($active_snapshot_comparer->reset()->hasChanges());
-
-    // Change a configuration value in sync.
-    $sync_data = $this->config($config_name)->get();
-    $sync_data[$config_key] = $new_data;
-    $sync->write($config_name, $sync_data);
-
-    // Verify that active and snapshot match, and that sync doesn't match
-    // active.
-    $this->assertFalse($active_snapshot_comparer->reset()->hasChanges());
-    $this->assertTrue($sync_snapshot_comparer->createChangelist()->hasChanges());
-
-    // Import changed data from sync to active.
-    $this->configImporter()->import();
-
-    // Verify changed config was properly imported.
-    \Drupal::configFactory()->reset($config_name);
-    $this->assertIdentical($this->config($config_name)->get($config_key), $new_data);
-
-    // Verify that a new snapshot was created which and that it matches
-    // the active config.
-    $this->assertFalse($active_snapshot_comparer->reset()->hasChanges());
-  }
-
-}
diff --git a/core/modules/config/src/Tests/DefaultConfigTest.php b/core/modules/config/src/Tests/DefaultConfigTest.php
deleted file mode 100644
index 2610c3d..0000000
--- a/core/modules/config/src/Tests/DefaultConfigTest.php
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\config\Tests\DefaultConfigTest.
- */
-
-namespace Drupal\config\Tests;
-
-use Drupal\config_test\TestInstallStorage;
-use Drupal\Core\Config\InstallStorage;
-use Drupal\Core\DependencyInjection\ContainerBuilder;
-use Drupal\simpletest\KernelTestBase;
-use Symfony\Component\DependencyInjection\Reference;
-
-/**
- * Tests that default configuration provided by all modules matches schema.
- *
- * @group config
- */
-class DefaultConfigTest extends KernelTestBase {
-
-  use SchemaCheckTestTrait;
-
-  /**
-   * Modules to enable.
-   *
-   * Enable the system module so that system_config_schema_info_alter() fires.
-   *
-   * @var array
-   */
-  public static $modules = array('system', 'config_test');
-
-  /**
-   * Themes which provide default configuration and need enabling.
-   *
-   * If a theme provides default configuration but does not have a schema
-   * because it can rely on schemas added by system_config_schema_info_alter()
-   * then this test needs to enable it.
-   *
-   * @var array
-   */
-  protected $themes = ['seven'];
-
-  protected function setUp() {
-    parent::setUp();
-    \Drupal::service('theme_handler')->install($this->themes);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function containerBuild(ContainerBuilder $container) {
-    parent::containerBuild($container);
-    $container->register('default_config_test.schema_storage')
-      ->setClass('\Drupal\config_test\TestInstallStorage')
-      ->addArgument(InstallStorage::CONFIG_SCHEMA_DIRECTORY);
-
-    $definition = $container->getDefinition('config.typed');
-    $definition->replaceArgument(1, new Reference('default_config_test.schema_storage'));
-  }
-
-  /**
-   * Tests default configuration data type.
-   */
-  public function testDefaultConfig() {
-    $typed_config = \Drupal::service('config.typed');
-    // Create a configuration storage with access to default configuration in
-    // every module, profile and theme.
-    $default_config_storage = new TestInstallStorage();
-
-    foreach ($default_config_storage->listAll() as $config_name) {
-      // Skip files provided by the config_schema_test module since that module
-      // is explicitly for testing schema.
-      if (strpos($config_name, 'config_schema_test') === 0) {
-        continue;
-      }
-
-      $data = $default_config_storage->read($config_name);
-      $this->assertConfigSchema($typed_config, $config_name, $data);
-    }
-  }
-
-}
diff --git a/core/modules/config/src/Tests/SchemaCheckTraitTest.php b/core/modules/config/src/Tests/SchemaCheckTraitTest.php
deleted file mode 100644
index 25d150d..0000000
--- a/core/modules/config/src/Tests/SchemaCheckTraitTest.php
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\config\Tests\SchemaCheckTraitTest.
- */
-
-namespace Drupal\config\Tests;
-
-use Drupal\Core\Config\Schema\SchemaCheckTrait;
-use Drupal\simpletest\KernelTestBase;
-
-
-/**
- * Tests the functionality of SchemaCheckTrait.
- *
- * @group config
- */
-class SchemaCheckTraitTest extends KernelTestBase {
-
-  use SchemaCheckTrait;
-
-  /**
-   * The typed config manager.
-   *
-   * @var \Drupal\Core\Config\TypedConfigManagerInterface
-   */
-  protected $typedConfig;
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('config_test', 'config_schema_test');
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->installConfig(array('config_test', 'config_schema_test'));
-    $this->typedConfig = \Drupal::service('config.typed');
-  }
-
-  /**
-   * Tests \Drupal\Core\Config\Schema\SchemaCheckTrait.
-   */
-  public function testTrait() {
-    // Test a non existing schema.
-    $ret = $this->checkConfigSchema($this->typedConfig, 'config_schema_test.noschema', $this->config('config_schema_test.noschema')->get());
-    $this->assertIdentical($ret, FALSE);
-
-    // Test an existing schema with valid data.
-    $config_data = $this->config('config_test.types')->get();
-    $ret = $this->checkConfigSchema($this->typedConfig, 'config_test.types', $config_data);
-    $this->assertIdentical($ret, TRUE);
-
-    // Add a new key, a new array and overwrite boolean with array to test the
-    // error messages.
-    $config_data = array('new_key' => 'new_value', 'new_array' => array()) + $config_data;
-    $config_data['boolean'] = array();
-    $ret = $this->checkConfigSchema($this->typedConfig, 'config_test.types', $config_data);
-    $expected = array(
-      'config_test.types:new_key' => 'missing schema',
-      'config_test.types:new_array' => 'missing schema',
-      'config_test.types:boolean' => 'non-scalar value but not defined as an array (such as mapping or sequence)',
-    );
-    $this->assertEqual($ret, $expected);
-  }
-
-}
diff --git a/core/modules/config/tests/src/Kernel/CacheabilityMetadataConfigOverrideTest.php b/core/modules/config/tests/src/Kernel/CacheabilityMetadataConfigOverrideTest.php
new file mode 100644
index 0000000..e9dd644
--- /dev/null
+++ b/core/modules/config/tests/src/Kernel/CacheabilityMetadataConfigOverrideTest.php
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\CacheabilityMetadataConfigOverrideTest.
+ */
+
+namespace Drupal\Tests\config\Kernel;
+
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\config_override_test\Cache\PirateDayCacheContext;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests if configuration overrides correctly affect cacheability metadata.
+ *
+ * @group config
+ */
+class CacheabilityMetadataConfigOverrideTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'block',
+    'block_content',
+    'config',
+    'config_override_test',
+    'system',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->installEntitySchema('block_content');
+    $this->installConfig(['config_override_test']);
+  }
+
+  /**
+   * Tests if config overrides correctly set cacheability metadata.
+   */
+  public function testConfigOverride() {
+    // It's pirate day today!
+    $GLOBALS['it_is_pirate_day'] = TRUE;
+
+    $config_factory = $this->container->get('config.factory');
+    $config = $config_factory->get('system.theme');
+
+    // Check that we are using the Pirate theme.
+    $theme = $config->get('default');
+    $this->assertEqual('pirate', $theme);
+
+    // Check that the cacheability metadata is correct.
+    $this->assertEqual(['pirate_day'], $config->getCacheContexts());
+    $this->assertEqual(['config:system.theme', 'pirate-day-tag'], $config->getCacheTags());
+    $this->assertEqual(PirateDayCacheContext::PIRATE_DAY_MAX_AGE, $config->getCacheMaxAge());
+  }
+
+  /**
+   * Tests if config overrides set cacheability metadata on config entities.
+   */
+  public function testConfigEntityOverride() {
+    // It's pirate day today!
+    $GLOBALS['it_is_pirate_day'] = TRUE;
+
+    // Load the User login block and check that its cacheability metadata is
+    // overridden correctly. This verifies that the metadata is correctly
+    // applied to config entities.
+    /** @var EntityManagerInterface $entity_manager */
+    $entity_manager = $this->container->get('entity.manager');
+    $block = $entity_manager->getStorage('block')->load('call_to_action');
+
+    // Check that our call to action message is appealing to filibusters.
+    $this->assertEqual($block->label(), 'Draw yer cutlasses!');
+
+    // Check that the cacheability metadata is correct.
+    $this->assertEqual(['pirate_day'], $block->getCacheContexts());
+    $this->assertEqual(['config:block.block.call_to_action', 'pirate-day-tag'], $block->getCacheTags());
+    $this->assertEqual(PirateDayCacheContext::PIRATE_DAY_MAX_AGE, $block->getCacheMaxAge());
+
+    // Check that duplicating a config entity does not have the original config
+    // entity's cache tag.
+    $this->assertEqual(['config:block.block.', 'pirate-day-tag'], $block->createDuplicate()->getCacheTags());
+
+    // Check that renaming a config entity does not have the original config
+    // entity's cache tag.
+    $block->set('id', 'call_to_looting')->save();
+    $this->assertEqual(['pirate_day'], $block->getCacheContexts());
+    $this->assertEqual(['config:block.block.call_to_looting', 'pirate-day-tag'], $block->getCacheTags());
+    $this->assertEqual(PirateDayCacheContext::PIRATE_DAY_MAX_AGE, $block->getCacheMaxAge());
+  }
+
+}
diff --git a/core/modules/config/tests/src/Kernel/ConfigEntityNormalizeTest.php b/core/modules/config/tests/src/Kernel/ConfigEntityNormalizeTest.php
new file mode 100644
index 0000000..0e98c20
--- /dev/null
+++ b/core/modules/config/tests/src/Kernel/ConfigEntityNormalizeTest.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\ConfigEntityNormalizeTest.
+ */
+
+namespace Drupal\Tests\config\Kernel;
+
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests the listing of configuration entities.
+ *
+ * @group config
+ */
+class ConfigEntityNormalizeTest extends KernelTestBase {
+
+  /**
+   * Modules to install.
+   *
+   * @var array
+   */
+  public static $modules = array('config_test');
+
+  protected function setUp() {
+    parent::setUp();
+    $this->installConfig(static::$modules);
+  }
+
+  public function testNormalize() {
+    $config_entity = entity_create('config_test', array('id' => 'system', 'label' => 'foobar', 'weight' => 1));
+    $config_entity->save();
+
+    // Modify stored config entity, this is comparable with a schema change.
+    $config = $this->config('config_test.dynamic.system');
+    $data = array(
+      'label' => 'foobar',
+      'additional_key' => TRUE
+    ) + $config->getRawData();
+    $config->setData($data)->save();
+    $this->assertNotIdentical($config_entity->toArray(), $config->getRawData(), 'Stored config entity is not is equivalent to config schema.');
+
+    $config_entity = entity_load('config_test', 'system', TRUE);
+    $config_entity->save();
+
+    $config = $this->config('config_test.dynamic.system');
+    $this->assertIdentical($config_entity->toArray(), $config->getRawData(), 'Stored config entity is equivalent to config schema.');
+  }
+
+}
diff --git a/core/modules/config/tests/src/Kernel/ConfigEntityStaticCacheTest.php b/core/modules/config/tests/src/Kernel/ConfigEntityStaticCacheTest.php
new file mode 100644
index 0000000..7d0929e
--- /dev/null
+++ b/core/modules/config/tests/src/Kernel/ConfigEntityStaticCacheTest.php
@@ -0,0 +1,110 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\ConfigEntityStaticCacheTest.
+ */
+
+namespace Drupal\Tests\config\Kernel;
+
+use Drupal\config_entity_static_cache_test\ConfigOverrider;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests the entity static cache when used by config entities.
+ *
+ * @group config
+ */
+class ConfigEntityStaticCacheTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('config_test', 'config_entity_static_cache_test');
+
+  /**
+   * The type ID of the entity under test.
+   *
+   * @var string
+   */
+  protected $entityTypeId;
+
+  /**
+   * The entity ID of the entity under test.
+   *
+   * @var string
+   */
+  protected $entityId;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->entityTypeId = 'config_test';
+    $this->entityId = 'test_1';
+    entity_create($this->entityTypeId, array('id' => $this->entityId, 'label' => 'Original label'))->save();
+  }
+
+  /**
+   * Tests that the static cache is working.
+   */
+  public function testCacheHit() {
+    $entity_1 = entity_load($this->entityTypeId, $this->entityId);
+    $entity_2 = entity_load($this->entityTypeId, $this->entityId);
+    // config_entity_static_cache_test_config_test_load() sets _loadStamp to a
+    // random string. If they match, it means $entity_2 was retrieved from the
+    // static cache rather than going through a separate load sequence.
+    $this->assertIdentical($entity_1->_loadStamp, $entity_2->_loadStamp);
+  }
+
+  /**
+   * Tests that the static cache is reset on entity save and delete.
+   */
+  public function testReset() {
+    $entity = entity_load($this->entityTypeId, $this->entityId);
+
+    // Ensure loading after a save retrieves the updated entity rather than an
+    // obsolete cached one.
+    $entity->label = 'New label';
+    $entity->save();
+    $entity = entity_load($this->entityTypeId, $this->entityId);
+    $this->assertIdentical($entity->label, 'New label');
+
+    // Ensure loading after a delete retrieves NULL rather than an obsolete
+    // cached one.
+    $entity->delete();
+    $this->assertNull(entity_load($this->entityTypeId, $this->entityId));
+  }
+
+  /**
+   * Tests that the static cache is sensitive to config overrides.
+   */
+  public function testConfigOverride() {
+    /** @var \Drupal\Core\Config\Entity\ConfigEntityStorage $storage */
+    $storage = \Drupal::entityManager()->getStorage($this->entityTypeId);
+    // Prime the cache prior to adding a config override.
+    $storage->load($this->entityId);
+
+    // Add the config override, and ensure that what is loaded is correct
+    // despite the prior cache priming.
+    \Drupal::configFactory()->addOverride(new ConfigOverrider());
+    $entity_override = $storage->load($this->entityId);
+    $this->assertIdentical($entity_override->label, 'Overridden label');
+
+    // Load override free to ensure that loading the config entity again does
+    // not return the overridden value.
+    $entity_no_override = $storage->loadOverrideFree($this->entityId);
+    $this->assertNotIdentical($entity_no_override->label, 'Overridden label');
+    $this->assertNotIdentical($entity_override->_loadStamp, $entity_no_override->_loadStamp);
+
+    // Reload the entity and ensure the cache is used.
+    $this->assertIdentical($storage->loadOverrideFree($this->entityId)->_loadStamp, $entity_no_override->_loadStamp);
+
+    // Enable overrides and reload the entity and ensure the cache is used.
+    $this->assertIdentical($storage->load($this->entityId)->_loadStamp, $entity_override->_loadStamp);
+  }
+
+}
diff --git a/core/modules/config/tests/src/Kernel/ConfigEntityUnitTest.php b/core/modules/config/tests/src/Kernel/ConfigEntityUnitTest.php
new file mode 100644
index 0000000..23e2e36
--- /dev/null
+++ b/core/modules/config/tests/src/Kernel/ConfigEntityUnitTest.php
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\ConfigEntityUnitTest.
+ */
+
+namespace Drupal\Tests\config\Kernel;
+
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Unit tests for configuration entity base methods.
+ *
+ * @group config
+ */
+class ConfigEntityUnitTest extends KernelTestBase {
+
+  /**
+   * Exempt from strict schema checking.
+   *
+   * @see \Drupal\Core\Config\Testing\ConfigSchemaChecker
+   *
+   * @var bool
+   */
+  protected $strictConfigSchema = FALSE;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('config_test');
+
+  /**
+   * The config_test entity storage.
+   *
+   * @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
+   */
+  protected $storage;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->storage = $this->container->get('entity.manager')->getStorage('config_test');
+  }
+
+  /**
+   * Tests storage methods.
+   */
+  public function testStorageMethods() {
+    $entity_type = \Drupal::entityManager()->getDefinition('config_test');
+
+    // Test the static extractID() method.
+    $expected_id = 'test_id';
+    $config_name = $entity_type->getConfigPrefix() . '.' . $expected_id;
+    $storage = $this->storage;
+    $this->assertIdentical($storage::getIDFromConfigName($config_name, $entity_type->getConfigPrefix()), $expected_id);
+
+    // Create three entities, two with the same style.
+    $style = $this->randomMachineName(8);
+    for ($i = 0; $i < 2; $i++) {
+      $entity = $this->storage->create(array(
+        'id' => $this->randomMachineName(),
+        'label' => $this->randomString(),
+        'style' => $style,
+      ));
+      $entity->save();
+    }
+    $entity = $this->storage->create(array(
+      'id' => $this->randomMachineName(),
+      'label' => $this->randomString(),
+      // Use a different length for the entity to ensure uniqueness.
+      'style' => $this->randomMachineName(9),
+    ));
+    $entity->save();
+
+    // Ensure that the configuration entity can be loaded by UUID.
+    $entity_loaded_by_uuid = \Drupal::entityManager()->loadEntityByUuid($entity_type->id(), $entity->uuid());
+    if (!$entity_loaded_by_uuid) {
+      $this->fail(sprintf("Failed to load '%s' entity ID '%s' by UUID '%s'.", $entity_type->id(), $entity->id(), $entity->uuid()));
+    }
+    // Compare UUIDs as the objects are not identical since
+    // $entity->enforceIsNew is FALSE and $entity_loaded_by_uuid->enforceIsNew
+    // is NULL.
+    $this->assertIdentical($entity->uuid(), $entity_loaded_by_uuid->uuid());
+
+    $entities = $this->storage->loadByProperties();
+    $this->assertEqual(count($entities), 3, 'Three entities are loaded when no properties are specified.');
+
+    $entities = $this->storage->loadByProperties(array('style' => $style));
+    $this->assertEqual(count($entities), 2, 'Two entities are loaded when the style property is specified.');
+
+    // Assert that both returned entities have a matching style property.
+    foreach ($entities as $entity) {
+      $this->assertIdentical($entity->get('style'), $style, 'The loaded entity has the correct style value specified.');
+    }
+
+    // Test that schema type enforcement can be overridden by trusting the data.
+    $entity = $this->storage->create(array(
+      'id' => $this->randomMachineName(),
+      'label' => $this->randomString(),
+      'style' => 999
+    ));
+    $entity->save();
+    $this->assertIdentical('999', $entity->style);
+    $entity->style = 999;
+    $entity->trustData()->save();
+    $this->assertIdentical(999, $entity->style);
+    $entity->save();
+    $this->assertIdentical('999', $entity->style);
+  }
+
+}
diff --git a/core/modules/config/tests/src/Kernel/ConfigImportRecreateTest.php b/core/modules/config/tests/src/Kernel/ConfigImportRecreateTest.php
new file mode 100644
index 0000000..de01854
--- /dev/null
+++ b/core/modules/config/tests/src/Kernel/ConfigImportRecreateTest.php
@@ -0,0 +1,109 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\ConfigImportRecreateTest.
+ */
+
+namespace Drupal\Tests\config\Kernel;
+
+use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Config\ConfigImporter;
+use Drupal\Core\Config\StorageComparer;
+use Drupal\node\Entity\NodeType;
+
+/**
+ * Tests importing recreated configuration entities.
+ *
+ * @group config
+ */
+class ConfigImportRecreateTest extends KernelTestBase {
+
+  /**
+   * Config Importer object used for testing.
+   *
+   * @var \Drupal\Core\Config\ConfigImporter
+   */
+  protected $configImporter;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['system', 'field', 'text', 'user', 'node'];
+
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installEntitySchema('node');
+    $this->installConfig(array('field', 'node'));
+
+    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
+
+    // Set up the ConfigImporter object for testing.
+    $storage_comparer = new StorageComparer(
+      $this->container->get('config.storage.sync'),
+      $this->container->get('config.storage'),
+      $this->container->get('config.manager')
+    );
+    $this->configImporter = new ConfigImporter(
+      $storage_comparer->createChangelist(),
+      $this->container->get('event_dispatcher'),
+      $this->container->get('config.manager'),
+      $this->container->get('lock'),
+      $this->container->get('config.typed'),
+      $this->container->get('module_handler'),
+      $this->container->get('module_installer'),
+      $this->container->get('theme_handler'),
+      $this->container->get('string_translation')
+    );
+  }
+
+  public function testRecreateEntity() {
+    $type_name = Unicode::strtolower($this->randomMachineName(16));
+    $content_type = entity_create('node_type', array(
+      'type' => $type_name,
+      'name' => 'Node type one',
+    ));
+    $content_type->save();
+    node_add_body_field($content_type);
+    /** @var \Drupal\Core\Config\StorageInterface $active */
+    $active = $this->container->get('config.storage');
+    /** @var \Drupal\Core\Config\StorageInterface $sync */
+    $sync = $this->container->get('config.storage.sync');
+
+    $config_name = $content_type->getEntityType()->getConfigPrefix() . '.' . $content_type->id();
+    $this->copyConfig($active, $sync);
+
+    // Delete the content type. This will also delete a field storage, a field,
+    // an entity view display and an entity form display.
+    $content_type->delete();
+    $this->assertFalse($active->exists($config_name), 'Content type\'s old name does not exist active store.');
+    // Recreate with the same type - this will have a different UUID.
+    $content_type = entity_create('node_type', array(
+      'type' => $type_name,
+      'name' => 'Node type two',
+    ));
+    $content_type->save();
+    node_add_body_field($content_type);
+
+    $this->configImporter->reset();
+    // A node type, a field, an entity view display and an entity form display
+    // will be recreated.
+    $creates = $this->configImporter->getUnprocessedConfiguration('create');
+    $deletes = $this->configImporter->getUnprocessedConfiguration('delete');
+    $this->assertEqual(5, count($creates), 'There are 5 configuration items to create.');
+    $this->assertEqual(5, count($deletes), 'There are 5 configuration items to delete.');
+    $this->assertEqual(0, count($this->configImporter->getUnprocessedConfiguration('update')), 'There are no configuration items to update.');
+    $this->assertIdentical($creates, array_reverse($deletes), 'Deletes and creates contain the same configuration names in opposite orders due to dependencies.');
+
+    $this->configImporter->import();
+
+    // Verify that there is nothing more to import.
+    $this->assertFalse($this->configImporter->reset()->hasUnprocessedConfigurationChanges());
+    $content_type = NodeType::load($type_name);
+    $this->assertEqual('Node type one', $content_type->label());
+  }
+
+}
diff --git a/core/modules/config/tests/src/Kernel/ConfigImportRenameValidationTest.php b/core/modules/config/tests/src/Kernel/ConfigImportRenameValidationTest.php
new file mode 100644
index 0000000..0b93079
--- /dev/null
+++ b/core/modules/config/tests/src/Kernel/ConfigImportRenameValidationTest.php
@@ -0,0 +1,162 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\ConfigImportRenameValidationTest.
+ */
+
+namespace Drupal\Tests\config\Kernel;
+
+use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Component\Utility\Unicode;
+use Drupal\Component\Uuid\Php;
+use Drupal\Core\Config\ConfigImporter;
+use Drupal\Core\Config\ConfigImporterException;
+use Drupal\Core\Config\StorageComparer;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests validating renamed configuration in a configuration import.
+ *
+ * @group config
+ */
+class ConfigImportRenameValidationTest extends KernelTestBase {
+
+  /**
+   * Config Importer object used for testing.
+   *
+   * @var \Drupal\Core\Config\ConfigImporter
+   */
+  protected $configImporter;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['system', 'user', 'node', 'field', 'text', 'config_test'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installEntitySchema('user');
+    $this->installEntitySchema('node');
+    $this->installConfig(array('field'));
+
+    // Set up the ConfigImporter object for testing.
+    $storage_comparer = new StorageComparer(
+      $this->container->get('config.storage.sync'),
+      $this->container->get('config.storage'),
+      $this->container->get('config.manager')
+    );
+    $this->configImporter = new ConfigImporter(
+      $storage_comparer->createChangelist(),
+      $this->container->get('event_dispatcher'),
+      $this->container->get('config.manager'),
+      $this->container->get('lock.persistent'),
+      $this->container->get('config.typed'),
+      $this->container->get('module_handler'),
+      $this->container->get('module_installer'),
+      $this->container->get('theme_handler'),
+      $this->container->get('string_translation')
+    );
+  }
+
+  /**
+   * Tests configuration renaming validation.
+   */
+  public function testRenameValidation() {
+    // Create a test entity.
+    $test_entity_id = $this->randomMachineName();
+    $test_entity = entity_create('config_test', array(
+      'id' => $test_entity_id,
+      'label' => $this->randomMachineName(),
+    ));
+    $test_entity->save();
+    $uuid = $test_entity->uuid();
+
+    // Stage the test entity and then delete it from the active storage.
+    $active = $this->container->get('config.storage');
+    $sync = $this->container->get('config.storage.sync');
+    $this->copyConfig($active, $sync);
+    $test_entity->delete();
+
+    // Create a content type with a matching UUID in the active storage.
+    $content_type = entity_create('node_type', array(
+      'type' => Unicode::strtolower($this->randomMachineName(16)),
+      'name' => $this->randomMachineName(),
+      'uuid' => $uuid,
+    ));
+    $content_type->save();
+
+    // Confirm that the staged configuration is detected as a rename since the
+    // UUIDs match.
+    $this->configImporter->reset();
+    $expected = array(
+      'node.type.' . $content_type->id() . '::config_test.dynamic.' . $test_entity_id,
+    );
+    $renames = $this->configImporter->getUnprocessedConfiguration('rename');
+    $this->assertIdentical($expected, $renames);
+
+    // Try to import the configuration. We expect an exception to be thrown
+    // because the staged entity is of a different type.
+    try {
+      $this->configImporter->import();
+      $this->fail('Expected ConfigImporterException thrown when a renamed configuration entity does not match the existing entity type.');
+    }
+    catch (ConfigImporterException $e) {
+      $this->pass('Expected ConfigImporterException thrown when a renamed configuration entity does not match the existing entity type.');
+      $expected = array(
+        SafeMarkup::format('Entity type mismatch on rename. @old_type not equal to @new_type for existing configuration @old_name and staged configuration @new_name.', array('@old_type' => 'node_type', '@new_type' => 'config_test', '@old_name' => 'node.type.' . $content_type->id(), '@new_name' => 'config_test.dynamic.' . $test_entity_id))
+      );
+      $this->assertEqual($expected, $this->configImporter->getErrors());
+    }
+  }
+
+  /**
+   * Tests configuration renaming validation for simple configuration.
+   */
+  public function testRenameSimpleConfigValidation() {
+    $uuid = new Php();
+    // Create a simple configuration with a UUID.
+    $config = $this->config('config_test.new');
+    $uuid_value = $uuid->generate();
+    $config->set('uuid', $uuid_value)->save();
+
+    $active = $this->container->get('config.storage');
+    $sync = $this->container->get('config.storage.sync');
+    $this->copyConfig($active, $sync);
+    $config->delete();
+
+    // Create another simple configuration with the same UUID.
+    $config = $this->config('config_test.old');
+    $config->set('uuid', $uuid_value)->save();
+
+    // Confirm that the staged configuration is detected as a rename since the
+    // UUIDs match.
+    $this->configImporter->reset();
+    $expected = array(
+      'config_test.old::config_test.new'
+    );
+    $renames = $this->configImporter->getUnprocessedConfiguration('rename');
+    $this->assertIdentical($expected, $renames);
+
+    // Try to import the configuration. We expect an exception to be thrown
+    // because the rename is for simple configuration.
+    try {
+      $this->configImporter->import();
+      $this->fail('Expected ConfigImporterException thrown when simple configuration is renamed.');
+    }
+    catch (ConfigImporterException $e) {
+      $this->pass('Expected ConfigImporterException thrown when simple configuration is renamed.');
+      $expected = array(
+        SafeMarkup::format('Rename operation for simple configuration. Existing configuration @old_name and staged configuration @new_name.', array('@old_name' => 'config_test.old', '@new_name' => 'config_test.new'))
+      );
+      $this->assertEqual($expected, $this->configImporter->getErrors());
+    }
+  }
+
+}
diff --git a/core/modules/config/tests/src/Kernel/ConfigImporterMissingContentTest.php b/core/modules/config/tests/src/Kernel/ConfigImporterMissingContentTest.php
new file mode 100644
index 0000000..154ec89
--- /dev/null
+++ b/core/modules/config/tests/src/Kernel/ConfigImporterMissingContentTest.php
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\ConfigImporterMissingContentTest.
+ */
+
+namespace Drupal\Tests\config\Kernel;
+
+use Drupal\Core\Config\ConfigImporter;
+use Drupal\Core\Config\StorageComparer;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests importing configuration which has missing content dependencies.
+ *
+ * @group config
+ */
+class ConfigImporterMissingContentTest extends KernelTestBase {
+
+  /**
+   * Config Importer object used for testing.
+   *
+   * @var \Drupal\Core\Config\ConfigImporter
+   */
+  protected $configImporter;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('system', 'user', 'entity_test', 'config_test', 'config_import_test');
+
+  protected function setUp() {
+    parent::setUp();
+    $this->installSchema('system', 'sequences');
+    $this->installEntitySchema('entity_test');
+    $this->installEntitySchema('user');
+    $this->installConfig(array('config_test'));
+    // Installing config_test's default configuration pollutes the global
+    // variable being used for recording hook invocations by this test already,
+    // so it has to be cleared out manually.
+    unset($GLOBALS['hook_config_test']);
+
+    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
+
+    // Set up the ConfigImporter object for testing.
+    $storage_comparer = new StorageComparer(
+      $this->container->get('config.storage.sync'),
+      $this->container->get('config.storage'),
+      $this->container->get('config.manager')
+    );
+    $this->configImporter = new ConfigImporter(
+      $storage_comparer->createChangelist(),
+      $this->container->get('event_dispatcher'),
+      $this->container->get('config.manager'),
+      $this->container->get('lock'),
+      $this->container->get('config.typed'),
+      $this->container->get('module_handler'),
+      $this->container->get('module_installer'),
+      $this->container->get('theme_handler'),
+      $this->container->get('string_translation')
+    );
+  }
+
+  /**
+   * Tests the missing content event is fired.
+   *
+   * @see \Drupal\Core\Config\ConfigImporter::processMissingContent()
+   * @see \Drupal\config_import_test\EventSubscriber
+   */
+  function testMissingContent() {
+    \Drupal::state()->set('config_import_test.config_import_missing_content', TRUE);
+
+    // Update a configuration entity in the sync directory to have a dependency
+    // on two content entities that do not exist.
+    $storage = $this->container->get('config.storage');
+    $sync = $this->container->get('config.storage.sync');
+    $entity_one = entity_create('entity_test', array('name' => 'one'));
+    $entity_two = entity_create('entity_test', array('name' => 'two'));
+    $entity_three = entity_create('entity_test', array('name' => 'three'));
+    $dynamic_name = 'config_test.dynamic.dotted.default';
+    $original_dynamic_data = $storage->read($dynamic_name);
+    // Entity one will be resolved by
+    // \Drupal\config_import_test\EventSubscriber::onConfigImporterMissingContentOne().
+    $original_dynamic_data['dependencies']['content'][] = $entity_one->getConfigDependencyName();
+    // Entity two will be resolved by
+    // \Drupal\config_import_test\EventSubscriber::onConfigImporterMissingContentTwo().
+    $original_dynamic_data['dependencies']['content'][] = $entity_two->getConfigDependencyName();
+    // Entity three will be resolved by
+    // \Drupal\Core\Config\Importer\FinalMissingContentSubscriber.
+    $original_dynamic_data['dependencies']['content'][] = $entity_three->getConfigDependencyName();
+    $sync->write($dynamic_name, $original_dynamic_data);
+
+    // Import.
+    $this->configImporter->reset()->import();
+    $this->assertEqual([], $this->configImporter->getErrors(), 'There were no errors during the import.');
+    $this->assertEqual($entity_one->uuid(), \Drupal::state()->get('config_import_test.config_import_missing_content_one'), 'The missing content event is fired during configuration import.');
+    $this->assertEqual($entity_two->uuid(), \Drupal::state()->get('config_import_test.config_import_missing_content_two'), 'The missing content event is fired during configuration import.');
+    $original_dynamic_data = $storage->read($dynamic_name);
+    $this->assertEqual([$entity_one->getConfigDependencyName(), $entity_two->getConfigDependencyName(), $entity_three->getConfigDependencyName()], $original_dynamic_data['dependencies']['content'], 'The imported configuration entity has the missing content entity dependency.');
+  }
+
+}
diff --git a/core/modules/config/tests/src/Kernel/ConfigImporterTest.php b/core/modules/config/tests/src/Kernel/ConfigImporterTest.php
new file mode 100644
index 0000000..6df25fc
--- /dev/null
+++ b/core/modules/config/tests/src/Kernel/ConfigImporterTest.php
@@ -0,0 +1,693 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\ConfigImporterTest.
+ */
+
+namespace Drupal\Tests\config\Kernel;
+
+use Drupal\Component\Utility\Html;
+use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Config\ConfigImporter;
+use Drupal\Core\Config\ConfigImporterException;
+use Drupal\Core\Config\StorageComparer;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests importing configuration from files into active configuration.
+ *
+ * @group config
+ */
+class ConfigImporterTest extends KernelTestBase {
+
+  /**
+   * Config Importer object used for testing.
+   *
+   * @var \Drupal\Core\Config\ConfigImporter
+   */
+  protected $configImporter;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('config_test', 'system', 'config_import_test');
+
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installConfig(array('config_test'));
+    // Installing config_test's default configuration pollutes the global
+    // variable being used for recording hook invocations by this test already,
+    // so it has to be cleared out manually.
+    unset($GLOBALS['hook_config_test']);
+
+    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
+
+    // Set up the ConfigImporter object for testing.
+    $storage_comparer = new StorageComparer(
+      $this->container->get('config.storage.sync'),
+      $this->container->get('config.storage'),
+      $this->container->get('config.manager')
+    );
+    $this->configImporter = new ConfigImporter(
+      $storage_comparer->createChangelist(),
+      $this->container->get('event_dispatcher'),
+      $this->container->get('config.manager'),
+      $this->container->get('lock'),
+      $this->container->get('config.typed'),
+      $this->container->get('module_handler'),
+      $this->container->get('module_installer'),
+      $this->container->get('theme_handler'),
+      $this->container->get('string_translation')
+    );
+  }
+
+  /**
+   * Tests omission of module APIs for bare configuration operations.
+   */
+  function testNoImport() {
+    $dynamic_name = 'config_test.dynamic.dotted.default';
+
+    // Verify the default configuration values exist.
+    $config = $this->config($dynamic_name);
+    $this->assertIdentical($config->get('id'), 'dotted.default');
+
+    // Verify that a bare $this->config() does not involve module APIs.
+    $this->assertFalse(isset($GLOBALS['hook_config_test']));
+  }
+
+  /**
+   * Tests that trying to import from an empty sync configuration directory
+   * fails.
+   */
+  function testEmptyImportFails() {
+    try {
+      $this->container->get('config.storage.sync')->deleteAll();
+      $this->configImporter->reset()->import();
+      $this->fail('ConfigImporterException thrown, successfully stopping an empty import.');
+    }
+    catch (ConfigImporterException $e) {
+      $this->pass('ConfigImporterException thrown, successfully stopping an empty import.');
+    }
+  }
+
+  /**
+   * Tests verification of site UUID before importing configuration.
+   */
+  function testSiteUuidValidate() {
+    $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);
+    try {
+      $this->configImporter->reset()->import();
+      $this->fail('ConfigImporterException not thrown, invalid import was not stopped due to mis-matching site UUID.');
+    }
+    catch (ConfigImporterException $e) {
+      $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.');
+      $error_log = $this->configImporter->getErrors();
+      $expected = array('Site UUID in source storage does not match the target storage.');
+      $this->assertEqual($expected, $error_log);
+    }
+  }
+
+  /**
+   * Tests deletion of configuration during import.
+   */
+  function testDeleted() {
+    $dynamic_name = 'config_test.dynamic.dotted.default';
+    $storage = $this->container->get('config.storage');
+    $sync = $this->container->get('config.storage.sync');
+
+    // Verify the default configuration values exist.
+    $config = $this->config($dynamic_name);
+    $this->assertIdentical($config->get('id'), 'dotted.default');
+
+    // Delete the file from the sync directory.
+    $sync->delete($dynamic_name);
+
+    // Import.
+    $this->configImporter->reset()->import();
+
+    // Verify the file has been removed.
+    $this->assertIdentical($storage->read($dynamic_name), FALSE);
+
+    $config = $this->config($dynamic_name);
+    $this->assertIdentical($config->get('id'), NULL);
+
+    // Verify that appropriate module API hooks have been invoked.
+    $this->assertTrue(isset($GLOBALS['hook_config_test']['load']));
+    $this->assertFalse(isset($GLOBALS['hook_config_test']['presave']));
+    $this->assertFalse(isset($GLOBALS['hook_config_test']['insert']));
+    $this->assertFalse(isset($GLOBALS['hook_config_test']['update']));
+    $this->assertTrue(isset($GLOBALS['hook_config_test']['predelete']));
+    $this->assertTrue(isset($GLOBALS['hook_config_test']['delete']));
+
+    $this->assertFalse($this->configImporter->hasUnprocessedConfigurationChanges());
+    $logs = $this->configImporter->getErrors();
+    $this->assertEqual(count($logs), 0);
+  }
+
+  /**
+   * Tests creation of configuration during import.
+   */
+  function testNew() {
+    $dynamic_name = 'config_test.dynamic.new';
+    $storage = $this->container->get('config.storage');
+    $sync = $this->container->get('config.storage.sync');
+
+    // Verify the configuration to create does not exist yet.
+    $this->assertIdentical($storage->exists($dynamic_name), FALSE, $dynamic_name . ' not found.');
+
+    // Create new config entity.
+    $original_dynamic_data = array(
+      'uuid' => '30df59bd-7b03-4cf7-bb35-d42fc49f0651',
+      'langcode' => \Drupal::languageManager()->getDefaultLanguage()->getId(),
+      'status' => TRUE,
+      'dependencies' => array(),
+      '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.');
+
+    // Import.
+    $this->configImporter->reset()->import();
+
+    // Verify the values appeared.
+    $config = $this->config($dynamic_name);
+    $this->assertIdentical($config->get('label'), $original_dynamic_data['label']);
+
+    // Verify that appropriate module API hooks have been invoked.
+    $this->assertFalse(isset($GLOBALS['hook_config_test']['load']));
+    $this->assertTrue(isset($GLOBALS['hook_config_test']['presave']));
+    $this->assertTrue(isset($GLOBALS['hook_config_test']['insert']));
+    $this->assertFalse(isset($GLOBALS['hook_config_test']['update']));
+    $this->assertFalse(isset($GLOBALS['hook_config_test']['predelete']));
+    $this->assertFalse(isset($GLOBALS['hook_config_test']['delete']));
+
+    // Verify that hook_config_import_steps_alter() can add steps to
+    // configuration synchronization.
+    $this->assertTrue(isset($GLOBALS['hook_config_test']['config_import_steps_alter']));
+
+    // Verify that there is nothing more to import.
+    $this->assertFalse($this->configImporter->hasUnprocessedConfigurationChanges());
+    $logs = $this->configImporter->getErrors();
+    $this->assertEqual(count($logs), 0);
+  }
+
+  /**
+   * Tests that secondary writes are overwritten.
+   */
+  function testSecondaryWritePrimaryFirst() {
+    $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 = array(
+      'id' => 'primary',
+      'label' => 'Primary',
+      'weight' => 0,
+      'uuid' => $uuid->generate(),
+    );
+    $sync->write($name_primary, $values_primary);
+    $values_secondary = array(
+      'id' => 'secondary',
+      'label' => 'Secondary Sync',
+      'weight' => 0,
+      'uuid' => $uuid->generate(),
+      // Add a dependency on primary, to ensure that is synced first.
+      'dependencies' => array(
+        'config' => array($name_primary),
+      )
+    );
+    $sync->write($name_secondary, $values_secondary);
+
+    // Import.
+    $this->configImporter->reset()->import();
+
+    $entity_storage = \Drupal::entityManager()->getStorage('config_test');
+    $primary = $entity_storage->load('primary');
+    $this->assertEqual($primary->id(), 'primary');
+    $this->assertEqual($primary->uuid(), $values_primary['uuid']);
+    $this->assertEqual($primary->label(), $values_primary['label']);
+    $secondary = $entity_storage->load('secondary');
+    $this->assertEqual($secondary->id(), 'secondary');
+    $this->assertEqual($secondary->uuid(), $values_secondary['uuid']);
+    $this->assertEqual($secondary->label(), $values_secondary['label']);
+
+    $logs = $this->configImporter->getErrors();
+    $this->assertEqual(count($logs), 1);
+    $this->assertEqual($logs[0], SafeMarkup::format('Deleted and replaced configuration entity "@name"', array('@name' => $name_secondary)));
+  }
+
+  /**
+   * Tests that secondary writes are overwritten.
+   */
+  function testSecondaryWriteSecondaryFirst() {
+    $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 = array(
+      'id' => 'primary',
+      'label' => 'Primary',
+      'weight' => 0,
+      'uuid' => $uuid->generate(),
+      // Add a dependency on secondary, so that is synced first.
+      'dependencies' => array(
+        'config' => array($name_secondary),
+      )
+    );
+    $sync->write($name_primary, $values_primary);
+    $values_secondary = array(
+      'id' => 'secondary',
+      'label' => 'Secondary Sync',
+      'weight' => 0,
+      'uuid' => $uuid->generate(),
+    );
+    $sync->write($name_secondary, $values_secondary);
+
+    // Import.
+    $this->configImporter->reset()->import();
+
+    $entity_storage = \Drupal::entityManager()->getStorage('config_test');
+    $primary = $entity_storage->load('primary');
+    $this->assertEqual($primary->id(), 'primary');
+    $this->assertEqual($primary->uuid(), $values_primary['uuid']);
+    $this->assertEqual($primary->label(), $values_primary['label']);
+    $secondary = $entity_storage->load('secondary');
+    $this->assertEqual($secondary->id(), 'secondary');
+    $this->assertEqual($secondary->uuid(), $values_secondary['uuid']);
+    $this->assertEqual($secondary->label(), $values_secondary['label']);
+
+    $logs = $this->configImporter->getErrors();
+    $this->assertEqual(count($logs), 1);
+    $this->assertEqual($logs[0], Html::escape("Unexpected error during import with operation create for $name_primary: 'config_test' entity with ID 'secondary' already exists."));
+  }
+
+  /**
+   * Tests that secondary updates for deleted files work as expected.
+   */
+  function testSecondaryUpdateDeletedDeleterFirst() {
+    $name_deleter = 'config_test.dynamic.deleter';
+    $name_deletee = 'config_test.dynamic.deletee';
+    $name_other = 'config_test.dynamic.other';
+    $storage = $this->container->get('config.storage');
+    $sync = $this->container->get('config.storage.sync');
+    $uuid = $this->container->get('uuid');
+
+    $values_deleter = array(
+      'id' => 'deleter',
+      'label' => 'Deleter',
+      'weight' => 0,
+      'uuid' => $uuid->generate(),
+    );
+    $storage->write($name_deleter, $values_deleter);
+    $values_deleter['label'] = 'Updated Deleter';
+    $sync->write($name_deleter, $values_deleter);
+    $values_deletee = array(
+      'id' => 'deletee',
+      'label' => 'Deletee',
+      'weight' => 0,
+      'uuid' => $uuid->generate(),
+      // Add a dependency on deleter, to make sure that is synced first.
+      'dependencies' => array(
+        'config' => array($name_deleter),
+      )
+    );
+    $storage->write($name_deletee, $values_deletee);
+    $values_deletee['label'] = 'Updated Deletee';
+    $sync->write($name_deletee, $values_deletee);
+
+    // Ensure that import will continue after the error.
+    $values_other = array(
+      'id' => 'other',
+      'label' => 'Other',
+      'weight' => 0,
+      'uuid' => $uuid->generate(),
+      // Add a dependency on deleter, to make sure that is synced first. This
+      // will also be synced after the deletee due to alphabetical ordering.
+      'dependencies' => array(
+        'config' => array($name_deleter),
+      )
+    );
+    $storage->write($name_other, $values_other);
+    $values_other['label'] = 'Updated other';
+    $sync->write($name_other, $values_other);
+
+    // Check update changelist order.
+    $updates = $this->configImporter->reset()->getStorageComparer()->getChangelist('update');
+    $expected = array(
+      $name_deleter,
+      $name_deletee,
+      $name_other,
+    );
+    $this->assertIdentical($expected, $updates);
+
+    // Import.
+    $this->configImporter->import();
+
+    $entity_storage = \Drupal::entityManager()->getStorage('config_test');
+    $deleter = $entity_storage->load('deleter');
+    $this->assertEqual($deleter->id(), 'deleter');
+    $this->assertEqual($deleter->uuid(), $values_deleter['uuid']);
+    $this->assertEqual($deleter->label(), $values_deleter['label']);
+
+    // The deletee was deleted in
+    // \Drupal\config_test\Entity\ConfigTest::postSave().
+    $this->assertFalse($entity_storage->load('deletee'));
+
+    $other = $entity_storage->load('other');
+    $this->assertEqual($other->id(), 'other');
+    $this->assertEqual($other->uuid(), $values_other['uuid']);
+    $this->assertEqual($other->label(), $values_other['label']);
+
+    $logs = $this->configImporter->getErrors();
+    $this->assertEqual(count($logs), 1);
+    $this->assertEqual($logs[0], SafeMarkup::format('Update target "@name" is missing.', array('@name' => $name_deletee)));
+  }
+
+  /**
+   * Tests that secondary updates for deleted files work as expected.
+   *
+   * This test is completely hypothetical since we only support full
+   * configuration tree imports. Therefore, any configuration updates that cause
+   * secondary deletes should be reflected already in the staged configuration.
+   */
+  function testSecondaryUpdateDeletedDeleteeFirst() {
+    $name_deleter = 'config_test.dynamic.deleter';
+    $name_deletee = 'config_test.dynamic.deletee';
+    $storage = $this->container->get('config.storage');
+    $sync = $this->container->get('config.storage.sync');
+    $uuid = $this->container->get('uuid');
+
+    $values_deleter = array(
+      'id' => 'deleter',
+      'label' => 'Deleter',
+      'weight' => 0,
+      'uuid' => $uuid->generate(),
+      // Add a dependency on deletee, to make sure that is synced first.
+      'dependencies' => array(
+        'config' => array($name_deletee),
+      ),
+    );
+    $storage->write($name_deleter, $values_deleter);
+    $values_deleter['label'] = 'Updated Deleter';
+    $sync->write($name_deleter, $values_deleter);
+    $values_deletee = array(
+      'id' => 'deletee',
+      'label' => 'Deletee',
+      'weight' => 0,
+      'uuid' => $uuid->generate(),
+    );
+    $storage->write($name_deletee, $values_deletee);
+    $values_deletee['label'] = 'Updated Deletee';
+    $sync->write($name_deletee, $values_deletee);
+
+    // Import.
+    $this->configImporter->reset()->import();
+
+    $entity_storage = \Drupal::entityManager()->getStorage('config_test');
+    // Both entities are deleted. ConfigTest::postSave() causes updates of the
+    // deleter entity to delete the deletee entity. Since the deleter depends on
+    // the deletee, removing the deletee causes the deleter to be removed.
+    $this->assertFalse($entity_storage->load('deleter'));
+    $this->assertFalse($entity_storage->load('deletee'));
+    $logs = $this->configImporter->getErrors();
+    $this->assertEqual(count($logs), 0);
+  }
+
+  /**
+   * Tests that secondary deletes for deleted files work as expected.
+   */
+  function testSecondaryDeletedDeleteeSecond() {
+    $name_deleter = 'config_test.dynamic.deleter';
+    $name_deletee = 'config_test.dynamic.deletee';
+    $storage = $this->container->get('config.storage');
+
+    $uuid = $this->container->get('uuid');
+
+    $values_deleter = array(
+      'id' => 'deleter',
+      'label' => 'Deleter',
+      'weight' => 0,
+      'uuid' => $uuid->generate(),
+      // Add a dependency on deletee, to make sure this delete is synced first.
+      'dependencies' => array(
+        'config' => array($name_deletee),
+      ),
+    );
+    $storage->write($name_deleter, $values_deleter);
+    $values_deletee = array(
+      'id' => 'deletee',
+      'label' => 'Deletee',
+      'weight' => 0,
+      'uuid' => $uuid->generate(),
+    );
+    $storage->write($name_deletee, $values_deletee);
+
+    // Import.
+    $this->configImporter->reset()->import();
+
+    $entity_storage = \Drupal::entityManager()->getStorage('config_test');
+    $this->assertFalse($entity_storage->load('deleter'));
+    $this->assertFalse($entity_storage->load('deletee'));
+    // The deletee entity does not exist as the delete worked and although the
+    // delete occurred in \Drupal\config_test\Entity\ConfigTest::postDelete()
+    // this does not matter.
+    $logs = $this->configImporter->getErrors();
+    $this->assertEqual(count($logs), 0);
+  }
+
+  /**
+   * Tests updating of configuration during import.
+   */
+  function testUpdated() {
+    $name = 'config_test.system';
+    $dynamic_name = 'config_test.dynamic.dotted.default';
+    $storage = $this->container->get('config.storage');
+    $sync = $this->container->get('config.storage.sync');
+
+    // Verify that the configuration objects to import exist.
+    $this->assertIdentical($storage->exists($name), TRUE, $name . ' found.');
+    $this->assertIdentical($storage->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
+
+    // Replace the file content of the existing configuration objects in the
+    // sync directory.
+    $original_name_data = array(
+      'foo' => 'beer',
+    );
+    $sync->write($name, $original_name_data);
+    $original_dynamic_data = $storage->read($dynamic_name);
+    $original_dynamic_data['label'] = 'Updated';
+    $sync->write($dynamic_name, $original_dynamic_data);
+
+    // Verify the active configuration still returns the default values.
+    $config = $this->config($name);
+    $this->assertIdentical($config->get('foo'), 'bar');
+    $config = $this->config($dynamic_name);
+    $this->assertIdentical($config->get('label'), 'Default');
+
+    // Import.
+    $this->configImporter->reset()->import();
+
+    // Verify the values were updated.
+    \Drupal::configFactory()->reset($name);
+    $config = $this->config($name);
+    $this->assertIdentical($config->get('foo'), 'beer');
+    $config = $this->config($dynamic_name);
+    $this->assertIdentical($config->get('label'), 'Updated');
+
+    // Verify that the original file content is still the same.
+    $this->assertIdentical($sync->read($name), $original_name_data);
+    $this->assertIdentical($sync->read($dynamic_name), $original_dynamic_data);
+
+    // Verify that appropriate module API hooks have been invoked.
+    $this->assertTrue(isset($GLOBALS['hook_config_test']['load']));
+    $this->assertTrue(isset($GLOBALS['hook_config_test']['presave']));
+    $this->assertFalse(isset($GLOBALS['hook_config_test']['insert']));
+    $this->assertTrue(isset($GLOBALS['hook_config_test']['update']));
+    $this->assertFalse(isset($GLOBALS['hook_config_test']['predelete']));
+    $this->assertFalse(isset($GLOBALS['hook_config_test']['delete']));
+
+    // Verify that there is nothing more to import.
+    $this->assertFalse($this->configImporter->hasUnprocessedConfigurationChanges());
+    $logs = $this->configImporter->getErrors();
+    $this->assertEqual(count($logs), 0);
+  }
+
+  /**
+   * Tests the isInstallable method()
+   */
+  function testIsInstallable() {
+    $config_name = 'config_test.dynamic.isinstallable';
+    $this->assertFalse($this->container->get('config.storage')->exists($config_name));
+    \Drupal::state()->set('config_test.isinstallable', TRUE);
+    $this->installConfig(array('config_test'));
+    $this->assertTrue($this->container->get('config.storage')->exists($config_name));
+  }
+
+  /**
+   * Tests dependency validation during configuration import.
+   *
+   * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber
+   * @see \Drupal\Core\Config\ConfigImporter::createExtensionChangelist()
+   */
+  public function testUnmetDependency() {
+    $storage = $this->container->get('config.storage');
+    $sync = $this->container->get('config.storage.sync');
+
+    // Test an unknown configuration owner.
+    $sync->write('unknown.config', ['test' => 'test']);
+
+    // Make a config entity have unmet dependencies.
+    $config_entity_data = $sync->read('config_test.dynamic.dotted.default');
+    $config_entity_data['dependencies'] = ['module' => ['unknown']];
+    $sync->write('config_test.dynamic.dotted.module', $config_entity_data);
+    $config_entity_data['dependencies'] = ['theme' => ['unknown']];
+    $sync->write('config_test.dynamic.dotted.theme', $config_entity_data);
+    $config_entity_data['dependencies'] = ['config' => ['unknown']];
+    $sync->write('config_test.dynamic.dotted.config', $config_entity_data);
+
+    // Make an active config depend on something that is missing in sync.
+    // The whole configuration needs to be consistent, not only the updated one.
+    $config_entity_data['dependencies'] = [];
+    $storage->write('config_test.dynamic.dotted.deleted', $config_entity_data);
+    $config_entity_data['dependencies'] = ['config' => ['config_test.dynamic.dotted.deleted']];
+    $storage->write('config_test.dynamic.dotted.existing', $config_entity_data);
+    $sync->write('config_test.dynamic.dotted.existing', $config_entity_data);
+
+    $extensions = $sync->read('core.extension');
+    // Add a module and a theme that do not exist.
+    $extensions['module']['unknown_module'] = 0;
+    $extensions['theme']['unknown_theme'] = 0;
+    // Add a module and a theme that depend on uninstalled extensions.
+    $extensions['module']['book'] = 0;
+    $extensions['theme']['bartik'] = 0;
+
+    $sync->write('core.extension', $extensions);
+    try {
+      $this->configImporter->reset()->import();
+      $this->fail('ConfigImporterException not thrown; an invalid import was not stopped due to missing dependencies.');
+    }
+    catch (ConfigImporterException $e) {
+      $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.');
+      $error_log = $this->configImporter->getErrors();
+      $expected = [
+        'Unable to install the <em class="placeholder">unknown_module</em> module since it does not exist.',
+        'Unable to install the <em class="placeholder">Book</em> module since it requires the <em class="placeholder">Node, Text, Field, Filter, User</em> modules.',
+        'Unable to install the <em class="placeholder">unknown_theme</em> theme since it does not exist.',
+        'Unable to install the <em class="placeholder">Bartik</em> theme since it requires the <em class="placeholder">Classy</em> theme.',
+        'Configuration <em class="placeholder">config_test.dynamic.dotted.config</em> depends on the <em class="placeholder">unknown</em> configuration that will not exist after import.',
+        'Configuration <em class="placeholder">config_test.dynamic.dotted.existing</em> depends on the <em class="placeholder">config_test.dynamic.dotted.deleted</em> configuration that will not exist after import.',
+        'Configuration <em class="placeholder">config_test.dynamic.dotted.module</em> depends on the <em class="placeholder">unknown</em> module that will not be installed after import.',
+        'Configuration <em class="placeholder">config_test.dynamic.dotted.theme</em> depends on the <em class="placeholder">unknown</em> theme that will not be installed after import.',
+        'Configuration <em class="placeholder">unknown.config</em> depends on the <em class="placeholder">unknown</em> extension that will not be installed after import.',
+      ];
+      foreach ($expected as $expected_message) {
+        $this->assertTrue(in_array($expected_message, $error_log), $expected_message);
+      }
+    }
+
+    // Make a config entity have mulitple unmet dependencies.
+    $config_entity_data = $sync->read('config_test.dynamic.dotted.default');
+    $config_entity_data['dependencies'] = ['module' => ['unknown', 'dblog']];
+    $sync->write('config_test.dynamic.dotted.module', $config_entity_data);
+    $config_entity_data['dependencies'] = ['theme' => ['unknown', 'seven']];
+    $sync->write('config_test.dynamic.dotted.theme', $config_entity_data);
+    $config_entity_data['dependencies'] = ['config' => ['unknown', 'unknown2']];
+    $sync->write('config_test.dynamic.dotted.config', $config_entity_data);
+    try {
+      $this->configImporter->reset()->import();
+      $this->fail('ConfigImporterException not thrown, invalid import was not stopped due to missing dependencies.');
+    }
+    catch (ConfigImporterException $e) {
+      $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.');
+      $error_log = $this->configImporter->getErrors();
+      $expected = [
+        'Configuration <em class="placeholder">config_test.dynamic.dotted.config</em> depends on configuration (<em class="placeholder">unknown, unknown2</em>) that will not exist after import.',
+        'Configuration <em class="placeholder">config_test.dynamic.dotted.module</em> depends on modules (<em class="placeholder">unknown, Database Logging</em>) that will not be installed after import.',
+        'Configuration <em class="placeholder">config_test.dynamic.dotted.theme</em> depends on themes (<em class="placeholder">unknown, Seven</em>) that will not be installed after import.',
+      ];
+      foreach ($expected as $expected_message) {
+        $this->assertTrue(in_array($expected_message, $error_log), $expected_message);
+      }
+    }
+  }
+
+  /**
+   * Tests missing core.extension during configuration import.
+   *
+   * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber
+   */
+  public function testMissingCoreExtension() {
+    $sync = $this->container->get('config.storage.sync');
+    $sync->delete('core.extension');
+    try {
+      $this->configImporter->reset()->import();
+      $this->fail('ConfigImporterException not thrown, invalid import was not stopped due to missing dependencies.');
+    }
+    catch (ConfigImporterException $e) {
+      $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.');
+      $error_log = $this->configImporter->getErrors();
+      $this->assertEqual(['The core.extension configuration does not exist.'], $error_log);
+    }
+  }
+
+  /**
+   * Tests install profile validation during configuration import.
+   *
+   * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber
+   */
+  public function testInstallProfile() {
+    $sync = $this->container->get('config.storage.sync');
+
+    $extensions = $sync->read('core.extension');
+    // Add an install profile.
+    $extensions['module']['standard'] = 0;
+
+    $sync->write('core.extension', $extensions);
+    try {
+      $this->configImporter->reset()->import();
+      $this->fail('ConfigImporterException not thrown; an invalid import was not stopped due to missing dependencies.');
+    }
+    catch (ConfigImporterException $e) {
+      $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.');
+      $error_log = $this->configImporter->getErrors();
+      // Install profiles should not even be scanned at this point.
+      $this->assertEqual(['Unable to install the <em class="placeholder">standard</em> module since it does not exist.'], $error_log);
+    }
+  }
+
+  /**
+   * Tests config_get_config_directory().
+   */
+  public function testConfigGetConfigDirectory() {
+    $directory = config_get_config_directory(CONFIG_SYNC_DIRECTORY);
+    $this->assertEqual($this->configDirectories[CONFIG_SYNC_DIRECTORY], $directory);
+
+    $message = 'Calling config_get_config_directory() with CONFIG_ACTIVE_DIRECTORY results in an exception.';
+    try {
+      config_get_config_directory(CONFIG_ACTIVE_DIRECTORY);
+      $this->fail($message);
+    }
+    catch (\Exception $e) {
+      $this->pass($message);
+    }
+  }
+
+}
diff --git a/core/modules/config/tests/src/Kernel/ConfigInstallTest.php b/core/modules/config/tests/src/Kernel/ConfigInstallTest.php
new file mode 100644
index 0000000..b4d4dc9
--- /dev/null
+++ b/core/modules/config/tests/src/Kernel/ConfigInstallTest.php
@@ -0,0 +1,254 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\ConfigInstallTest.
+ */
+
+namespace Drupal\Tests\config\Kernel;
+
+use Drupal\Core\Config\InstallStorage;
+use Drupal\Core\Config\PreExistingConfigException;
+use Drupal\Core\Config\UnmetDependenciesException;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests installation of configuration objects in installation functionality.
+ *
+ * @group config
+ * @see \Drupal\Core\Config\ConfigInstaller
+ */
+class ConfigInstallTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['system'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->installSchema('system', ['router']);
+
+    // 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 installation.
+   */
+  function testModuleInstallation() {
+    $default_config = 'config_test.system';
+    $default_configuration_entity = 'config_test.dynamic.dotted.default';
+
+    // Verify that default module config does not exist before installation yet.
+    $config = $this->config($default_config);
+    $this->assertIdentical($config->isNew(), TRUE);
+    $config = $this->config($default_configuration_entity);
+    $this->assertIdentical($config->isNew(), TRUE);
+
+    // Ensure that schema provided by modules that are not installed is not
+    // available.
+    $this->assertFalse(\Drupal::service('config.typed')->hasConfigSchema('config_schema_test.someschema'), 'Configuration schema for config_schema_test.someschema does not exist.');
+
+    // Install the test module.
+    $this->installModules(array('config_test'));
+
+    // Verify that default module config exists.
+    \Drupal::configFactory()->reset($default_config);
+    \Drupal::configFactory()->reset($default_configuration_entity);
+    $config = $this->config($default_config);
+    $this->assertIdentical($config->isNew(), FALSE);
+    $config = $this->config($default_configuration_entity);
+    $this->assertIdentical($config->isNew(), FALSE);
+
+    // Verify that config_test API hooks were invoked for the dynamic default
+    // configuration entity.
+    $this->assertFalse(isset($GLOBALS['hook_config_test']['load']));
+    $this->assertTrue(isset($GLOBALS['hook_config_test']['presave']));
+    $this->assertTrue(isset($GLOBALS['hook_config_test']['insert']));
+    $this->assertFalse(isset($GLOBALS['hook_config_test']['update']));
+    $this->assertFalse(isset($GLOBALS['hook_config_test']['predelete']));
+    $this->assertFalse(isset($GLOBALS['hook_config_test']['delete']));
+
+    // Install the schema test module.
+    $this->enableModules(array('config_schema_test'));
+    $this->installConfig(array('config_schema_test'));
+
+    // After module installation the new schema should exist.
+    $this->assertTrue(\Drupal::service('config.typed')->hasConfigSchema('config_schema_test.someschema'), 'Configuration schema for config_schema_test.someschema exists.');
+
+    // Test that uninstalling configuration removes configuration schema.
+    $this->config('core.extension')->set('module', array())->save();
+    \Drupal::service('config.manager')->uninstall('module', 'config_test');
+    $this->assertFalse(\Drupal::service('config.typed')->hasConfigSchema('config_schema_test.someschema'), 'Configuration schema for config_schema_test.someschema does not exist.');
+  }
+
+  /**
+   * Tests that collections are ignored if the event does not return anything.
+   */
+  public function testCollectionInstallationNoCollections() {
+    // Install the test module.
+    $this->enableModules(array('config_collection_install_test'));
+    $this->installConfig(array('config_collection_install_test'));
+    /** @var \Drupal\Core\Config\StorageInterface $active_storage */
+    $active_storage = \Drupal::service('config.storage');
+    $this->assertEqual(array(), $active_storage->getAllCollectionNames());
+  }
+
+  /**
+   * Tests config objects in collections are installed as expected.
+   */
+  public function testCollectionInstallationCollections() {
+    $collections = array(
+      'another_collection',
+      'collection.test1',
+      'collection.test2',
+    );
+    // Set the event listener to return three possible collections.
+    // @see \Drupal\config_collection_install_test\EventSubscriber
+    \Drupal::state()->set('config_collection_install_test.collection_names', $collections);
+    // Install the test module.
+    $this->enableModules(array('config_collection_install_test'));
+    $this->installConfig(array('config_collection_install_test'));
+    /** @var \Drupal\Core\Config\StorageInterface $active_storage */
+    $active_storage = \Drupal::service('config.storage');
+    $this->assertEqual($collections, $active_storage->getAllCollectionNames());
+    foreach ($collections as $collection) {
+      $collection_storage = $active_storage->createCollection($collection);
+      $data = $collection_storage->read('config_collection_install_test.test');
+      $this->assertEqual($collection, $data['collection']);
+    }
+
+    // Tests that clashing configuration in collections is detected.
+    try {
+      \Drupal::service('module_installer')->install(['config_collection_clash_install_test']);
+      $this->fail('Expected PreExistingConfigException not thrown.');
+    }
+    catch (PreExistingConfigException $e) {
+      $this->assertEqual($e->getExtension(), 'config_collection_clash_install_test');
+      $this->assertEqual($e->getConfigObjects(), [
+        'another_collection' => ['config_collection_install_test.test'],
+        'collection.test1' => ['config_collection_install_test.test'],
+        'collection.test2' => ['config_collection_install_test.test'],
+      ]);
+      $this->assertEqual($e->getMessage(), 'Configuration objects (another_collection/config_collection_install_test.test, collection/test1/config_collection_install_test.test, collection/test2/config_collection_install_test.test) provided by config_collection_clash_install_test already exist in active configuration');
+    }
+
+    // Test that the we can use the config installer to install all the
+    // available default configuration in a particular collection for enabled
+    // extensions.
+    \Drupal::service('config.installer')->installCollectionDefaultConfig('entity');
+    // The 'entity' collection will not exist because the 'config_test' module
+    // is not enabled.
+    $this->assertEqual($collections, $active_storage->getAllCollectionNames());
+    // Enable the 'config_test' module and try again.
+    $this->enableModules(array('config_test'));
+    \Drupal::service('config.installer')->installCollectionDefaultConfig('entity');
+    $collections[] = 'entity';
+    $this->assertEqual($collections, $active_storage->getAllCollectionNames());
+    $collection_storage = $active_storage->createCollection('entity');
+    $data = $collection_storage->read('config_test.dynamic.dotted.default');
+    $this->assertIdentical(array('label' => 'entity'), $data);
+
+    // Test that the config manager uninstalls configuration from collections
+    // as expected.
+    \Drupal::service('config.manager')->uninstall('module', 'config_collection_install_test');
+    $this->assertEqual(array('entity'), $active_storage->getAllCollectionNames());
+    \Drupal::service('config.manager')->uninstall('module', 'config_test');
+    $this->assertEqual(array(), $active_storage->getAllCollectionNames());
+  }
+
+  /**
+   * Tests collections which do not support config entities install correctly.
+   *
+   * Config entity detection during config installation is done by matching
+   * config name prefixes. If a collection provides a configuration with a
+   * matching name but does not support config entities it should be created
+   * using simple configuration.
+   */
+  public function testCollectionInstallationCollectionConfigEntity() {
+    $collections = array(
+      'entity',
+    );
+    \Drupal::state()->set('config_collection_install_test.collection_names', $collections);
+    // Install the test module.
+    $this->installModules(array('config_test', 'config_collection_install_test'));
+    /** @var \Drupal\Core\Config\StorageInterface $active_storage */
+    $active_storage = \Drupal::service('config.storage');
+    $this->assertEqual($collections, $active_storage->getAllCollectionNames());
+    $collection_storage = $active_storage->createCollection('entity');
+
+    // The config_test.dynamic.dotted.default configuration object saved in the
+    // active store should be a configuration entity complete with UUID. Because
+    // the entity collection does not support configuration entities the
+    // configuration object stored there with the same name should only contain
+    // a label.
+    $name = 'config_test.dynamic.dotted.default';
+    $data = $active_storage->read($name);
+    $this->assertTrue(isset($data['uuid']));
+    $data = $collection_storage->read($name);
+    $this->assertIdentical(array('label' => 'entity'), $data);
+  }
+
+  /**
+   * Tests the configuration with unmet dependencies is not installed.
+   */
+  public function testDependencyChecking() {
+    $this->installModules(['config_test']);
+    try {
+      $this->installModules(['config_install_dependency_test']);
+      $this->fail('Expected UnmetDependenciesException not thrown.');
+    }
+    catch (UnmetDependenciesException $e) {
+      $this->assertEqual($e->getExtension(), 'config_install_dependency_test');
+      $this->assertEqual($e->getConfigObjects(), ['config_test.dynamic.other_module_test_with_dependency']);
+      $this->assertEqual($e->getMessage(), 'Configuration objects (config_test.dynamic.other_module_test_with_dependency) provided by config_install_dependency_test have unmet dependencies');
+    }
+    $this->installModules(['config_other_module_config_test']);
+    $this->installModules(['config_install_dependency_test']);
+    $entity = \Drupal::entityManager()->getStorage('config_test')->load('other_module_test_with_dependency');
+    $this->assertTrue($entity, 'The config_test.dynamic.other_module_test_with_dependency configuration has been created during install.');
+    // Ensure that dependencies can be added during module installation by
+    // hooks.
+    $this->assertIdentical('config_install_dependency_test', $entity->getDependencies()['module'][0]);
+  }
+
+  /**
+   * Tests imported configuration entities with and without language information.
+   */
+  function testLanguage() {
+    $this->installModules(['config_test_language']);
+    // Test imported configuration with implicit language code.
+    $storage = new InstallStorage();
+    $data = $storage->read('config_test.dynamic.dotted.english');
+    $this->assertTrue(!isset($data['langcode']));
+    $this->assertEqual(
+      $this->config('config_test.dynamic.dotted.english')->get('langcode'),
+      'en'
+    );
+
+    // Test imported configuration with explicit language code.
+    $data = $storage->read('config_test.dynamic.dotted.french');
+    $this->assertEqual($data['langcode'], 'fr');
+    $this->assertEqual(
+      $this->config('config_test.dynamic.dotted.french')->get('langcode'),
+      'fr'
+    );
+  }
+
+  /**
+   * Installs a module.
+   *
+   * @param array $modules
+   *   The module names.
+   */
+  protected function installModules(array $modules) {
+    $this->container->get('module_installer')->install($modules);
+    $this->container = \Drupal::getContainer();
+  }
+
+}
diff --git a/core/modules/config/tests/src/Kernel/ConfigLanguageOverrideTest.php b/core/modules/config/tests/src/Kernel/ConfigLanguageOverrideTest.php
new file mode 100644
index 0000000..83374c8
--- /dev/null
+++ b/core/modules/config/tests/src/Kernel/ConfigLanguageOverrideTest.php
@@ -0,0 +1,125 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\ConfigLanguageOverrideTest.
+ */
+
+namespace Drupal\Tests\config\Kernel;
+
+use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Confirm that language overrides work.
+ *
+ * @group config
+ */
+class ConfigLanguageOverrideTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('user', 'language', 'config_test', 'system', 'field');
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->installConfig(array('config_test'));
+  }
+
+  /**
+   * Tests locale override based on language.
+   */
+  function testConfigLanguageOverride() {
+    // The language module implements a config factory override object that
+    // overrides configuration when the Language module is enabled. This test ensures that
+    // English overrides work.
+    \Drupal::languageManager()->setConfigOverrideLanguage(\Drupal::languageManager()->getLanguage('en'));
+    $config = \Drupal::config('config_test.system');
+    $this->assertIdentical($config->get('foo'), 'en bar');
+
+    // Ensure that the raw data is not translated.
+    $raw = $config->getRawData();
+    $this->assertIdentical($raw['foo'], 'bar');
+
+    ConfigurableLanguage::createFromLangcode('fr')->save();
+    ConfigurableLanguage::createFromLangcode('de')->save();
+
+    \Drupal::languageManager()->setConfigOverrideLanguage(\Drupal::languageManager()->getLanguage('fr'));
+    $config = \Drupal::config('config_test.system');
+    $this->assertIdentical($config->get('foo'), 'fr bar');
+
+    \Drupal::languageManager()->setConfigOverrideLanguage(\Drupal::languageManager()->getLanguage('de'));
+    $config = \Drupal::config('config_test.system');
+    $this->assertIdentical($config->get('foo'), 'de bar');
+
+    // Test overrides of completely new configuration objects. In normal runtime
+    // this should only happen for configuration entities as we should not be
+    // creating simple configuration objects on the fly.
+    \Drupal::languageManager()
+      ->getLanguageConfigOverride('de', 'config_test.new')
+      ->set('language', 'override')
+      ->save();
+    $config = \Drupal::config('config_test.new');
+    $this->assertTrue($config->isNew(), 'The configuration object config_test.new is new');
+    $this->assertIdentical($config->get('language'), 'override');
+    $this->assertIdentical($config->getOriginal('language', FALSE), NULL);
+
+    // Test how overrides react to base configuration changes. Set up some base
+    // values.
+    \Drupal::configFactory()->getEditable('config_test.foo')
+      ->set('value', array('key' => 'original'))
+      ->set('label', 'Original')
+      ->save();
+    \Drupal::languageManager()
+      ->getLanguageConfigOverride('de', 'config_test.foo')
+      ->set('value', array('key' => 'override'))
+      ->set('label', 'Override')
+      ->save();
+    \Drupal::languageManager()
+      ->getLanguageConfigOverride('fr', 'config_test.foo')
+      ->set('value', array('key' => 'override'))
+      ->save();
+    \Drupal::configFactory()->clearStaticCache();
+    $config = \Drupal::config('config_test.foo');
+    $this->assertIdentical($config->get('value'), array('key' => 'override'));
+
+    // Ensure renaming the config will rename the override.
+    \Drupal::languageManager()->setConfigOverrideLanguage(\Drupal::languageManager()->getLanguage('en'));
+    \Drupal::configFactory()->rename('config_test.foo', 'config_test.bar');
+    $config = \Drupal::config('config_test.bar');
+    $this->assertEqual($config->get('value'), array('key' => 'original'));
+    $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.foo');
+    $this->assertTrue($override->isNew());
+    $this->assertEqual($override->get('value'), NULL);
+    $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.bar');
+    $this->assertFalse($override->isNew());
+    $this->assertEqual($override->get('value'), array('key' => 'override'));
+    $override = \Drupal::languageManager()->getLanguageConfigOverride('fr', 'config_test.bar');
+    $this->assertFalse($override->isNew());
+    $this->assertEqual($override->get('value'), array('key' => 'override'));
+
+    // Ensure changing data in the config will update the overrides.
+    $config = \Drupal::configFactory()->getEditable('config_test.bar')->clear('value.key')->save();
+    $this->assertEqual($config->get('value'), array());
+    $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.bar');
+    $this->assertFalse($override->isNew());
+    $this->assertEqual($override->get('value'), NULL);
+    // The French override will become empty and therefore removed.
+    $override = \Drupal::languageManager()->getLanguageConfigOverride('fr', 'config_test.bar');
+    $this->assertTrue($override->isNew());
+    $this->assertEqual($override->get('value'), NULL);
+
+    // Ensure deleting the config will delete the override.
+    \Drupal::configFactory()->getEditable('config_test.bar')->delete();
+    $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.bar');
+    $this->assertTrue($override->isNew());
+    $this->assertEqual($override->get('value'), NULL);
+  }
+}
+
diff --git a/core/modules/config/tests/src/Kernel/ConfigOverrideTest.php b/core/modules/config/tests/src/Kernel/ConfigOverrideTest.php
new file mode 100644
index 0000000..762cc7a
--- /dev/null
+++ b/core/modules/config/tests/src/Kernel/ConfigOverrideTest.php
@@ -0,0 +1,143 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\ConfigOverrideTest.
+ */
+
+namespace Drupal\Tests\config\Kernel;
+
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests configuration overrides via $config in settings.php.
+ *
+ * @group config
+ */
+class ConfigOverrideTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('system', 'config_test');
+
+  protected function setUp() {
+    parent::setUp();
+    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
+  }
+
+  /**
+   * Tests configuration override.
+   */
+  function testConfOverride() {
+    $expected_original_data = array(
+      'foo' => 'bar',
+      'baz' => NULL,
+      '404' => 'herp',
+    );
+
+    // Set globals before installing to prove that the installed file does not
+    // contain these values.
+    $overrides['config_test.system']['foo'] = 'overridden';
+    $overrides['config_test.system']['baz'] = 'injected';
+    $overrides['config_test.system']['404'] = 'derp';
+    $GLOBALS['config'] = $overrides;
+
+    $this->installConfig(array('config_test'));
+
+    // Verify that the original configuration data exists. Have to read storage
+    // directly otherwise overrides will apply.
+    $active = $this->container->get('config.storage');
+    $data = $active->read('config_test.system');
+    $this->assertIdentical($data['foo'], $expected_original_data['foo']);
+    $this->assertFalse(isset($data['baz']));
+    $this->assertIdentical($data['404'], $expected_original_data['404']);
+
+    // Get the configuration object with overrides.
+    $config = \Drupal::configFactory()->get('config_test.system');
+
+    // Verify that it contains the overridden data from $config.
+    $this->assertIdentical($config->get('foo'), $overrides['config_test.system']['foo']);
+    $this->assertIdentical($config->get('baz'), $overrides['config_test.system']['baz']);
+    $this->assertIdentical($config->get('404'), $overrides['config_test.system']['404']);
+
+    // Get the configuration object which does not have overrides.
+    $config = \Drupal::configFactory()->getEditable('config_test.system');
+
+    // Verify that it does not contains the overridden data from $config.
+    $this->assertIdentical($config->get('foo'), $expected_original_data['foo']);
+    $this->assertIdentical($config->get('baz'), NULL);
+    $this->assertIdentical($config->get('404'), $expected_original_data['404']);
+
+    // Set the value for 'baz' (on the original data).
+    $expected_original_data['baz'] = 'original baz';
+    $config->set('baz', $expected_original_data['baz']);
+
+    // Set the value for '404' (on the original data).
+    $expected_original_data['404'] = 'original 404';
+    $config->set('404', $expected_original_data['404']);
+
+    // Save the configuration object (having overrides applied).
+    $config->save();
+
+    // Reload it and verify that it still contains overridden data from $config.
+    $config = \Drupal::config('config_test.system');
+    $this->assertIdentical($config->get('foo'), $overrides['config_test.system']['foo']);
+    $this->assertIdentical($config->get('baz'), $overrides['config_test.system']['baz']);
+    $this->assertIdentical($config->get('404'), $overrides['config_test.system']['404']);
+
+    // Verify that raw config data has changed.
+    $this->assertIdentical($config->getOriginal('foo', FALSE), $expected_original_data['foo']);
+    $this->assertIdentical($config->getOriginal('baz', FALSE), $expected_original_data['baz']);
+    $this->assertIdentical($config->getOriginal('404', FALSE), $expected_original_data['404']);
+
+    // Write file to sync.
+    $sync = $this->container->get('config.storage.sync');
+    $expected_new_data = array(
+      'foo' => 'barbar',
+      '404' => 'herpderp',
+    );
+    $sync->write('config_test.system', $expected_new_data);
+
+    // Import changed data from sync to active.
+    $this->configImporter()->import();
+    $data = $active->read('config_test.system');
+
+    // Verify that the new configuration data exists. Have to read storage
+    // directly otherwise overrides will apply.
+    $this->assertIdentical($data['foo'], $expected_new_data['foo']);
+    $this->assertFalse(isset($data['baz']));
+    $this->assertIdentical($data['404'], $expected_new_data['404']);
+
+    // Verify that the overrides are still working.
+    $config = \Drupal::config('config_test.system');
+    $this->assertIdentical($config->get('foo'), $overrides['config_test.system']['foo']);
+    $this->assertIdentical($config->get('baz'), $overrides['config_test.system']['baz']);
+    $this->assertIdentical($config->get('404'), $overrides['config_test.system']['404']);
+
+    // Test overrides of completely new configuration objects. In normal runtime
+    // this should only happen for configuration entities as we should not be
+    // creating simple configuration objects on the fly.
+    $GLOBALS['config']['config_test.new']['key'] = 'override';
+    $config = \Drupal::config('config_test.new');
+    $this->assertTrue($config->isNew(), 'The configuration object config_test.new is new');
+    $this->assertIdentical($config->get('key'), 'override');
+    $config_raw = \Drupal::configFactory()->getEditable('config_test.new');
+    $this->assertIdentical($config_raw->get('key'), NULL);
+    $config_raw
+      ->set('key', 'raw')
+      ->set('new_key', 'new_value')
+      ->save();
+    // Ensure override is preserved but all other data has been updated
+    // accordingly.
+    $config = \Drupal::config('config_test.new');
+    $this->assertFalse($config->isNew(), 'The configuration object config_test.new is not new');
+    $this->assertIdentical($config->get('key'), 'override');
+    $this->assertIdentical($config->get('new_key'), 'new_value');
+    $raw_data = $config->getRawData();
+    $this->assertIdentical($raw_data['key'], 'raw');
+  }
+
+}
diff --git a/core/modules/config/tests/src/Kernel/ConfigSchemaTest.php b/core/modules/config/tests/src/Kernel/ConfigSchemaTest.php
new file mode 100644
index 0000000..3331f07
--- /dev/null
+++ b/core/modules/config/tests/src/Kernel/ConfigSchemaTest.php
@@ -0,0 +1,575 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\ConfigSchemaTest.
+ */
+
+namespace Drupal\Tests\config\Kernel;
+
+use Drupal\Core\Config\FileStorage;
+use Drupal\Core\Config\InstallStorage;
+use Drupal\Core\Config\Schema\ConfigSchemaAlterException;
+use Drupal\Core\TypedData\Type\IntegerInterface;
+use Drupal\Core\TypedData\Type\StringInterface;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests schema for configuration objects.
+ *
+ * @group config
+ */
+class ConfigSchemaTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('system', 'language', 'field', 'image', 'config_test', 'config_schema_test');
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->installConfig(array('system', 'image', 'config_schema_test'));
+  }
+
+  /**
+   * Tests the basic metadata retrieval layer.
+   */
+  function testSchemaMapping() {
+    // Nonexistent configuration key will have Undefined as metadata.
+    $this->assertIdentical(FALSE, \Drupal::service('config.typed')->hasConfigSchema('config_schema_test.no_such_key'));
+    $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.no_such_key');
+    $expected = array();
+    $expected['label'] = 'Undefined';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Undefined';
+    $expected['type'] = 'undefined';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for nonexistent configuration.');
+
+    // Configuration file without schema will return Undefined as well.
+    $this->assertIdentical(FALSE, \Drupal::service('config.typed')->hasConfigSchema('config_schema_test.noschema'));
+    $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.noschema');
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for configuration with no schema.');
+
+    // Configuration file with only some schema.
+    $this->assertIdentical(TRUE, \Drupal::service('config.typed')->hasConfigSchema('config_schema_test.someschema'));
+    $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.someschema');
+    $expected = array();
+    $expected['label'] = 'Schema test data';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
+    $expected['mapping']['langcode']['type'] = 'string';
+    $expected['mapping']['langcode']['label'] = 'Language code';
+    $expected['mapping']['_core']['type'] = '_core_config_info';
+    $expected['mapping']['testitem'] = array('label' => 'Test item');
+    $expected['mapping']['testlist'] = array('label' => 'Test list');
+    $expected['type'] = 'config_schema_test.someschema';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for configuration with only some schema.');
+
+    // Check type detection on elements with undefined types.
+    $config = \Drupal::service('config.typed')->get('config_schema_test.someschema');
+    $definition = $config->get('testitem')->getDataDefinition()->toArray();
+    $expected = array();
+    $expected['label'] = 'Test item';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Undefined';
+    $expected['type'] = 'undefined';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
+    $this->assertEqual($definition, $expected, 'Automatic type detected for a scalar is undefined.');
+    $definition = $config->get('testlist')->getDataDefinition()->toArray();
+    $expected = array();
+    $expected['label'] = 'Test list';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Undefined';
+    $expected['type'] = 'undefined';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
+    $this->assertEqual($definition, $expected, 'Automatic type detected for a list is undefined.');
+    $definition = $config->get('testnoschema')->getDataDefinition()->toArray();
+    $expected = array();
+    $expected['label'] = 'Undefined';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Undefined';
+    $expected['type'] = 'undefined';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
+    $this->assertEqual($definition, $expected, 'Automatic type detected for an undefined integer is undefined.');
+
+    // Simple case, straight metadata.
+    $definition = \Drupal::service('config.typed')->getDefinition('system.maintenance');
+    $expected = array();
+    $expected['label'] = 'Maintenance mode';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
+    $expected['mapping']['message'] = array(
+      'label' =>  'Message to display when in maintenance mode',
+      'type' => 'text',
+    );
+    $expected['mapping']['langcode'] = array(
+      'label' => 'Language code',
+      'type' => 'string',
+    );
+    $expected['mapping']['_core']['type'] = '_core_config_info';
+    $expected['type'] = 'system.maintenance';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for system.maintenance');
+
+    // Mixed schema with ignore elements.
+    $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.ignore');
+    $expected = array();
+    $expected['label'] = 'Ignore test';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
+    $expected['mapping']['langcode'] = array(
+      'type' => 'string',
+      'label' => 'Language code',
+    );
+    $expected['mapping']['_core']['type'] = '_core_config_info';
+    $expected['mapping']['label'] = array(
+      'label' =>  'Label',
+      'type' => 'label',
+    );
+    $expected['mapping']['irrelevant'] = array(
+      'label' => 'Irrelevant',
+      'type' => 'ignore',
+    );
+    $expected['mapping']['indescribable'] = array(
+      'label' => 'Indescribable',
+      'type' => 'ignore',
+    );
+    $expected['mapping']['weight'] = array(
+      'label' => 'Weight',
+      'type' => 'integer',
+    );
+    $expected['type'] = 'config_schema_test.ignore';
+
+    $this->assertEqual($definition, $expected);
+
+    // The ignore elements themselves.
+    $definition = \Drupal::service('config.typed')->get('config_schema_test.ignore')->get('irrelevant')->getDataDefinition()->toArray();
+    $expected = array();
+    $expected['type'] = 'ignore';
+    $expected['label'] = 'Irrelevant';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Ignore';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
+    $this->assertEqual($definition, $expected);
+    $definition = \Drupal::service('config.typed')->get('config_schema_test.ignore')->get('indescribable')->getDataDefinition()->toArray();
+    $expected['label'] = 'Indescribable';
+    $this->assertEqual($definition, $expected);
+
+    // More complex case, generic type. Metadata for image style.
+    $definition = \Drupal::service('config.typed')->getDefinition('image.style.large');
+    $expected = array();
+    $expected['label'] = 'Image style';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
+    $expected['mapping']['name']['type'] = 'string';
+    $expected['mapping']['uuid']['type'] = 'string';
+    $expected['mapping']['uuid']['label'] = 'UUID';
+    $expected['mapping']['langcode']['type'] = 'string';
+    $expected['mapping']['langcode']['label'] = 'Language code';
+    $expected['mapping']['status']['type'] = 'boolean';
+    $expected['mapping']['status']['label'] = 'Status';
+    $expected['mapping']['dependencies']['type'] = 'config_dependencies';
+    $expected['mapping']['dependencies']['label'] = 'Dependencies';
+    $expected['mapping']['name']['type'] = 'string';
+    $expected['mapping']['label']['type'] = 'label';
+    $expected['mapping']['label']['label'] = 'Label';
+    $expected['mapping']['effects']['type'] = 'sequence';
+    $expected['mapping']['effects']['sequence']['type'] = 'mapping';
+    $expected['mapping']['effects']['sequence']['mapping']['id']['type'] = 'string';
+    $expected['mapping']['effects']['sequence']['mapping']['data']['type'] = 'image.effect.[%parent.id]';
+    $expected['mapping']['effects']['sequence']['mapping']['weight']['type'] = 'integer';
+    $expected['mapping']['effects']['sequence']['mapping']['uuid']['type'] = 'string';
+    $expected['mapping']['third_party_settings']['type'] = 'sequence';
+    $expected['mapping']['third_party_settings']['label'] = 'Third party settings';
+    $expected['mapping']['third_party_settings']['sequence']['type'] = '[%parent.%parent.%type].third_party.[%key]';
+    $expected['mapping']['_core']['type'] = '_core_config_info';
+    $expected['type'] = 'image.style.*';
+
+    $this->assertEqual($definition, $expected);
+
+    // More complex, type based on a complex one.
+    $definition = \Drupal::service('config.typed')->getDefinition('image.effect.image_scale');
+    // This should be the schema for image.effect.image_scale.
+    $expected = array();
+    $expected['label'] = 'Image scale';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
+    $expected['mapping']['width']['type'] = 'integer';
+    $expected['mapping']['width']['label'] = 'Width';
+    $expected['mapping']['height']['type'] = 'integer';
+    $expected['mapping']['height']['label'] = 'Height';
+    $expected['mapping']['upscale']['type'] = 'boolean';
+    $expected['mapping']['upscale']['label'] = 'Upscale';
+    $expected['type'] = 'image.effect.image_scale';
+
+
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for image.effect.image_scale');
+
+    // Most complex case, get metadata for actual configuration element.
+    $effects = \Drupal::service('config.typed')->get('image.style.medium')->get('effects');
+    $definition = $effects->get('bddf0d06-42f9-4c75-a700-a33cafa25ea0')->get('data')->getDataDefinition()->toArray();
+    // This should be the schema for image.effect.image_scale, reuse previous one.
+    $expected['type'] =  'image.effect.image_scale';
+
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for the first effect of image.style.medium');
+
+    $a = \Drupal::config('config_test.dynamic.third_party');
+    $test = \Drupal::service('config.typed')->get('config_test.dynamic.third_party')->get('third_party_settings.config_schema_test');
+    $definition = $test->getDataDefinition()->toArray();
+    $expected = array();
+    $expected['type'] = 'config_test.dynamic.*.third_party.config_schema_test';
+    $expected['label'] = 'Mapping';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
+    $expected['mapping'] = [
+      'integer' => ['type' => 'integer'],
+      'string' => ['type' => 'string'],
+    ];
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_test.dynamic.third_party:third_party_settings.config_schema_test');
+
+    // More complex, several level deep test.
+    $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.someschema.somemodule.section_one.subsection');
+    // This should be the schema of config_schema_test.someschema.somemodule.*.*.
+    $expected = array();
+    $expected['label'] = 'Schema multiple filesystem marker test';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
+    $expected['mapping']['langcode']['type'] = 'string';
+    $expected['mapping']['langcode']['label'] = 'Language code';
+    $expected['mapping']['_core']['type'] = '_core_config_info';
+    $expected['mapping']['testid']['type'] = 'string';
+    $expected['mapping']['testid']['label'] = 'ID';
+    $expected['mapping']['testdescription']['type'] = 'text';
+    $expected['mapping']['testdescription']['label'] = 'Description';
+    $expected['type'] = 'config_schema_test.someschema.somemodule.*.*';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
+
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_schema_test.someschema.somemodule.section_one.subsection');
+
+    $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.someschema.somemodule.section_two.subsection');
+    // The other file should have the same schema.
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_schema_test.someschema.somemodule.section_two.subsection');
+  }
+
+  /**
+   * Tests metadata retrieval with several levels of %parent indirection.
+   */
+  function testSchemaMappingWithParents() {
+    $config_data = \Drupal::service('config.typed')->get('config_schema_test.someschema.with_parents');
+
+    // Test fetching parent one level up.
+    $entry = $config_data->get('one_level');
+    $definition = $entry->get('testitem')->getDataDefinition()->toArray();
+    $expected = array(
+      'type' => 'config_schema_test.someschema.with_parents.key_1',
+      'label' => 'Test item nested one level',
+      'class' => '\Drupal\Core\TypedData\Plugin\DataType\StringData',
+      'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
+    );
+    $this->assertEqual($definition, $expected);
+
+    // Test fetching parent two levels up.
+    $entry = $config_data->get('two_levels');
+    $definition = $entry->get('wrapper')->get('testitem')->getDataDefinition()->toArray();
+    $expected = array(
+      'type' => 'config_schema_test.someschema.with_parents.key_2',
+      'label' => 'Test item nested two levels',
+      'class' => '\Drupal\Core\TypedData\Plugin\DataType\StringData',
+      'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
+    );
+    $this->assertEqual($definition, $expected);
+
+    // Test fetching parent three levels up.
+    $entry = $config_data->get('three_levels');
+    $definition = $entry->get('wrapper_1')->get('wrapper_2')->get('testitem')->getDataDefinition()->toArray();
+    $expected = array(
+      'type' => 'config_schema_test.someschema.with_parents.key_3',
+      'label' => 'Test item nested three levels',
+      'class' => '\Drupal\Core\TypedData\Plugin\DataType\StringData',
+      'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
+    );
+    $this->assertEqual($definition, $expected);
+  }
+
+  /**
+   * Tests metadata applied to configuration objects.
+   */
+  function testSchemaData() {
+    // Try a simple property.
+    $meta = \Drupal::service('config.typed')->get('system.site');
+    $property = $meta->get('page')->get('front');
+    $this->assertTrue($property instanceof StringInterface, 'Got the right wrapper fo the page.front property.');
+    $this->assertEqual($property->getValue(), '/user/login', 'Got the right value for page.front data.');
+    $definition = $property->getDataDefinition();
+    $this->assertTrue(empty($definition['translatable']), 'Got the right translatability setting for page.front data.');
+
+    // Check nested array of properties.
+    $list = $meta->get('page')->getElements();
+    $this->assertEqual(count($list), 3, 'Got a list with the right number of properties for site page data');
+    $this->assertTrue(isset($list['front']) && isset($list['403']) && isset($list['404']), 'Got a list with the right properties for site page data.');
+    $this->assertEqual($list['front']->getValue(), '/user/login', 'Got the right value for page.front data from the list.');
+
+    // And test some TypedConfigInterface methods.
+    $properties = $list;
+    $this->assertTrue(count($properties) == 3 && $properties['front'] == $list['front'], 'Got the right properties for site page.');
+    $values = $meta->get('page')->toArray();
+    $this->assertTrue(count($values) == 3 && $values['front'] == '/user/login', 'Got the right property values for site page.');
+
+    // Now let's try something more complex, with nested objects.
+    $wrapper = \Drupal::service('config.typed')->get('image.style.large');
+    $effects = $wrapper->get('effects');
+    $this->assertTrue(count($effects->toArray()) == 1, 'Got an array with effects for image.style.large data');
+    $uuid = key($effects->getValue());
+    $effect = $effects->get($uuid)->getElements();
+    $this->assertTrue(!$effect['data']->isEmpty() && $effect['id']->getValue() == 'image_scale', 'Got data for the image scale effect from metadata.');
+    $this->assertTrue($effect['data']->get('width') instanceof IntegerInterface, 'Got the right type for the scale effect width.');
+    $this->assertEqual($effect['data']->get('width')->getValue(), 480, 'Got the right value for the scale effect width.' );
+  }
+
+  /**
+   * Test configuration value data type enforcement using schemas.
+   */
+  public function testConfigSaveWithSchema() {
+    $untyped_values = array(
+      'string' => 1,
+      'empty_string' => '',
+      'null_string' => NULL,
+      'integer' => '100',
+      'null_integer' => '',
+      'boolean' => 1,
+      // If the config schema doesn't have a type it shouldn't be casted.
+      'no_type' => 1,
+      'mapping' => array(
+        'string' => 1
+      ),
+      'float' => '3.14',
+      'null_float' => '',
+      'sequence' => array (1, 0, 1),
+      'sequence_bc' => array(1, 0, 1),
+      // Not in schema and therefore should be left untouched.
+      'not_present_in_schema' => TRUE,
+      // Test a custom type.
+      'config_schema_test_integer' => '1',
+      'config_schema_test_integer_empty_string' => '',
+    );
+    $untyped_to_typed = $untyped_values;
+
+    $typed_values = array(
+      'string' => '1',
+      'empty_string' => '',
+      'null_string' => NULL,
+      'integer' => 100,
+      'null_integer' => NULL,
+      'boolean' => TRUE,
+      'no_type' => 1,
+      'mapping' => array(
+        'string' => '1'
+      ),
+      'float' => 3.14,
+      'null_float' => NULL,
+      'sequence' => array (TRUE, FALSE, TRUE),
+      'sequence_bc' => array(TRUE, FALSE, TRUE),
+      'not_present_in_schema' => TRUE,
+      'config_schema_test_integer' => 1,
+      'config_schema_test_integer_empty_string' => NULL,
+    );
+
+    // Save config which has a schema that enforces types.
+    $this->config('config_schema_test.schema_data_types')
+      ->setData($untyped_to_typed)
+      ->save();
+    $this->assertIdentical($this->config('config_schema_test.schema_data_types')->get(), $typed_values);
+
+    // Save config which does not have a schema that enforces types.
+    $this->config('config_schema_test.no_schema_data_types')
+      ->setData($untyped_values)
+      ->save();
+    $this->assertIdentical($this->config('config_schema_test.no_schema_data_types')->get(), $untyped_values);
+
+    // Ensure that configuration objects with keys marked as ignored are not
+    // changed when saved. The 'config_schema_test.ignore' will have been saved
+    // during the installation of configuration in the setUp method.
+    $extension_path = drupal_get_path('module', 'config_schema_test');
+    $install_storage = new FileStorage($extension_path . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY);
+    $original_data = $install_storage->read('config_schema_test.ignore');
+    $installed_data = $this->config('config_schema_test.ignore')->get();
+    unset($installed_data['_core']);
+    $this->assertIdentical($installed_data, $original_data);
+  }
+
+  /**
+   * Tests fallback to a greedy wildcard.
+   */
+  function testSchemaFallback() {
+    $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.wildcard_fallback.something');
+    // This should be the schema of config_schema_test.wildcard_fallback.*.
+    $expected = array();
+    $expected['label'] = 'Schema wildcard fallback test';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
+    $expected['mapping']['langcode']['type'] = 'string';
+    $expected['mapping']['langcode']['label'] = 'Language code';
+    $expected['mapping']['_core']['type'] = '_core_config_info';
+    $expected['mapping']['testid']['type'] = 'string';
+    $expected['mapping']['testid']['label'] = 'ID';
+    $expected['mapping']['testdescription']['type'] = 'text';
+    $expected['mapping']['testdescription']['label'] = 'Description';
+    $expected['type'] = 'config_schema_test.wildcard_fallback.*';
+
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_schema_test.wildcard_fallback.something');
+
+    $definition2 = \Drupal::service('config.typed')->getDefinition('config_schema_test.wildcard_fallback.something.something');
+    // This should be the schema of config_schema_test.wildcard_fallback.* as
+    //well.
+    $this->assertIdentical($definition, $definition2);
+  }
+
+  /**
+   * Tests use of colons in schema type determination.
+   *
+   * @see \Drupal\Core\Config\TypedConfigManager::getFallbackName()
+   */
+  function testColonsInSchemaTypeDetermination() {
+    $tests = \Drupal::service('config.typed')->get('config_schema_test.plugin_types')->get('tests')->getElements();
+    $definition = $tests[0]->getDataDefinition()->toArray();
+    $this->assertEqual($definition['type'], 'test.plugin_types.boolean');
+
+    $definition = $tests[1]->getDataDefinition()->toArray();
+    $this->assertEqual($definition['type'], 'test.plugin_types.boolean:*');
+
+    $definition = $tests[2]->getDataDefinition()->toArray();
+    $this->assertEqual($definition['type'], 'test.plugin_types.*');
+
+    $definition = $tests[3]->getDataDefinition()->toArray();
+    $this->assertEqual($definition['type'], 'test.plugin_types.*');
+
+    $tests = \Drupal::service('config.typed')->get('config_schema_test.plugin_types')->get('test_with_parents')->getElements();
+    $definition = $tests[0]->get('settings')->getDataDefinition()->toArray();
+    $this->assertEqual($definition['type'], 'test_with_parents.plugin_types.boolean');
+
+    $definition = $tests[1]->get('settings')->getDataDefinition()->toArray();
+    $this->assertEqual($definition['type'], 'test_with_parents.plugin_types.boolean:*');
+
+    $definition = $tests[2]->get('settings')->getDataDefinition()->toArray();
+    $this->assertEqual($definition['type'], 'test_with_parents.plugin_types.*');
+
+    $definition = $tests[3]->get('settings')->getDataDefinition()->toArray();
+    $this->assertEqual($definition['type'], 'test_with_parents.plugin_types.*');
+  }
+
+  /**
+   * Tests hook_config_schema_info_alter().
+   */
+  public function testConfigSchemaInfoAlter() {
+    /** @var \Drupal\Core\Config\TypedConfigManagerInterface $typed_config */
+    $typed_config = \Drupal::service('config.typed');
+    $typed_config->clearCachedDefinitions();
+
+    // Ensure that keys can not be added or removed by
+    // hook_config_schema_info_alter().
+    \Drupal::state()->set('config_schema_test_exception_remove', TRUE);
+    $message = 'Expected ConfigSchemaAlterException thrown.';
+    try {
+      $typed_config->getDefinitions();
+      $this->fail($message);
+    }
+    catch (ConfigSchemaAlterException $e) {
+      $this->pass($message);
+      $this->assertEqual($e->getMessage(), 'Invoking hook_config_schema_info_alter() has removed (config_schema_test.hook) schema definitions');
+    }
+
+    \Drupal::state()->set('config_schema_test_exception_add', TRUE);
+    $message = 'Expected ConfigSchemaAlterException thrown.';
+    try {
+      $typed_config->getDefinitions();
+      $this->fail($message);
+    }
+    catch (ConfigSchemaAlterException $e) {
+      $this->pass($message);
+      $this->assertEqual($e->getMessage(), 'Invoking hook_config_schema_info_alter() has added (config_schema_test.hook_added_defintion) and removed (config_schema_test.hook) schema definitions');
+    }
+
+    \Drupal::state()->set('config_schema_test_exception_remove', FALSE);
+    $message = 'Expected ConfigSchemaAlterException thrown.';
+    try {
+      $typed_config->getDefinitions();
+      $this->fail($message);
+    }
+    catch (ConfigSchemaAlterException $e) {
+      $this->pass($message);
+      $this->assertEqual($e->getMessage(), 'Invoking hook_config_schema_info_alter() has added (config_schema_test.hook_added_defintion) schema definitions');
+    }
+
+    // Tests that hook_config_schema_info_alter() can add additional metadata to
+    // existing configuration schema.
+    \Drupal::state()->set('config_schema_test_exception_add', FALSE);
+    $definitions = $typed_config->getDefinitions();
+    $this->assertEqual($definitions['config_schema_test.hook']['additional_metadata'], 'new schema info');
+  }
+
+  /**
+   * Tests saving config when the type is wrapped by a dynamic type.
+   */
+  public function testConfigSaveWithWrappingSchema() {
+    $untyped_values = [
+      'tests' => [
+        [
+          'wrapper_value' => 'foo',
+          'plugin_id' => 'wrapper:foo',
+          'internal_value' => 100,
+        ],
+      ],
+    ];
+
+    $typed_values = [
+      'tests' => [
+        [
+          'wrapper_value' => 'foo',
+          'plugin_id' => 'wrapper:foo',
+          'internal_value' => '100',
+        ],
+      ],
+    ];
+
+    // Save config which has a schema that enforces types.
+    \Drupal::configFactory()->getEditable('wrapping.config_schema_test.plugin_types')
+      ->setData($untyped_values)
+      ->save();
+    $this->assertIdentical(\Drupal::config('wrapping.config_schema_test.plugin_types')
+      ->get(), $typed_values);
+  }
+
+  /**
+   * Tests dynamic config schema type with multiple sub-key references.
+   */
+  public function testConfigSaveWithWrappingSchemaDoubleBrackets() {
+    $untyped_values = [
+      'tests' => [
+        [
+          'wrapper_value' => 'foo',
+          'foo' => 'cat',
+          'bar' => 'dog',
+          'another_key' => 100,
+        ],
+      ],
+    ];
+
+    $typed_values = [
+      'tests' => [
+        [
+          'wrapper_value' => 'foo',
+          'foo' => 'cat',
+          'bar' => 'dog',
+          'another_key' => '100',
+        ],
+      ],
+    ];
+
+    // Save config which has a schema that enforces types.
+    \Drupal::configFactory()->getEditable('wrapping.config_schema_test.double_brackets')
+      ->setData($untyped_values)
+      ->save();
+    $this->assertIdentical(\Drupal::config('wrapping.config_schema_test.double_brackets')
+      ->get(), $typed_values);
+  }
+
+}
diff --git a/core/modules/config/tests/src/Kernel/ConfigSnapshotTest.php b/core/modules/config/tests/src/Kernel/ConfigSnapshotTest.php
new file mode 100644
index 0000000..88cae6f
--- /dev/null
+++ b/core/modules/config/tests/src/Kernel/ConfigSnapshotTest.php
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\ConfigSnapshotTest.
+ */
+
+namespace Drupal\Tests\config\Kernel;
+
+use Drupal\Core\Config\StorageComparer;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests config snapshot creation and updating.
+ *
+ * @group config
+ */
+class ConfigSnapshotTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('config_test', 'system');
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    // Update the config snapshot. This allows the parent::setUp() to write
+    // configuration files.
+    \Drupal::service('config.manager')->createSnapshot(\Drupal::service('config.storage'), \Drupal::service('config.storage.snapshot'));
+    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
+  }
+
+  /**
+   * Tests config snapshot creation and updating.
+   */
+  function testSnapshot() {
+    $active = $this->container->get('config.storage');
+    $sync = $this->container->get('config.storage.sync');
+    $snapshot = $this->container->get('config.storage.snapshot');
+    $config_manager = $this->container->get('config.manager');
+    $config_name = 'config_test.system';
+    $config_key = 'foo';
+    $new_data = 'foobar';
+
+    $active_snapshot_comparer = new StorageComparer($active, $snapshot, $config_manager);
+    $sync_snapshot_comparer = new StorageComparer($sync, $snapshot, $config_manager);
+
+    // Verify that we have an initial snapshot that matches the active
+    // configuration. This has to be true as no config should be installed.
+    $this->assertFalse($active_snapshot_comparer->createChangelist()->hasChanges());
+
+    // Install the default config.
+    $this->installConfig(array('config_test'));
+    // Although we have imported config this has not affected the snapshot.
+    $this->assertTrue($active_snapshot_comparer->reset()->hasChanges());
+
+    // Update the config snapshot.
+    \Drupal::service('config.manager')->createSnapshot($active, $snapshot);
+
+    // The snapshot and active config should now contain the same config
+    // objects.
+    $this->assertFalse($active_snapshot_comparer->reset()->hasChanges());
+
+    // Change a configuration value in sync.
+    $sync_data = $this->config($config_name)->get();
+    $sync_data[$config_key] = $new_data;
+    $sync->write($config_name, $sync_data);
+
+    // Verify that active and snapshot match, and that sync doesn't match
+    // active.
+    $this->assertFalse($active_snapshot_comparer->reset()->hasChanges());
+    $this->assertTrue($sync_snapshot_comparer->createChangelist()->hasChanges());
+
+    // Import changed data from sync to active.
+    $this->configImporter()->import();
+
+    // Verify changed config was properly imported.
+    \Drupal::configFactory()->reset($config_name);
+    $this->assertIdentical($this->config($config_name)->get($config_key), $new_data);
+
+    // Verify that a new snapshot was created which and that it matches
+    // the active config.
+    $this->assertFalse($active_snapshot_comparer->reset()->hasChanges());
+  }
+
+}
diff --git a/core/modules/config/tests/src/Kernel/DefaultConfigTest.php b/core/modules/config/tests/src/Kernel/DefaultConfigTest.php
new file mode 100644
index 0000000..81dfa8c
--- /dev/null
+++ b/core/modules/config/tests/src/Kernel/DefaultConfigTest.php
@@ -0,0 +1,84 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\DefaultConfigTest.
+ */
+
+namespace Drupal\Tests\config\Kernel;
+
+use Drupal\config_test\TestInstallStorage;
+use Drupal\Core\Config\InstallStorage;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\KernelTests\KernelTestBase;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * Tests that default configuration provided by all modules matches schema.
+ *
+ * @group config
+ */
+class DefaultConfigTest extends KernelTestBase {
+
+  use SchemaCheckTestTrait;
+
+  /**
+   * Modules to enable.
+   *
+   * Enable the system module so that system_config_schema_info_alter() fires.
+   *
+   * @var array
+   */
+  public static $modules = array('system', 'config_test');
+
+  /**
+   * Themes which provide default configuration and need enabling.
+   *
+   * If a theme provides default configuration but does not have a schema
+   * because it can rely on schemas added by system_config_schema_info_alter()
+   * then this test needs to enable it.
+   *
+   * @var array
+   */
+  protected $themes = ['seven'];
+
+  protected function setUp() {
+    parent::setUp();
+    \Drupal::service('theme_handler')->install($this->themes);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function containerBuild(ContainerBuilder $container) {
+    parent::containerBuild($container);
+    $container->register('default_config_test.schema_storage')
+      ->setClass('\Drupal\config_test\TestInstallStorage')
+      ->addArgument(InstallStorage::CONFIG_SCHEMA_DIRECTORY);
+
+    $definition = $container->getDefinition('config.typed');
+    $definition->replaceArgument(1, new Reference('default_config_test.schema_storage'));
+  }
+
+  /**
+   * Tests default configuration data type.
+   */
+  public function testDefaultConfig() {
+    $typed_config = \Drupal::service('config.typed');
+    // Create a configuration storage with access to default configuration in
+    // every module, profile and theme.
+    $default_config_storage = new TestInstallStorage();
+
+    foreach ($default_config_storage->listAll() as $config_name) {
+      // Skip files provided by the config_schema_test module since that module
+      // is explicitly for testing schema.
+      if (strpos($config_name, 'config_schema_test') === 0) {
+        continue;
+      }
+
+      $data = $default_config_storage->read($config_name);
+      $this->assertConfigSchema($typed_config, $config_name, $data);
+    }
+  }
+
+}
diff --git a/core/modules/config/tests/src/Kernel/SchemaCheckTraitTest.php b/core/modules/config/tests/src/Kernel/SchemaCheckTraitTest.php
new file mode 100644
index 0000000..866bbdd
--- /dev/null
+++ b/core/modules/config/tests/src/Kernel/SchemaCheckTraitTest.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config\Tests\SchemaCheckTraitTest.
+ */
+
+namespace Drupal\Tests\config\Kernel;
+
+use Drupal\Core\Config\Schema\SchemaCheckTrait;
+use Drupal\KernelTests\KernelTestBase;
+
+
+/**
+ * Tests the functionality of SchemaCheckTrait.
+ *
+ * @group config
+ */
+class SchemaCheckTraitTest extends KernelTestBase {
+
+  use SchemaCheckTrait;
+
+  /**
+   * The typed config manager.
+   *
+   * @var \Drupal\Core\Config\TypedConfigManagerInterface
+   */
+  protected $typedConfig;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('config_test', 'config_schema_test');
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->installConfig(array('config_test', 'config_schema_test'));
+    $this->typedConfig = \Drupal::service('config.typed');
+  }
+
+  /**
+   * Tests \Drupal\Core\Config\Schema\SchemaCheckTrait.
+   */
+  public function testTrait() {
+    // Test a non existing schema.
+    $ret = $this->checkConfigSchema($this->typedConfig, 'config_schema_test.noschema', $this->config('config_schema_test.noschema')->get());
+    $this->assertIdentical($ret, FALSE);
+
+    // Test an existing schema with valid data.
+    $config_data = $this->config('config_test.types')->get();
+    $ret = $this->checkConfigSchema($this->typedConfig, 'config_test.types', $config_data);
+    $this->assertIdentical($ret, TRUE);
+
+    // Add a new key, a new array and overwrite boolean with array to test the
+    // error messages.
+    $config_data = array('new_key' => 'new_value', 'new_array' => array()) + $config_data;
+    $config_data['boolean'] = array();
+    $ret = $this->checkConfigSchema($this->typedConfig, 'config_test.types', $config_data);
+    $expected = array(
+      'config_test.types:new_key' => 'missing schema',
+      'config_test.types:new_array' => 'missing schema',
+      'config_test.types:boolean' => 'non-scalar value but not defined as an array (such as mapping or sequence)',
+    );
+    $this->assertEqual($ret, $expected);
+  }
+
+}
