class ConfigCRUDTest

Same name in other branches
  1. 9 core/tests/Drupal/KernelTests/Core/Config/ConfigCRUDTest.php \Drupal\KernelTests\Core\Config\ConfigCRUDTest
  2. 8.9.x core/tests/Drupal/KernelTests/Core/Config/ConfigCRUDTest.php \Drupal\KernelTests\Core\Config\ConfigCRUDTest
  3. 11.x core/tests/Drupal/KernelTests/Core/Config/ConfigCRUDTest.php \Drupal\KernelTests\Core\Config\ConfigCRUDTest

Tests CRUD operations on configuration objects.

@group config

Hierarchy

Expanded class hierarchy of ConfigCRUDTest

File

core/tests/Drupal/KernelTests/Core/Config/ConfigCRUDTest.php, line 20

Namespace

Drupal\KernelTests\Core\Config
View source
class ConfigCRUDTest extends KernelTestBase {
    
    /**
     * Exempt from strict schema checking.
     *
     * @see \Drupal\Core\Config\Development\ConfigSchemaChecker
     *
     * @var bool
     */
    protected $strictConfigSchema = FALSE;
    
    /**
     * {@inheritdoc}
     */
    protected static $modules = [
        'system',
    ];
    
    /**
     * Tests CRUD operations.
     */
    public function testCRUD() : void {
        $event_dispatcher = $this->container
            ->get('event_dispatcher');
        $typed_config_manager = $this->container
            ->get('config.typed');
        $storage = $this->container
            ->get('config.storage');
        $collection_storage = $storage->createCollection('test_collection');
        $config_factory = $this->container
            ->get('config.factory');
        $name = 'config_test.crud';
        // Create a new configuration object in the default collection.
        $config = $this->config($name);
        $this->assertTrue($config->isNew());
        $config->set('value', 'initial');
        $config->save();
        $this->assertFalse($config->isNew());
        // Verify the active configuration contains the saved value.
        $actual_data = $storage->read($name);
        $this->assertSame([
            'value' => 'initial',
        ], $actual_data);
        // Verify the config factory contains the saved value.
        $actual_data = $config_factory->get($name)
            ->getRawData();
        $this->assertSame([
            'value' => 'initial',
        ], $actual_data);
        // Create another instance of the config object using a custom collection.
        $collection_config = new Config($name, $collection_storage, $event_dispatcher, $typed_config_manager);
        $collection_config->set('value', 'overridden');
        $collection_config->save();
        // Verify that the config factory still returns the right value, from the
        // config instance in the default collection.
        $actual_data = $config_factory->get($name)
            ->getRawData();
        $this->assertSame([
            'value' => 'initial',
        ], $actual_data);
        // Update the configuration object instance.
        $config->set('value', 'instance-update');
        $config->save();
        $this->assertFalse($config->isNew());
        // Verify the active configuration contains the updated value.
        $actual_data = $storage->read($name);
        $this->assertSame([
            'value' => 'instance-update',
        ], $actual_data);
        // Verify a call to $this->config() immediately returns the updated value.
        $new_config = $this->config($name);
        $this->assertSame($config->get(), $new_config->get());
        $this->assertFalse($config->isNew());
        // Pollute the config factory static cache.
        $config_factory->getEditable($name);
        // Delete the config object that uses a custom collection. This should not
        // affect the instance returned by the config factory which depends on the
        // default collection storage.
        $collection_config->delete();
        $actual_config = $config_factory->get($name);
        $this->assertFalse($actual_config->isNew());
        $this->assertSame([
            'value' => 'instance-update',
        ], $actual_config->getRawData());
        // Delete the configuration object.
        $config->delete();
        // Verify the configuration object is empty.
        $this->assertSame([], $config->get());
        $this->assertTrue($config->isNew());
        // Verify that all copies of the configuration has been removed from the
        // static cache.
        $this->assertTrue($config_factory->getEditable($name)
            ->isNew());
        // Verify the active configuration contains no value.
        $actual_data = $storage->read($name);
        $this->assertFalse($actual_data);
        // Verify $this->config() returns no data.
        $new_config = $this->config($name);
        $this->assertSame($config->get(), $new_config->get());
        $this->assertTrue($config->isNew());
        // Re-create the configuration object.
        $config->set('value', 're-created');
        $config->save();
        $this->assertFalse($config->isNew());
        // Verify the active configuration contains the updated value.
        $actual_data = $storage->read($name);
        $this->assertSame([
            'value' => 're-created',
        ], $actual_data);
        // Verify a call to $this->config() immediately returns the updated value.
        $new_config = $this->config($name);
        $this->assertSame($config->get(), $new_config->get());
        $this->assertFalse($config->isNew());
        // Rename the configuration object.
        $new_name = 'config_test.crud_rename';
        $this->container
            ->get('config.factory')
            ->rename($name, $new_name);
        $renamed_config = $this->config($new_name);
        $this->assertSame($config->get(), $renamed_config->get());
        $this->assertFalse($renamed_config->isNew());
        // Ensure that the old configuration object is removed from both the cache
        // and the configuration storage.
        $config = $this->config($name);
        $this->assertSame([], $config->get());
        $this->assertTrue($config->isNew());
        // Test renaming when config.factory does not have the object in its static
        // cache.
        $name = 'config_test.crud_rename';
        // Pollute the non-overrides static cache.
        $config_factory->getEditable($name);
        // Pollute the overrides static cache.
        $config = $config_factory->get($name);
        // Rename and ensure that happened properly.
        $new_name = 'config_test.crud_rename_no_cache';
        $config_factory->rename($name, $new_name);
        $renamed_config = $config_factory->get($new_name);
        $this->assertSame($config->get(), $renamed_config->get());
        $this->assertFalse($renamed_config->isNew());
        // Ensure the overrides static cache has been cleared.
        $this->assertTrue($config_factory->get($name)
            ->isNew());
        // Ensure the non-overrides static cache has been cleared.
        $this->assertTrue($config_factory->getEditable($name)
            ->isNew());
        // Merge data into the configuration object.
        $new_config = $this->config($new_name);
        $expected_values = [
            'value' => 'herp',
            '404' => 'foo',
        ];
        $new_config->merge($expected_values);
        $new_config->save();
        $this->assertSame($expected_values['value'], $new_config->get('value'));
        $this->assertSame($expected_values['404'], $new_config->get('404'));
        // Test that getMultiple() does not return new config objects that were
        // previously accessed with get()
        $new_config = $config_factory->get('non_existing_key');
        $this->assertTrue($new_config->isNew());
        $this->assertCount(0, $config_factory->loadMultiple([
            'non_existing_key',
        ]), 'loadMultiple() does not return new objects');
    }
    
