Issue #3361534 by Wim Leers, borisson_, longwave, catch: KernelTestBase::$strictConfigSchema = TRUE and BrowserTestBase::$strictConfigSchema = TRUE do not actually strictly validate
parent
29dc14b207
commit
f13ad693c8
|
@ -99,7 +99,9 @@ machine_name:
|
|||
type: string
|
||||
label: 'Machine name'
|
||||
constraints:
|
||||
Regex: '/^[a-z0-9_]+$/'
|
||||
Regex:
|
||||
pattern: '/^[a-z0-9_]+$/'
|
||||
message: "The %value machine name is not valid."
|
||||
Length:
|
||||
# @see \Drupal\Core\Config\Entity\ConfigEntityStorage::MAX_ID_LENGTH
|
||||
max: 166
|
||||
|
@ -233,6 +235,7 @@ theme_settings:
|
|||
label: 'Logo path'
|
||||
url:
|
||||
type: uri
|
||||
nullable: true
|
||||
label: 'URL'
|
||||
use_default:
|
||||
type: boolean
|
||||
|
|
|
@ -9,6 +9,7 @@ use Drupal\Core\TypedData\Type\BooleanInterface;
|
|||
use Drupal\Core\TypedData\Type\StringInterface;
|
||||
use Drupal\Core\TypedData\Type\FloatInterface;
|
||||
use Drupal\Core\TypedData\Type\IntegerInterface;
|
||||
use Symfony\Component\Validator\ConstraintViolation;
|
||||
|
||||
/**
|
||||
* Provides a trait for checking configuration schema.
|
||||
|
@ -57,6 +58,34 @@ trait SchemaCheckTrait {
|
|||
$errors[] = $this->checkValue($key, $value);
|
||||
}
|
||||
$errors = array_merge(...$errors);
|
||||
// Also perform explicit validation. Note this does NOT require every node
|
||||
// in the config schema tree to have validation constraints defined.
|
||||
$violations = $this->schema->validate();
|
||||
$ignored_validation_constraint_messages = [
|
||||
// @see \Drupal\Core\Config\Plugin\Validation\Constraint\ConfigExistsConstraint::$message
|
||||
// @todo Remove this in https://www.drupal.org/project/drupal/issues/3362453
|
||||
"The '.*' config does not exist.",
|
||||
// @see \Drupal\Core\Extension\Plugin\Validation\Constraint\ExtensionExistsConstraint::$moduleMessage
|
||||
// @see \Drupal\Core\Extension\Plugin\Validation\Constraint\ExtensionExistsConstraint::$themeMessage
|
||||
// @todo Remove this in https://www.drupal.org/project/drupal/issues/3362456
|
||||
"Module '.*' is not installed.",
|
||||
"Theme '.*' is not installed.",
|
||||
// @see \Drupal\Core\Plugin\Plugin\Validation\Constraint\PluginExistsConstraint::$unknownPluginMessage
|
||||
// @todo Remove this in https://www.drupal.org/project/drupal/issues/3362457
|
||||
"The '.*' plugin does not exist.",
|
||||
// @see "machine_name" in core.data_types.schema.yml
|
||||
// @todo Remove this in https://www.drupal.org/project/drupal/issues/3372972
|
||||
"The <em class=\"placeholder\">.*<\/em> machine name is not valid.",
|
||||
];
|
||||
$filtered_violations = array_filter(
|
||||
iterator_to_array($violations),
|
||||
fn (ConstraintViolation $v) => preg_match(sprintf("/^(%s)$/", implode('|', $ignored_validation_constraint_messages)), (string) $v->getMessage()) !== 1
|
||||
);
|
||||
$validation_errors = array_map(
|
||||
fn (ConstraintViolation $v) => sprintf("[%s] %s", $v->getPropertyPath(), (string) $v->getMessage()),
|
||||
$filtered_violations
|
||||
);
|
||||
$errors = array_merge($errors, $validation_errors);
|
||||
if (empty($errors)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,9 @@ block.block.*:
|
|||
# @see https://www.drupal.org/project/drupal/issues/2685917
|
||||
# @see https://www.drupal.org/project/drupal/issues/2043527
|
||||
constraints:
|
||||
Regex: '/^[a-z0-9_.]+$/'
|
||||
Regex:
|
||||
pattern: '/^[a-z0-9_.]+$/'
|
||||
message: "The %value machine name is not valid."
|
||||
theme:
|
||||
type: string
|
||||
label: 'Theme'
|
||||
|
|
|
@ -580,6 +580,7 @@ class BlockTest extends BlockTestBase {
|
|||
$block = Block::create([
|
||||
'id' => $this->randomMachineName(),
|
||||
'plugin' => 'system_powered_by_block',
|
||||
'theme' => 'stark',
|
||||
]);
|
||||
|
||||
$block->setVisibilityConfig('user_role', [
|
||||
|
|
|
@ -69,7 +69,7 @@ class BlockContentDeletionTest extends KernelTestBase {
|
|||
$block_content->save();
|
||||
|
||||
$plugin_id = 'block_content' . PluginBase::DERIVATIVE_SEPARATOR . $block_content->uuid();
|
||||
$block = $this->placeBlock($plugin_id, ['region' => 'content']);
|
||||
$block = $this->placeBlock($plugin_id, ['region' => 'content', 'theme' => 'stark']);
|
||||
|
||||
// Delete it via storage.
|
||||
$storage = $this->container->get('entity_type.manager')->getStorage('block_content');
|
||||
|
|
|
@ -12,7 +12,6 @@ use Drupal\ckeditor5\Plugin\CKEditor5PluginManagerInterface;
|
|||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Config\Schema\SchemaCheckTrait;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Form\SubformState;
|
||||
|
@ -50,8 +49,6 @@ use Symfony\Component\Validator\ConstraintViolationListInterface;
|
|||
*/
|
||||
class CKEditor5 extends EditorBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
use SchemaCheckTrait;
|
||||
|
||||
/**
|
||||
* The CKEditor plugin manager.
|
||||
*
|
||||
|
@ -729,8 +726,6 @@ class CKEditor5 extends EditorBase implements ContainerFactoryPluginInterface {
|
|||
// ::getGeneratedAllowedHtmlValue(), to update filter_html's
|
||||
// "allowed_html".
|
||||
$form_state->set('ckeditor5_validated_pair', $eventual_editor_and_format);
|
||||
|
||||
assert(TRUE === $this->checkConfigSchema(\Drupal::getContainer()->get('config.typed'), 'editor.editor.id_does_not_matter', $submitted_editor->toArray()), 'Schema errors: ' . print_r($this->checkConfigSchema(\Drupal::getContainer()->get('config.typed'), 'editor.editor.id_does_not_matter', $submitted_editor->toArray()), TRUE));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -224,7 +224,11 @@ class ImageUploadTest extends BrowserTestBase {
|
|||
'drupalInsertImage',
|
||||
],
|
||||
],
|
||||
'plugins' => [],
|
||||
'plugins' => [
|
||||
'ckeditor5_imageResize' => [
|
||||
'allow_resize' => FALSE,
|
||||
],
|
||||
],
|
||||
],
|
||||
'image_upload' => $upload_config,
|
||||
]);
|
||||
|
|
|
@ -82,6 +82,16 @@ class CKEditor5PluginManagerTest extends KernelTestBase {
|
|||
$this->typedConfig = $this->container->get('config.typed');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function enableModules(array $modules) {
|
||||
parent::enableModules($modules);
|
||||
// Ensure the CKEditor 5 plugin manager instance on the test reflects the
|
||||
// status after the module is installed.
|
||||
$this->manager = $this->container->get('plugin.manager.ckeditor5.plugin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Mocks a module providing a CKEditor 5 plugin in VFS.
|
||||
*
|
||||
|
|
|
@ -541,6 +541,13 @@ class SmartDefaultSettingsTest extends KernelTestBase {
|
|||
|
||||
// Ensure that the result of ::computeSmartDefaultSettings() always complies
|
||||
// with the config schema.
|
||||
// TRICKY: because we're validating using `editor.editor.*` as the config
|
||||
// name, TextEditorObjectDependentValidatorTrait will load the stored filter
|
||||
// format. That has not yet been updated at this point, so in order for
|
||||
// validation to pass, it must first be saved.
|
||||
// @see \Drupal\ckeditor5\Plugin\Validation\Constraint\TextEditorObjectDependentValidatorTrait::createTextEditorObjectFromContext()
|
||||
// @todo Remove this work-around in https://www.drupal.org/project/drupal/issues/3231354
|
||||
$updated_text_editor->getFilterFormat()->save();
|
||||
$this->assertConfigSchema(
|
||||
$this->typedConfig,
|
||||
$updated_text_editor->getConfigDependencyName(),
|
||||
|
|
|
@ -595,20 +595,15 @@ class ValidatorsTest extends KernelTestBase {
|
|||
->set('name', $this->randomString())
|
||||
->save();
|
||||
|
||||
$this->assertConfigSchema(
|
||||
$this->typedConfig,
|
||||
$text_editor->getConfigDependencyName(),
|
||||
$text_editor->toArray()
|
||||
);
|
||||
// TRICKY: only validate the Editor entity in isolation if we expect NO
|
||||
// violations: when violations are expected, this would just find the very
|
||||
// violations that the next assertion is checking.
|
||||
// @todo Remove in https://www.drupal.org/project/drupal/issues/3361534, which moves this into ::assertConfigSchema()
|
||||
// TRICKY: only assert config schema (and validation constraints) if we
|
||||
// expect NO violations: when violations are expected, this would just find
|
||||
// the very violations that the next assertion is checking.
|
||||
if (empty($expected_violations)) {
|
||||
$this->assertSame([], array_map(
|
||||
fn ($v) => sprintf("[%s] %s", $v->getPropertyPath(), (string) $v->getMessage()),
|
||||
iterator_to_array($this->typedConfig->createFromNameAndData($text_editor->getConfigDependencyName(), $text_editor->toArray())->validate())
|
||||
));
|
||||
$this->assertConfigSchema(
|
||||
$this->typedConfig,
|
||||
$text_editor->getConfigDependencyName(),
|
||||
$text_editor->toArray()
|
||||
);
|
||||
}
|
||||
|
||||
$this->assertSame($expected_violations, $this->validatePairToViolationsArray($text_editor, $text_format, TRUE));
|
||||
|
|
|
@ -6,3 +6,4 @@ giraffe:
|
|||
hum1: hum1
|
||||
hum2: hum2
|
||||
uuid: '7C30C50E-641A-4E34-A7F1-46BCFB9BE5A3'
|
||||
langcode: en
|
||||
|
|
|
@ -11,6 +11,9 @@ use Drupal\Tests\system\Functional\Module\ModuleTestBase;
|
|||
/**
|
||||
* Tests the largest configuration import possible with all available modules.
|
||||
*
|
||||
* Note that the use of SchemaCheckTestTrait means that the schema conformance
|
||||
* of all default configuration is also tested.
|
||||
*
|
||||
* @group config
|
||||
*/
|
||||
class ConfigImportAllTest extends ModuleTestBase {
|
||||
|
|
|
@ -204,7 +204,7 @@ class ImageFieldDefaultImagesTest extends ImageFieldTestBase {
|
|||
|
||||
// Remove the field default from articles.
|
||||
$default_image_settings = $field->getSetting('default_image');
|
||||
$default_image_settings['uuid'] = 0;
|
||||
$default_image_settings['uuid'] = \Drupal::service('uuid')->generate();
|
||||
$field->setSetting('default_image', $default_image_settings);
|
||||
$field->save();
|
||||
|
||||
|
|
|
@ -120,6 +120,10 @@ language.content_settings.*.*:
|
|||
default_langcode:
|
||||
type: langcode
|
||||
label: 'Default language'
|
||||
constraints:
|
||||
Choice:
|
||||
# The "default language" has a different list of allowed values.
|
||||
callback: '\Drupal\language\Entity\ContentLanguageSettings::getAllValidDefaultLangcodes'
|
||||
language_alterable:
|
||||
type: boolean
|
||||
label: 'Allow to alter the language'
|
||||
|
|
|
@ -214,4 +214,25 @@ class ContentLanguageSettings extends ConfigEntityBase implements ContentLanguag
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all valid values for the `default_langcode` property.
|
||||
*
|
||||
* @return string[]
|
||||
* All possible valid default langcodes. This includes all langcodes in the
|
||||
* standard list of human languages, along with special langcodes like
|
||||
* `site_default`, `current_interface` and `authors_default`.
|
||||
*
|
||||
* @see \Drupal\language\Element\LanguageConfiguration::getDefaultOptions()
|
||||
* @see \Drupal\Core\TypedData\Plugin\DataType\LanguageReference::getAllValidLangcodes()
|
||||
*/
|
||||
public static function getAllValidDefaultLangcodes(): array {
|
||||
$language_manager = \Drupal::service('language_manager');
|
||||
return array_unique([
|
||||
...array_keys($language_manager->getLanguages(LanguageInterface::STATE_ALL)),
|
||||
LanguageInterface::LANGCODE_SITE_DEFAULT,
|
||||
'current_interface',
|
||||
'authors_default',
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,6 +42,15 @@ use Drupal\block\Entity\Block;
|
|||
*/
|
||||
class LanguageUILanguageNegotiationTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $configSchemaCheckerExclusions = [
|
||||
// Necessary to allow setting `selected_langcode` to NULL.
|
||||
// @see testUILanguageNegotiation()
|
||||
'language.negotiation',
|
||||
];
|
||||
|
||||
/**
|
||||
* The admin user for testing.
|
||||
*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
icon_base_uri: 'public://media-icons/generic'
|
||||
iframe_domain: ''
|
||||
iframe_domain: ~
|
||||
oembed_providers_url: 'https://oembed.com/providers.json'
|
||||
standalone_url: false
|
||||
|
|
|
@ -7,6 +7,7 @@ media.settings:
|
|||
label: 'Full URI to a folder where the media icons will be installed'
|
||||
iframe_domain:
|
||||
type: uri
|
||||
nullable: true
|
||||
label: 'Domain from which to serve oEmbed content in an iframe'
|
||||
oembed_providers_url:
|
||||
type: uri
|
||||
|
|
|
@ -33,3 +33,15 @@ function media_post_update_oembed_loading_attribute(array &$sandbox = NULL): voi
|
|||
return $media_config_updater->processOembedEagerLoadField($view_display);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates media.settings:iframe_domain config if it's still at the default.
|
||||
*/
|
||||
function media_post_update_set_blank_iframe_domain_to_null() {
|
||||
$media_settings = \Drupal::configFactory()->getEditable('media.settings');
|
||||
if ($media_settings->get('iframe_domain') === '') {
|
||||
$media_settings
|
||||
->set('iframe_domain', NULL)
|
||||
->save(TRUE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,8 +117,13 @@ class MediaSettingsForm extends ConfigFormBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$iframe_domain = $form_state->getValue('iframe_domain');
|
||||
// The empty string is not a valid URI, but NULL is allowed.
|
||||
if ($iframe_domain === '') {
|
||||
$iframe_domain = NULL;
|
||||
}
|
||||
$this->config('media.settings')
|
||||
->set('iframe_domain', $form_state->getValue('iframe_domain'))
|
||||
->set('iframe_domain', $iframe_domain)
|
||||
->set('standalone_url', $form_state->getValue('standalone_url'))
|
||||
->save();
|
||||
|
||||
|
|
|
@ -50,3 +50,21 @@ $connection->update('key_value')
|
|||
->condition('name', 'existing_updates')
|
||||
->execute();
|
||||
|
||||
// Create media.settings.
|
||||
$connection->insert('config')
|
||||
->fields([
|
||||
'collection',
|
||||
'name',
|
||||
'data',
|
||||
])
|
||||
->values([
|
||||
'collection' => '',
|
||||
'name' => 'media.settings',
|
||||
'data' => serialize([
|
||||
'icon_base_uri' => 'public://media-icons/generic',
|
||||
'iframe_domain' => '',
|
||||
'oembed_providers_url' => 'https://oembed.com/providers.json',
|
||||
'standalone_url' => FALSE,
|
||||
]),
|
||||
])
|
||||
->execute();
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Drupal\Tests\media\Functional;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Testing the media settings.
|
||||
*
|
||||
|
@ -19,7 +21,10 @@ class MediaSettingsTest extends MediaFunctionalTestBase {
|
|||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->drupalLogin($this->createUser(['administer site configuration']));
|
||||
$this->drupalLogin($this->createUser([
|
||||
'administer site configuration',
|
||||
'administer media',
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,4 +42,25 @@ class MediaSettingsTest extends MediaFunctionalTestBase {
|
|||
$assert_session->pageTextContains('It is potentially insecure to display oEmbed content in a frame');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the media settings form stores a `null` iFrame domain.
|
||||
*/
|
||||
public function testSettingsForm(): void {
|
||||
$assert_session = $this->assertSession();
|
||||
|
||||
$this->assertNull($this->config('media.settings')->get('iframe_domain'));
|
||||
$this->drupalGet(Url::fromRoute('media.settings'));
|
||||
$assert_session->fieldExists('iframe_domain');
|
||||
|
||||
// Explicitly submitting an empty string does not result in the
|
||||
// `iframe_domain` property getting set to the empty string: it is converted
|
||||
// to `null` to comply with the config schema.
|
||||
// @see \Drupal\media\Form\MediaSettingsForm::submitForm()
|
||||
$this->submitForm([
|
||||
'iframe_domain' => '',
|
||||
], 'Save configuration');
|
||||
$assert_session->statusMessageContains('The configuration options have been saved.', 'status');
|
||||
$this->assertNull($this->config('media.settings')->get('iframe_domain'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\media\Functional\Update;
|
||||
|
||||
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
|
||||
use Drupal\Tests\UpdatePathTestTrait;
|
||||
|
||||
/**
|
||||
* Tests update of media.settings:iframe_domain if it's still the default of "".
|
||||
*
|
||||
* @group system
|
||||
* @covers \media_post_update_set_blank_iframe_domain_to_null
|
||||
*/
|
||||
class MediaSettingsDefaultIframeDomainUpdateTest extends UpdatePathTestBase {
|
||||
|
||||
use UpdatePathTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setDatabaseDumpFiles() {
|
||||
$this->databaseDumpFiles = [
|
||||
DRUPAL_ROOT . '/core/modules/system/tests/fixtures/update/drupal-9.4.0.bare.standard.php.gz',
|
||||
__DIR__ . '/../../../fixtures/update/media.php',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
// Because the test manually installs media module, the entity type config
|
||||
// must be manually installed similar to kernel tests.
|
||||
$entity_type_manager = \Drupal::entityTypeManager();
|
||||
$media = $entity_type_manager->getDefinition('media');
|
||||
\Drupal::service('entity_type.listener')->onEntityTypeCreate($media);
|
||||
$media_type = $entity_type_manager->getDefinition('media_type');
|
||||
\Drupal::service('entity_type.listener')->onEntityTypeCreate($media_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests update of media.settings:iframe_domain.
|
||||
*/
|
||||
public function testUpdate() {
|
||||
$iframe_domain_before = $this->config('media.settings')->get('iframe_domain');
|
||||
$this->assertSame('', $iframe_domain_before);
|
||||
|
||||
$this->runUpdates();
|
||||
|
||||
$iframe_domain_after = $this->config('media.settings')->get('iframe_domain');
|
||||
$this->assertNull($iframe_domain_after);
|
||||
}
|
||||
|
||||
}
|
|
@ -11,7 +11,9 @@ shortcut.set.*:
|
|||
# dashes but not underscores.
|
||||
# @see \Drupal\shortcut\ShortcutSetForm::form()
|
||||
constraints:
|
||||
Regex: '/^[a-z0-9-]+$/'
|
||||
Regex:
|
||||
pattern: '/^[a-z0-9-]+$/'
|
||||
message: "The %value machine name is not valid."
|
||||
Length:
|
||||
max: 23
|
||||
label:
|
||||
|
|
|
@ -10,5 +10,5 @@ features:
|
|||
node_user_picture: true
|
||||
logo:
|
||||
path: ''
|
||||
url: ''
|
||||
url: ~
|
||||
use_default: true
|
||||
|
|
|
@ -215,7 +215,9 @@ system.menu.*:
|
|||
# underscores.
|
||||
# @see \Drupal\menu_ui\MenuForm::form()
|
||||
constraints:
|
||||
Regex: '/^[a-z0-9-]+$/'
|
||||
Regex:
|
||||
pattern: '/^[a-z0-9-]+$/'
|
||||
message: "The %value machine name is not valid."
|
||||
Length:
|
||||
max: 32
|
||||
label:
|
||||
|
|
|
@ -146,3 +146,15 @@ function system_post_update_add_description_to_entity_form_mode(array &$sandbox
|
|||
|
||||
$config_entity_updater->update($sandbox, 'entity_form_mode', $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates system.theme.global:logo.url config if it's still at the default.
|
||||
*/
|
||||
function system_post_update_set_blank_log_url_to_null() {
|
||||
$global_theme_settings = \Drupal::configFactory()->getEditable('system.theme.global');
|
||||
if ($global_theme_settings->get('logo.url') === '') {
|
||||
$global_theme_settings
|
||||
->set('logo.url', NULL)
|
||||
->save(TRUE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\system\Functional\Update;
|
||||
|
||||
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
|
||||
use Drupal\Tests\UpdatePathTestTrait;
|
||||
|
||||
/**
|
||||
* Tests update of system.theme.global:logo.url if it's still the default of "".
|
||||
*
|
||||
* @group system
|
||||
* @covers \system_post_update_set_blank_log_url_to_null
|
||||
*/
|
||||
class GlobalThemeSettingsDefaultLogoUrlUpdateTest extends UpdatePathTestBase {
|
||||
|
||||
use UpdatePathTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setDatabaseDumpFiles() {
|
||||
$this->databaseDumpFiles = [
|
||||
DRUPAL_ROOT . '/core/modules/system/tests/fixtures/update/drupal-9.4.0.bare.standard.php.gz',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests update of system.theme.global:logo.url.
|
||||
*/
|
||||
public function testUpdate() {
|
||||
$logo_url_before = $this->config('system.theme.global')->get('logo.url');
|
||||
$this->assertSame('', $logo_url_before);
|
||||
|
||||
$this->runUpdates();
|
||||
|
||||
$logo_url_after = $this->config('system.theme.global')->get('logo.url');
|
||||
$this->assertNull($logo_url_after);
|
||||
}
|
||||
|
||||
}
|
|
@ -2,7 +2,7 @@ check:
|
|||
disabled_extensions: false
|
||||
interval_days: 1
|
||||
fetch:
|
||||
url: ''
|
||||
url: ~
|
||||
max_attempts: 2
|
||||
timeout: 30
|
||||
notification:
|
||||
|
|
|
@ -20,6 +20,7 @@ update.settings:
|
|||
mapping:
|
||||
url:
|
||||
type: uri
|
||||
nullable: true
|
||||
label: 'URL for fetching available update data'
|
||||
max_attempts:
|
||||
type: integer
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\update\Functional\Update;
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
|
||||
use Drupal\Tests\UpdatePathTestTrait;
|
||||
|
||||
/**
|
||||
* Tests update of update.settings:fetch.url if it's still the default of "".
|
||||
*
|
||||
* @group system
|
||||
* @covers \update_post_update_set_blank_fetch_url_to_null
|
||||
*/
|
||||
class UpdateSettingsDefaultFetchUrlUpdateTest extends UpdatePathTestBase {
|
||||
|
||||
use UpdatePathTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setDatabaseDumpFiles() {
|
||||
$this->databaseDumpFiles = [
|
||||
DRUPAL_ROOT . '/core/modules/system/tests/fixtures/update/drupal-9.4.0.bare.standard.php.gz',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$connection = Database::getConnection();
|
||||
|
||||
// Set the schema version.
|
||||
$connection->merge('key_value')
|
||||
->fields([
|
||||
'value' => 'i:8001;',
|
||||
'name' => 'update',
|
||||
'collection' => 'system.schema',
|
||||
])
|
||||
->condition('collection', 'system.schema')
|
||||
->condition('name', 'update')
|
||||
->execute();
|
||||
|
||||
// Update core.extension.
|
||||
$extensions = $connection->select('config')
|
||||
->fields('config', ['data'])
|
||||
->condition('collection', '')
|
||||
->condition('name', 'core.extension')
|
||||
->execute()
|
||||
->fetchField();
|
||||
$extensions = unserialize($extensions);
|
||||
$extensions['module']['update'] = 0;
|
||||
$connection->update('config')
|
||||
->fields(['data' => serialize($extensions)])
|
||||
->condition('collection', '')
|
||||
->condition('name', 'core.extension')
|
||||
->execute();
|
||||
|
||||
// Create update.settings config.
|
||||
$default_update_settings = [
|
||||
'check' => [
|
||||
'disabled_extensions' => FALSE,
|
||||
'interval_days' => 1,
|
||||
],
|
||||
'fetch' => [
|
||||
'url' => '',
|
||||
'max_attempts' => 2,
|
||||
'timeout' => 30,
|
||||
],
|
||||
'notification' => [
|
||||
'emails' => [],
|
||||
'threshold' => 'all',
|
||||
],
|
||||
];
|
||||
$connection->insert('config')
|
||||
->fields([
|
||||
'collection',
|
||||
'name',
|
||||
'data',
|
||||
])
|
||||
->values([
|
||||
'collection' => '',
|
||||
'name' => 'update.settings',
|
||||
'data' => serialize($default_update_settings),
|
||||
])
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests update of update.settings:fetch.url.
|
||||
*/
|
||||
public function testUpdate() {
|
||||
$fetch_url_before = $this->config('update.settings')->get('fetch.url');
|
||||
$this->assertSame('', $fetch_url_before);
|
||||
|
||||
$this->runUpdates();
|
||||
|
||||
$fetch_url_after = $this->config('update.settings')->get('fetch.url');
|
||||
$this->assertNull($fetch_url_after);
|
||||
}
|
||||
|
||||
}
|
|
@ -13,3 +13,15 @@ function update_remove_post_updates() {
|
|||
'update_post_update_add_view_update_notifications_permission' => '10.0.0',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates update.settings:fetch.url config if it's still at the default.
|
||||
*/
|
||||
function update_post_update_set_blank_fetch_url_to_null() {
|
||||
$update_settings = \Drupal::configFactory()->getEditable('update.settings');
|
||||
if ($update_settings->get('fetch.url') === '') {
|
||||
$update_settings
|
||||
->set('fetch.url', NULL)
|
||||
->save(TRUE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ class TestViewsTest extends KernelTestBase {
|
|||
\Drupal::service('module_handler'),
|
||||
\Drupal::service('class_resolver')
|
||||
);
|
||||
$typed_config->setValidationConstraintManager(\Drupal::service('validation.constraint'));
|
||||
|
||||
// Create a configuration storage with access to default configuration in
|
||||
// every module, profile and theme.
|
||||
|
|
|
@ -26,7 +26,7 @@ class AreaEntityUITest extends UITestBase {
|
|||
|
||||
public function testUI() {
|
||||
// Set up a block and an entity_test entity.
|
||||
$block = Block::create(['id' => 'test_id', 'plugin' => 'system_main_block']);
|
||||
$block = Block::create(['id' => 'test_id', 'plugin' => 'system_main_block', 'theme' => 'stark']);
|
||||
$block->save();
|
||||
|
||||
$entity_test = EntityTest::create(['bundle' => 'entity_test']);
|
||||
|
|
|
@ -33,6 +33,9 @@ settings:
|
|||
- heading4
|
||||
- heading5
|
||||
- heading6
|
||||
ckeditor5_list:
|
||||
reversed: false
|
||||
startIndex: false
|
||||
ckeditor5_sourceEditing:
|
||||
allowed_tags:
|
||||
- '<cite>'
|
||||
|
@ -50,6 +53,8 @@ settings:
|
|||
- '<h6 id>'
|
||||
- '<img src alt data-entity-type data-entity-uuid data-align data-caption width height>'
|
||||
- '<drupal-media data-view-mode title>'
|
||||
media_media:
|
||||
allow_view_mode_override: false
|
||||
image_upload:
|
||||
status: false
|
||||
scheme: public
|
||||
|
|
|
@ -38,8 +38,13 @@ settings:
|
|||
- heading4
|
||||
- heading5
|
||||
- heading6
|
||||
ckeditor5_list:
|
||||
reversed: false
|
||||
startIndex: false
|
||||
ckeditor5_sourceEditing:
|
||||
allowed_tags: { }
|
||||
media_media:
|
||||
allow_view_mode_override: false
|
||||
image_upload:
|
||||
status: true
|
||||
scheme: public
|
||||
|
|
|
@ -10,5 +10,5 @@ features:
|
|||
node_user_picture: true
|
||||
logo:
|
||||
path: ''
|
||||
url: ''
|
||||
url: ~
|
||||
use_default: true
|
||||
|
|
|
@ -10,5 +10,5 @@ features:
|
|||
node_user_picture: false
|
||||
logo:
|
||||
path: ''
|
||||
url: ''
|
||||
url: ~
|
||||
use_default: true
|
||||
|
|
|
@ -25,6 +25,11 @@ class TypedConfigTest extends KernelTestBase {
|
|||
*/
|
||||
protected static $modules = ['config_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $configSchemaCheckerExclusions = ['config_test.validation'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -90,7 +95,7 @@ class TypedConfigTest extends KernelTestBase {
|
|||
$typed_config_manager = \Drupal::service('config.typed');
|
||||
$typed_config = $typed_config_manager->createFromNameAndData('config_test.validation', \Drupal::configFactory()->get('config_test.validation')->get());
|
||||
$this->assertInstanceOf(TypedConfigInterface::class, $typed_config);
|
||||
$this->assertEquals(['_core', 'llama', 'cat', 'giraffe', 'uuid'], array_keys($typed_config->getElements()));
|
||||
$this->assertEquals(['_core', 'llama', 'cat', 'giraffe', 'uuid', 'langcode'], array_keys($typed_config->getElements()));
|
||||
$this->assertSame('config_test.validation', $typed_config->getName());
|
||||
$this->assertSame('config_test.validation', $typed_config->getPropertyPath());
|
||||
$this->assertSame('config_test.validation.llama', $typed_config->get('llama')->getPropertyPath());
|
||||
|
|
|
@ -106,14 +106,18 @@ abstract class ConfigEntityValidationTestBase extends KernelTestBase {
|
|||
$constraints = $this->getMachineNameConstraints();
|
||||
|
||||
$this->assertNotEmpty($constraints['Regex']);
|
||||
$this->assertIsString($constraints['Regex']);
|
||||
$this->assertIsArray($constraints['Regex']);
|
||||
$this->assertArrayHasKey('pattern', $constraints['Regex']);
|
||||
$this->assertIsString($constraints['Regex']['pattern']);
|
||||
$this->assertArrayHasKey('message', $constraints['Regex']);
|
||||
$this->assertIsString($constraints['Regex']['message']);
|
||||
|
||||
$id_key = $this->entity->getEntityType()->getKey('id');
|
||||
if ($is_expected_to_be_valid) {
|
||||
$expected_errors = [];
|
||||
}
|
||||
else {
|
||||
$expected_errors = [$id_key => 'This value is not valid.'];
|
||||
$expected_errors = [$id_key => sprintf('The <em class="placeholder">"%s"</em> machine name is not valid.', $machine_name)];
|
||||
}
|
||||
|
||||
$this->entity->set(
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\KernelTests\Core\Config;
|
||||
|
||||
use Drupal\Tests\SchemaCheckTestTrait;
|
||||
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.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $modules = ['system', 'config_test'];
|
||||
|
||||
/**
|
||||
* Config files to be ignored by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $toSkip = [
|
||||
// Skip files provided by the config_schema_test module since that module
|
||||
// is explicitly for testing schema.
|
||||
'config_schema_test.ignore',
|
||||
'config_schema_test.noschema',
|
||||
'config_schema_test.plugin_types',
|
||||
'config_schema_test.someschema.somemodule.section_one.subsection',
|
||||
'config_schema_test.someschema.somemodule.section_two.subsection',
|
||||
'config_schema_test.someschema.with_parents',
|
||||
'config_schema_test.someschema',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function register(ContainerBuilder $container) {
|
||||
parent::register($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) {
|
||||
if (in_array($config_name, $this->toSkip)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$data = $default_config_storage->read($config_name);
|
||||
$this->assertConfigSchema($typed_config, $config_name, $data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -56,9 +56,14 @@ class SchemaCheckTraitTest extends KernelTestBase {
|
|||
$config_data['boolean'] = [];
|
||||
$ret = $this->checkConfigSchema($this->typedConfig, 'config_test.types', $config_data);
|
||||
$expected = [
|
||||
// Storage type check errors.
|
||||
// @see \Drupal\Core\Config\Schema\SchemaCheckTrait::checkValue()
|
||||
'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)',
|
||||
// Validation constraints violations.
|
||||
// @see \Drupal\Core\TypedData\TypedDataInterface::validate()
|
||||
'0' => '[boolean] This value should be of the correct primitive type.',
|
||||
];
|
||||
$this->assertEquals($expected, $ret);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue