diff --git a/core/tests/Drupal/FunctionalTests/Core/Config/SchemaConfigListenerTest.php b/core/tests/Drupal/FunctionalTests/Core/Config/SchemaConfigListenerTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7138c5e80fc7c73b1cc553a770a283ec409b8bf2 --- /dev/null +++ b/core/tests/Drupal/FunctionalTests/Core/Config/SchemaConfigListenerTest.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\FunctionalTests\Core\Config; + +use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\Traits\Core\Config\SchemaConfigListenerTestTrait; + +/** + * Tests the functionality of ConfigSchemaChecker in KernelTestBase tests. + * + * @group config + */ +class SchemaConfigListenerTest extends BrowserTestBase { + + use SchemaConfigListenerTestTrait; + + /** + * {@inheritdoc} + */ + public static $modules = array('config_test'); + +} diff --git a/core/tests/Drupal/KernelTests/Core/Config/SchemaConfigListenerTest.php b/core/tests/Drupal/KernelTests/Core/Config/SchemaConfigListenerTest.php index e87562da445634ab4d793b6c5d0a4f80cd412b12..f07802127799b0dbcdb1c1d6fbb25fa09d781660 100644 --- a/core/tests/Drupal/KernelTests/Core/Config/SchemaConfigListenerTest.php +++ b/core/tests/Drupal/KernelTests/Core/Config/SchemaConfigListenerTest.php @@ -2,8 +2,8 @@ namespace Drupal\KernelTests\Core\Config; -use Drupal\Core\Config\Schema\SchemaIncompleteException; use Drupal\KernelTests\KernelTestBase; +use Drupal\Tests\Traits\Core\Config\SchemaConfigListenerTestTrait; /** * Tests the functionality of ConfigSchemaChecker in KernelTestBase tests. @@ -12,50 +12,22 @@ */ class SchemaConfigListenerTest extends KernelTestBase { + use SchemaConfigListenerTestTrait; + /** * {@inheritdoc} */ public static $modules = array('config_test'); /** - * Tests \Drupal\Core\Config\Testing\ConfigSchemaChecker. + * {@inheritdoc} */ - public function testConfigSchemaChecker() { - // Test a non-existing schema. - $message = 'Expected SchemaIncompleteException thrown'; - try { - $this->config('config_schema_test.schemaless')->set('foo', 'bar')->save(); - $this->fail($message); - } - catch (SchemaIncompleteException $e) { - $this->pass($message); - $this->assertEqual('No schema for config_schema_test.schemaless', $e->getMessage()); - } - - // Test a valid schema. - $message = 'Unexpected SchemaIncompleteException thrown'; - $config = $this->config('config_test.types')->set('int', 10); - try { - $config->save(); - $this->pass($message); - } - catch (SchemaIncompleteException $e) { - $this->fail($message); - } - - // Test an invalid schema. - $message = 'Expected SchemaIncompleteException thrown'; - $config = $this->config('config_test.types') - ->set('foo', 'bar') - ->set('array', 1); - try { - $config->save(); - $this->fail($message); - } - catch (SchemaIncompleteException $e) { - $this->pass($message); - $this->assertEqual('Schema errors for config_test.types with the following errors: config_test.types:foo missing schema, config_test.types:array variable type is integer but applied schema class is Drupal\Core\Config\Schema\Sequence', $e->getMessage()); - } + protected function setUp() { + parent::setUp(); + // Install configuration provided by the module so that the order of the + // config keys is the same as + // \Drupal\FunctionalTests\Core\Config\SchemaConfigListenerTest. + $this->installConfig(['config_test']); } } diff --git a/core/tests/Drupal/Tests/BrowserTestBase.php b/core/tests/Drupal/Tests/BrowserTestBase.php index 01e15d0066b71703715e549dcc008f622eee512b..6a8b150b053fc9589e08507286c07c211c5775e2 100644 --- a/core/tests/Drupal/Tests/BrowserTestBase.php +++ b/core/tests/Drupal/Tests/BrowserTestBase.php @@ -12,6 +12,7 @@ use Drupal\Component\Utility\SafeMarkup; use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Cache\Cache; +use Drupal\Core\Config\Testing\ConfigSchemaChecker; use Drupal\Core\Database\Database; use Drupal\Core\DrupalKernel; use Drupal\Core\Serialization\Yaml; @@ -154,6 +155,31 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase { */ protected $configImporter; + /** + * Set to TRUE to strict check all configuration saved. + * + * @see \Drupal\Core\Config\Testing\ConfigSchemaChecker + * + * @var bool + */ + protected $strictConfigSchema = TRUE; + + /** + * An array of config object names that are excluded from schema checking. + * + * @var string[] + */ + protected static $configSchemaCheckerExclusions = array( + // Following are used to test lack of or partial schema. Where partial + // schema is provided, that is explicitly tested in specific tests. + 'config_schema_test.noschema', + 'config_schema_test.someschema', + 'config_schema_test.schema_data_types', + 'config_schema_test.no_schema_data_types', + // Used to test application of schema to filtering of configuration. + 'config_test.dynamic.system', + ); + /** * The profile to install as a basis for testing. * @@ -990,6 +1016,17 @@ public function installDrupal() { } // Copy the testing-specific service overrides in place. copy($settings_services_file, $directory . '/services.yml'); + if ($this->strictConfigSchema) { + // Add a listener to validate configuration schema on save. + $content = file_get_contents($directory . '/services.yml'); + $services = Yaml::decode($content); + $services['services']['simpletest.config_schema_checker'] = [ + 'class' => ConfigSchemaChecker::class, + 'arguments' => ['@config.typed', $this->getConfigSchemaExclusions()], + 'tags' => [['name' => 'event_subscriber']] + ]; + file_put_contents($directory . '/services.yml', Yaml::encode($services)); + } // Since Drupal is bootstrapped already, install_begin_request() will not // bootstrap into DRUPAL_BOOTSTRAP_CONFIGURATION (again). Hence, we have to @@ -1686,4 +1723,23 @@ protected function setContainerParameter($name, $value) { $file_cache->delete($filename); } + /** + * Gets the config schema exclusions for this test. + * + * @return string[] + * An array of config object names that are excluded from schema checking. + */ + protected function getConfigSchemaExclusions() { + $class = get_class($this); + $exceptions = []; + while ($class) { + if (property_exists($class, 'configSchemaCheckerExclusions')) { + $exceptions = array_merge($exceptions, $class::$configSchemaCheckerExclusions); + } + $class = get_parent_class($class); + } + // Filter out any duplicates. + return array_unique($exceptions); + } + } diff --git a/core/tests/Drupal/Tests/Traits/Core/Config/SchemaConfigListenerTestTrait.php b/core/tests/Drupal/Tests/Traits/Core/Config/SchemaConfigListenerTestTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..02931e4577cabb66f958c6eda9acf3af58a06abe --- /dev/null +++ b/core/tests/Drupal/Tests/Traits/Core/Config/SchemaConfigListenerTestTrait.php @@ -0,0 +1,54 @@ +<?php + +namespace Drupal\Tests\Traits\Core\Config; + +use \Drupal\Core\Config\Schema\SchemaIncompleteException; + +/** + * Adds a test for the configuration schema checker use in tests. + */ +trait SchemaConfigListenerTestTrait { + + /** + * Tests \Drupal\Core\Config\Testing\ConfigSchemaChecker. + */ + public function testConfigSchemaChecker() { + // Test a non-existing schema. + $message = 'Expected SchemaIncompleteException thrown'; + try { + $this->config('config_schema_test.schemaless')->set('foo', 'bar')->save(); + $this->fail($message); + } + catch (SchemaIncompleteException $e) { + $this->pass($message); + $this->assertEqual('No schema for config_schema_test.schemaless', $e->getMessage()); + } + + // Test a valid schema. + $message = 'Unexpected SchemaIncompleteException thrown'; + $config = $this->config('config_test.types')->set('int', 10); + try { + $config->save(); + $this->pass($message); + } + catch (SchemaIncompleteException $e) { + $this->fail($message); + } + + // Test an invalid schema. + $message = 'Expected SchemaIncompleteException thrown'; + $config = $this->config('config_test.types') + ->set('foo', 'bar') + ->set('array', 1); + try { + $config->save(); + $this->fail($message); + } + catch (SchemaIncompleteException $e) { + $this->pass($message); + $this->assertEqual('Schema errors for config_test.types with the following errors: config_test.types:array variable type is integer but applied schema class is Drupal\Core\Config\Schema\Sequence, config_test.types:foo missing schema', $e->getMessage()); + } + + } + +}