    /**
     * Tests the validation of configuration object names.
     */
    public function testNameValidation() : void {
        // Verify that an object name without namespace causes an exception.
        $name = 'no_namespace';
        try {
            $this->config($name)
                ->save();
            $this->fail('Expected ConfigNameException was thrown for a name without a namespace.');
        } catch (\Exception $e) {
            $this->assertInstanceOf(ConfigNameException::class, $e);
        }
        // Verify that a name longer than the maximum length causes an exception.
        $name = 'config_test.herman_melville.dick_or_the_whale.harper_1851.now_small_fowls_flew_screaming_over_the_yet_yawning_gulf_a_sullen_white_surf_beat_against_its_steep_sides_then_all_collapsed_and_the_great_shroud_of_the_sea_rolled_on_as_it_rolled_five_thousand_years_ago';
        try {
            $this->config($name)
                ->save();
            $this->fail('Expected ConfigNameException was thrown for a name longer than Config::MAX_NAME_LENGTH.');
        } catch (\Exception $e) {
            $this->assertInstanceOf(ConfigNameException::class, $e);
        }
        // Verify that disallowed characters in the name cause an exception.
        $characters = $test_characters = [
            ':',
            '?',
            '*',
            '<',
            '>',
            '"',
            '\'',
            '/',
            '\\',
        ];
        foreach ($test_characters as $i => $c) {
            try {
                $name = 'namespace.object' . $c;
                $config = $this->config($name);
                $config->save();
            } catch (ConfigNameException $e) {
                unset($test_characters[$i]);
            }
        }
        $this->assertEmpty($test_characters, sprintf('Expected ConfigNameException was thrown for all invalid name characters: %s', implode(' ', $characters)));
        // Verify that a valid config object name can be saved.
        $name = 'namespace.object';
        try {
            $config = $this->config($name);
            $config->save();
        } catch (ConfigNameException $e) {
            $this->fail('ConfigNameException was not thrown for a valid object name.');
        }
    }
    
    /**
     * Tests the validation of configuration object values.
     */
    public function testValueValidation() : void {
        // Verify that setData() will catch dotted keys.
        try {
            $this->config('namespace.object')
                ->setData([
                'key.value' => 12,
            ])
                ->save();
            $this->fail('Expected ConfigValueException was thrown from setData() for value with dotted keys.');
        } catch (\Exception $e) {
            $this->assertInstanceOf(ConfigValueException::class, $e);
        }
        // Verify that set() will catch dotted keys.
        try {
            $this->config('namespace.object')
                ->set('foo', [
                'key.value' => 12,
            ])
                ->save();
            $this->fail('Expected ConfigValueException was thrown from set() for value with dotted keys.');
        } catch (\Exception $e) {
            $this->assertInstanceOf(ConfigValueException::class, $e);
        }
    }
    
    /**
     * Tests data type handling.
     */
    public function testDataTypes() : void {
        \Drupal::service('module_installer')->install([
            'config_test',
        ]);
        $storage = new DatabaseStorage($this->container
            ->get('database'), 'config');
        $name = 'config_test.types';
        $config = $this->config($name);
        // Verify variable data types are intact.
        $data = [
            'array' => [],
            'boolean' => TRUE,
            'exp' => 1.2E+34,
            'float' => 3.14159,
            'float_as_integer' => (double) 1,
            'hex' => 0xc,
            'int' => 99,
            // Symfony 5.1's YAML parser issues a deprecation when reading octal with
            // a leading zero, to comply with YAML 1.2. However PECL YAML is still
            // YAML 1.1 compliant.
            // @todo Revisit parsing of octal once PECL YAML supports YAML 1.2.
            //   https://www.drupal.org/project/drupal/issues/3205480
            //   'octal' => 0775,
'string' => 'string',
            'string_int' => '1',
            'nullable_array' => NULL,
            'nullable_boolean' => NULL,
            'nullable_exp' => NULL,
            'nullable_float' => NULL,
            'nullable_float_as_integer' => NULL,
            'nullable_hex' => NULL,
            'nullable_int' => NULL,
            'nullable_octal' => NULL,
            'nullable_string' => NULL,
            'nullable_string_int' => NULL,
            'mapping_with_only_required_keys' => [],
            'mapping_with_some_required_keys' => [],
            'mapping_with_only_optional_keys' => [],
        ];
        $data = [
            '_core' => [
                'default_config_hash' => Crypt::hashBase64(serialize($data)),
            ],
        ] + $data;
        $this->assertSame($data, $config->get());
        // Re-set each key using Config::set().
        foreach ($data as $key => $value) {
            $config->set($key, $value);
        }
        $config->save();
        $this->assertSame($data, $config->get());
        // Assert the data against the file storage.
        $this->assertSame($data, $storage->read($name));
        // Set data using config::setData().
        $config->setData($data)
            ->save();
        $this->assertSame($data, $config->get());
        $this->assertSame($data, $storage->read($name));
        // Test that schema type enforcement can be overridden by trusting the data.
        $this->assertSame(99, $config->get('int'));
        $config->set('int', '99')
            ->save(TRUE);
        $this->assertSame('99', $config->get('int'));
        // Test that re-saving without testing the data enforces the schema type.
        $config->save();
        $this->assertSame($data, $config->get());
        // Test that setting an unsupported type for a config object with a schema
        // fails.
        try {
            $config->set('stream', fopen(__FILE__, 'r'))
                ->save();
            $this->fail('No Exception thrown upon saving invalid data type.');
        } catch (UnsupportedDataTypeConfigException $e) {
            // Expected exception; just continue testing.
        }
        // Test that setting an unsupported type for a config object with no schema
        // also fails.
        $typed_config_manager = $this->container
            ->get('config.typed');
        $config_name = 'config_test.no_schema';
        $config = $this->config($config_name);
        $this->assertFalse($typed_config_manager->hasConfigSchema($config_name));
        try {
            $config->set('stream', fopen(__FILE__, 'r'))
                ->save();
            $this->fail('No Exception thrown upon saving invalid data type.');
        } catch (UnsupportedDataTypeConfigException $e) {
            // Expected exception; just continue testing.
        }
    }

}

Members

Title Sort descending Deprecated Modifiers Object type Summary Overriden Title Overrides
AssertContentTrait::$content protected property The current raw content.
AssertContentTrait::$drupalSettings protected property The drupalSettings value from the current raw $content.
AssertContentTrait::$elements protected property The XML structure parsed from the current raw $content. 1
AssertContentTrait::$plainTextContent protected property The plain-text content of raw $content (text nodes).
AssertContentTrait::assertEscaped protected function Passes if the raw text IS found escaped on the loaded page, fail otherwise.
AssertContentTrait::assertField protected function Asserts that a field exists with the given name or ID.
AssertContentTrait::assertFieldById protected function Asserts that a field exists with the given ID and value.
AssertContentTrait::assertFieldByName protected function Asserts that a field exists with the given name and value.
AssertContentTrait::assertFieldByXPath protected function Asserts that a field exists in the current page by the given XPath.
AssertContentTrait::assertFieldChecked protected function Asserts that a checkbox field in the current page is checked.
AssertContentTrait::assertFieldsByValue protected function Asserts that a field exists in the current page with a given Xpath result.
AssertContentTrait::assertLink protected function Passes if a link with the specified label is found.
AssertContentTrait::assertLinkByHref protected function Passes if a link containing a given href (part) is found.
AssertContentTrait::assertNoDuplicateIds protected function Asserts that each HTML ID is used for just a single element.
AssertContentTrait::assertNoEscaped protected function Passes if raw text IS NOT found escaped on loaded page, fail otherwise.
AssertContentTrait::assertNoField protected function Asserts that a field does not exist with the given name or ID.
AssertContentTrait::assertNoFieldById protected function Asserts that a field does not exist with the given ID and value.
AssertContentTrait::assertNoFieldByName protected function Asserts that a field does not exist with the given name and value.
AssertContentTrait::assertNoFieldByXPath protected function Asserts that a field does not exist or its value does not match, by XPath.
AssertContentTrait::assertNoFieldChecked protected function Asserts that a checkbox field in the current page is not checked.
AssertContentTrait::assertNoLink protected function Passes if a link with the specified label is not found.
AssertContentTrait::assertNoLinkByHref protected function Passes if a link containing a given href (part) is not found.
AssertContentTrait::assertNoLinkByHrefInMainRegion protected function Passes if a link containing a given href is not found in the main region.
AssertContentTrait::assertNoOption protected function Asserts that a select option in the current page does not exist.
AssertContentTrait::assertNoOptionSelected protected function Asserts that a select option in the current page is not checked.
AssertContentTrait::assertNoPattern protected function Triggers a pass if the perl regex pattern is not found in raw content.
AssertContentTrait::assertNoRaw protected function Passes if the raw text is NOT found on the loaded page, fail otherwise.
AssertContentTrait::assertNoText protected function Passes if the page (with HTML stripped) does not contains the text.
AssertContentTrait::assertNoTitle protected function Pass if the page title is not the given string.
AssertContentTrait::assertNoUniqueText protected function Passes if the text is found MORE THAN ONCE on the text version of the page.
AssertContentTrait::assertOption protected function Asserts that a select option in the current page exists.
AssertContentTrait::assertOptionByText protected function Asserts that a select option with the visible text exists.
AssertContentTrait::assertOptionSelected protected function Asserts that a select option in the current page is checked.
AssertContentTrait::assertOptionSelectedWithDrupalSelector protected function Asserts that a select option in the current page is checked.
AssertContentTrait::assertOptionWithDrupalSelector protected function Asserts that a select option in the current page exists.
AssertContentTrait::assertPattern protected function Triggers a pass if the Perl regex pattern is found in the raw content.
AssertContentTrait::assertRaw protected function Passes if the raw text IS found on the loaded page, fail otherwise.
AssertContentTrait::assertText protected function Passes if the page (with HTML stripped) contains the text.
AssertContentTrait::assertTextHelper protected function Helper for assertText and assertNoText.
AssertContentTrait::assertTextPattern protected function Asserts that a Perl regex pattern is found in the plain-text content.
AssertContentTrait::assertThemeOutput protected function Asserts themed output.
AssertContentTrait::assertTitle protected function Pass if the page title is the given string.
AssertContentTrait::assertUniqueText protected function Passes if the text is found ONLY ONCE on the text version of the page.
AssertContentTrait::assertUniqueTextHelper protected function Helper for assertUniqueText and assertNoUniqueText.
AssertContentTrait::buildXPathQuery protected function Builds an XPath query.
AssertContentTrait::constructFieldXpath protected function Helper: Constructs an XPath for the given set of attributes and value.
AssertContentTrait::cssSelect protected function Searches elements using a CSS selector in the raw content.
AssertContentTrait::getAllOptions protected function Get all option elements, including nested options, in a select.
AssertContentTrait::getDrupalSettings protected function Gets the value of drupalSettings for the currently-loaded page.
AssertContentTrait::getRawContent protected function Gets the current raw content.
AssertContentTrait::getSelectedItem protected function Get the selected value from a select field.
AssertContentTrait::getTextContent protected function Retrieves the plain-text content from the current raw content.
AssertContentTrait::parse protected function Parse content returned from curlExec using DOM and SimpleXML.
AssertContentTrait::removeWhiteSpace protected function Removes all white-space between HTML tags from the raw content.
AssertContentTrait::setDrupalSettings protected function Sets the value of drupalSettings for the currently-loaded page.
AssertContentTrait::setRawContent protected function Sets the raw content (e.g. HTML).
AssertContentTrait::xpath protected function Performs an xpath search on the contents of the internal browser.
ConfigCRUDTest::$modules protected static property Modules to install. Overrides KernelTestBase::$modules
ConfigCRUDTest::$strictConfigSchema protected property Exempt from strict schema checking. Overrides KernelTestBase::$strictConfigSchema
ConfigCRUDTest::testCRUD public function Tests CRUD operations.
ConfigCRUDTest::testDataTypes public function Tests data type handling.
ConfigCRUDTest::testNameValidation public function Tests the validation of configuration object names.
ConfigCRUDTest::testValueValidation public function Tests the validation of configuration object values.
ConfigTestTrait::configImporter protected function Returns a ConfigImporter object to import test configuration.
ConfigTestTrait::copyConfig protected function Copies configuration objects from source storage to target storage.
ExtensionListTestTrait::getModulePath protected function Gets the path for the specified module.
ExtensionListTestTrait::getThemePath protected function Gets the path for the specified theme.
KernelTestBase::$backupGlobals protected property Back up and restore any global variables that may be changed by tests.
KernelTestBase::$backupStaticAttributes protected property Back up and restore static class properties that may be changed by tests.
KernelTestBase::$backupStaticAttributesBlacklist protected property Contains a few static class properties for performance.
KernelTestBase::$classLoader protected property
KernelTestBase::$configImporter protected property @todo Move into Config test base class. 6
KernelTestBase::$configSchemaCheckerExclusions protected static property An array of config object names that are excluded from schema checking. 3
KernelTestBase::$container protected property
KernelTestBase::$databasePrefix protected property
KernelTestBase::$keyValue protected property The key_value service that must persist between container rebuilds.
KernelTestBase::$preserveGlobalState protected property Do not forward any global state from the parent process to the processes
that run the actual tests.
KernelTestBase::$root protected property The app root.
KernelTestBase::$runTestInSeparateProcess protected property Kernel tests are run in separate processes because they allow autoloading
of code from extensions. Running the test in a separate process isolates
this behavior from other tests. Subclasses should not override this
property.
KernelTestBase::$siteDirectory protected property
KernelTestBase::$usesSuperUserAccessPolicy protected property Set to TRUE to make user 1 a super user. 7
KernelTestBase::$vfsRoot protected property The virtual filesystem root directory.
KernelTestBase::assertPostConditions protected function 1
KernelTestBase::bootEnvironment protected function Bootstraps a basic test environment.
KernelTestBase::bootKernel protected function Bootstraps a kernel for a test. 1
KernelTestBase::config protected function Configuration accessor for tests. Returns non-overridden configuration.
KernelTestBase::disableModules protected function Disables modules for this test.
KernelTestBase::enableModules protected function Enables modules for this test. 1
KernelTestBase::getConfigSchemaExclusions protected function Gets the config schema exclusions for this test.
KernelTestBase::getDatabaseConnectionInfo protected function Returns the Database connection info to be used for this test. 2
KernelTestBase::getDatabasePrefix public function
KernelTestBase::getExtensionsForModules private function Returns Extension objects for $modules to install.
KernelTestBase::getModulesToEnable private static function Returns the modules to install for this test.
KernelTestBase::initFileCache protected function Initializes the FileCache component.
KernelTestBase::installConfig protected function Installs default configuration for a given list of modules.
KernelTestBase::installEntitySchema protected function Installs the storage schema for a specific entity type.
KernelTestBase::installSchema protected function Installs database tables from a module schema definition.
KernelTestBase::register public function Registers test-specific services. Overrides ServiceProviderInterface::register 27
KernelTestBase::render protected function Renders a render array. 1
KernelTestBase::setInstallProfile protected function Sets the install profile and rebuilds the container to update it.
KernelTestBase::setSetting protected function Sets an in-memory Settings variable.
KernelTestBase::setUp protected function 401
KernelTestBase::setUpBeforeClass public static function 1
KernelTestBase::setUpFilesystem protected function Sets up the filesystem, so things like the file directory. 2
KernelTestBase::stop Deprecated protected function Stops test execution.
KernelTestBase::tearDown protected function 6
KernelTestBase::tearDownCloseDatabaseConnection public function @after
KernelTestBase::vfsDump protected function Dumps the current state of the virtual filesystem to STDOUT.
KernelTestBase::__get public function
KernelTestBase::__sleep public function Prevents serializing any properties.
PhpUnitWarnings::$deprecationWarnings private static property Deprecation warnings from PHPUnit to raise with @trigger_error().
PhpUnitWarnings::addWarning public function Converts PHPUnit deprecation warnings to E_USER_DEPRECATED.
RandomGeneratorTrait::getRandomGenerator protected function Gets the random generator for the utility methods.
RandomGeneratorTrait::randomMachineName protected function Generates a unique random string containing letters and numbers.
RandomGeneratorTrait::randomObject public function Generates a random PHP object.
RandomGeneratorTrait::randomString public function Generates a pseudo-random string of ASCII characters of codes 32 to 126.
RandomGeneratorTrait::randomStringValidate Deprecated public function Callback for random string validation.
StorageCopyTrait::replaceStorageContents protected static function Copy the configuration from one storage to another and remove stale items.
TestRequirementsTrait::checkModuleRequirements Deprecated private function Checks missing module requirements.
TestRequirementsTrait::checkRequirements Deprecated protected function Check module requirements for the Drupal use case.
TestRequirementsTrait::getDrupalRoot protected static function Returns the Drupal root directory.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.