diff options
14 files changed, 180 insertions, 35 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 58f39c03ac17..936401851968 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -234,6 +234,7 @@ default: _TARGET_DB_DRIVER: "mysql" _TARGET_DB_DRIVER_MODULE: "mysql" PERFORMANCE_TEST: $PERFORMANCE_TEST + OPENTELEMETRY_COLLECTOR: $OPENTELEMETRY_COLLECTOR # Run on MR, schedule, push, parent pipeline and performance test. rules: - if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ROOT_NAMESPACE == "project" diff --git a/.gitlab-ci/pipeline.yml b/.gitlab-ci/pipeline.yml index 88a60ff66594..4efc20087814 100644 --- a/.gitlab-ci/pipeline.yml +++ b/.gitlab-ci/pipeline.yml @@ -273,7 +273,7 @@ variables: [[ $_TARGET_DB == mariadb* ]] && export SIMPLETEST_DB=$_TARGET_DB_DRIVER://$MYSQL_USER:$MYSQL_PASSWORD@database/$MYSQL_DATABASE?module=$_TARGET_DB_DRIVER_MODULE [[ $_TARGET_DB == pgsql* ]] && export SIMPLETEST_DB=pgsql://$POSTGRES_USER:$POSTGRES_PASSWORD@database/$POSTGRES_DB?module=pgsql - composer install --optimize-autoloader - - export OTEL_COLLECTOR="$OTEL_COLLECTOR" + - export OTEL_COLLECTOR="$OPENTELEMETRY_COLLECTOR" - mkdir -p ./sites/simpletest ./sites/default/files ./build/logs/junit /var/www/.composer - chown -R www-data:www-data ./sites ./build/logs/junit ./vendor /var/www/ - sudo -u www-data git config --global --add safe.directory $CI_PROJECT_DIR diff --git a/core/.phpstan-baseline.php b/core/.phpstan-baseline.php index e0660c7dc93e..4b4b01e4701b 100644 --- a/core/.phpstan-baseline.php +++ b/core/.phpstan-baseline.php @@ -17462,18 +17462,6 @@ $ignoreErrors[] = [ 'path' => __DIR__ . '/modules/file/tests/file_module_test/src/Form/FileModuleTestForm.php', ]; $ignoreErrors[] = [ - 'message' => '#^Method Drupal\\\\file_test\\\\Form\\\\FileTestForm\\:\\:submitForm\\(\\) has no return type specified\\.$#', - 'identifier' => 'missingType.return', - 'count' => 1, - 'path' => __DIR__ . '/modules/file/tests/file_test/src/Form/FileTestForm.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Method Drupal\\\\file_test\\\\Form\\\\FileTestForm\\:\\:validateForm\\(\\) has no return type specified\\.$#', - 'identifier' => 'missingType.return', - 'count' => 1, - 'path' => __DIR__ . '/modules/file/tests/file_test/src/Form/FileTestForm.php', -]; -$ignoreErrors[] = [ 'message' => '#^Method Drupal\\\\file_test\\\\Form\\\\FileTestSaveUploadFromForm\\:\\:create\\(\\) has no return type specified\\.$#', 'identifier' => 'missingType.return', 'count' => 1, diff --git a/core/lib/Drupal/Core/Extension/ModuleHandler.php b/core/lib/Drupal/Core/Extension/ModuleHandler.php index ad361d3fe669..b187560c10fb 100644 --- a/core/lib/Drupal/Core/Extension/ModuleHandler.php +++ b/core/lib/Drupal/Core/Extension/ModuleHandler.php @@ -230,7 +230,9 @@ class ModuleHandler implements ModuleHandlerInterface { protected function add($type, $name, $path) { $pathname = "$path/$name.info.yml"; $php_file_path = $this->root . "/$path/$name.$type"; - $filename = file_exists($php_file_path) ? "$name.$type" : NULL; + if ($filename = file_exists($php_file_path) ? "$name.$type" : NULL) { + include_once $php_file_path; + } $this->moduleList[$name] = new Extension($this->root, $type, $pathname, $filename); $this->resetImplementations(); $hook_collector = HookCollectorPass::collectAllHookImplementations([$name => ['pathname' => $pathname]]); diff --git a/core/lib/Drupal/Core/Hook/HookCollectorPass.php b/core/lib/Drupal/Core/Hook/HookCollectorPass.php index 7c0f913ca219..75bbb039414e 100644 --- a/core/lib/Drupal/Core/Hook/HookCollectorPass.php +++ b/core/lib/Drupal/Core/Hook/HookCollectorPass.php @@ -403,12 +403,6 @@ class HookCollectorPass implements CompilerPassInterface { $extension = $fileinfo->getExtension(); $filename = $fileinfo->getPathname(); - if (($extension === 'module' || $extension === 'profile') && !$iterator->getDepth() && !$skip_procedural) { - // There is an expectation for all modules and profiles to be loaded. - // .module and .profile files are not supposed to be in subdirectories. - // These need to be loaded even if the module has no procedural hooks. - include_once $filename; - } if ($extension === 'php') { $cached = $hook_file_cache->get($filename); if ($cached) { @@ -512,11 +506,13 @@ class HookCollectorPass implements CompilerPassInterface { $function = $module . '_' . $hook; if ($hook === 'hook_info') { $this->hookInfo[] = $function; + include_once $fileinfo->getPathname(); } elseif ($hook === 'module_implements_alter') { $message = "$function without a #[LegacyModuleImplementsAlter] attribute is deprecated in drupal:11.2.0 and removed in drupal:12.0.0. See https://www.drupal.org/node/3496788"; @trigger_error($message, E_USER_DEPRECATED); $this->moduleImplementsAlters[] = $function; + include_once $fileinfo->getPathname(); } $this->proceduralImplementations[$hook][] = $module; if ($fileinfo->getExtension() !== 'module') { diff --git a/core/modules/ckeditor5/tests/src/Unit/CKEditor5ImageControllerTest.php b/core/modules/ckeditor5/tests/src/Unit/CKEditor5ImageControllerTest.php new file mode 100644 index 000000000000..bb69c28c6fbf --- /dev/null +++ b/core/modules/ckeditor5/tests/src/Unit/CKEditor5ImageControllerTest.php @@ -0,0 +1,85 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\ckeditor5\Unit; + +use Drupal\ckeditor5\Controller\CKEditor5ImageController; +use Drupal\ckeditor5\Plugin\CKEditor5PluginManagerInterface; +use Drupal\Core\Entity\EntityConstraintViolationList; +use Drupal\Core\Entity\EntityStorageInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Entity\EntityTypeRepositoryInterface; +use Drupal\Core\File\FileSystemInterface; +use Drupal\Core\Lock\LockBackendInterface; +use Drupal\editor\EditorInterface; +use Drupal\file\Entity\File; +use Drupal\file\FileInterface; +use Drupal\file\Upload\FileUploadHandlerInterface; +use Drupal\Tests\UnitTestCase; +use Prophecy\Argument; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\HttpException; + +/** + * Tests CKEditor5ImageController. + * + * @group ckeditor5 + * @coversDefaultClass \Drupal\ckeditor5\Controller\CKEditor5ImageController + */ +final class CKEditor5ImageControllerTest extends UnitTestCase { + + /** + * Tests that upload fails correctly when the file is too large. + */ + public function testInvalidFile(): void { + $file_system = $this->prophesize(FileSystemInterface::class); + $file_system->move(Argument::any())->shouldNotBeCalled(); + $directory = 'public://'; + $file_system->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY)->willReturn(TRUE); + $file_system->getDestinationFilename(Argument::cetera())->willReturn('/tmp/foo.txt'); + $lock = $this->prophesize(LockBackendInterface::class); + $lock->acquire(Argument::any())->willReturn(TRUE); + $container = $this->prophesize(ContainerInterface::class); + $file_storage = $this->prophesize(EntityStorageInterface::class); + $file = $this->prophesize(FileInterface::class); + $violations = $this->prophesize(EntityConstraintViolationList::class); + $violations->count()->willReturn(0); + $file->validate()->willReturn($violations->reveal()); + $file_storage->create(Argument::any())->willReturn($file->reveal()); + $entity_type_manager = $this->prophesize(EntityTypeManagerInterface::class); + $entity_type_manager->getStorage('file')->willReturn($file_storage->reveal()); + $container->get('entity_type.manager')->willReturn($entity_type_manager->reveal()); + $entity_type_repository = $this->prophesize(EntityTypeRepositoryInterface::class); + $entity_type_repository->getEntityTypeFromClass(File::class)->willReturn('file'); + $container->get('entity_type.repository')->willReturn($entity_type_repository->reveal()); + \Drupal::setContainer($container->reveal()); + $controller = new CKEditor5ImageController( + $file_system->reveal(), + $this->prophesize(FileUploadHandlerInterface::class)->reveal(), + $lock->reveal(), + $this->prophesize(CKEditor5PluginManagerInterface::class)->reveal(), + ); + // We can't use vfsstream here because of how Symfony request works. + $file_uri = tempnam(sys_get_temp_dir(), 'tmp'); + $fp = fopen($file_uri, 'w'); + fwrite($fp, 'foo'); + fclose($fp); + $request = Request::create('/', files: [ + 'upload' => [ + 'name' => 'foo.txt', + 'type' => 'text/plain', + 'size' => 42, + 'tmp_name' => $file_uri, + 'error' => \UPLOAD_ERR_FORM_SIZE, + ], + ]); + $editor = $this->prophesize(EditorInterface::class); + $request->attributes->set('editor', $editor->reveal()); + $this->expectException(HttpException::class); + $this->expectExceptionMessage('The file "foo.txt" exceeds the upload limit defined in your form.'); + $controller->upload($request); + } + +} diff --git a/core/modules/file/tests/file_test/src/Form/FileRequiredTestForm.php b/core/modules/file/tests/file_test/src/Form/FileRequiredTestForm.php index 1491510fd648..4bdcf5455f9d 100644 --- a/core/modules/file/tests/file_test/src/Form/FileRequiredTestForm.php +++ b/core/modules/file/tests/file_test/src/Form/FileRequiredTestForm.php @@ -14,14 +14,14 @@ class FileRequiredTestForm extends FileTestForm { /** * {@inheritdoc} */ - public function getFormId() { + public function getFormId(): string { return '_file_required_test_form'; } /** * {@inheritdoc} */ - public function buildForm(array $form, FormStateInterface $form_state) { + public function buildForm(array $form, FormStateInterface $form_state): array { $form = parent::buildForm($form, $form_state); $form['file_test_upload']['#required'] = TRUE; return $form; diff --git a/core/modules/file/tests/file_test/src/Form/FileTestForm.php b/core/modules/file/tests/file_test/src/Form/FileTestForm.php index d021a538f44c..902c675cdcf4 100644 --- a/core/modules/file/tests/file_test/src/Form/FileTestForm.php +++ b/core/modules/file/tests/file_test/src/Form/FileTestForm.php @@ -6,28 +6,28 @@ namespace Drupal\file_test\Form; use Drupal\Core\File\FileExists; use Drupal\Core\File\FileSystemInterface; -use Drupal\Core\Form\FormInterface; +use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; /** * File test form class. */ -class FileTestForm implements FormInterface { +class FileTestForm extends FormBase { use FileTestFormTrait; use StringTranslationTrait; /** * {@inheritdoc} */ - public function getFormId() { + public function getFormId(): string { return '_file_test_form'; } /** * {@inheritdoc} */ - public function buildForm(array $form, FormStateInterface $form_state) { + public function buildForm(array $form, FormStateInterface $form_state): array { $form = $this->baseForm($form, $form_state); @@ -42,12 +42,7 @@ class FileTestForm implements FormInterface { /** * {@inheritdoc} */ - public function validateForm(array &$form, FormStateInterface $form_state) {} - - /** - * {@inheritdoc} - */ - public function submitForm(array &$form, FormStateInterface $form_state) { + public function submitForm(array &$form, FormStateInterface $form_state): void { // Process the upload and perform validation. Note: we're using the // form value for the $replace parameter. if (!$form_state->isValueEmpty('file_subdir')) { diff --git a/core/modules/layout_builder/src/InlineBlockEntityOperations.php b/core/modules/layout_builder/src/InlineBlockEntityOperations.php index 16bda99a45cd..7a832ad284c6 100644 --- a/core/modules/layout_builder/src/InlineBlockEntityOperations.php +++ b/core/modules/layout_builder/src/InlineBlockEntityOperations.php @@ -134,8 +134,6 @@ class InlineBlockEntityOperations implements ContainerInjectionInterface { * The parent entity. */ public function handleEntityDelete(EntityInterface $entity) { - // @todo In https://www.drupal.org/node/3008943 call - // \Drupal\layout_builder\LayoutEntityHelperTrait::isLayoutCompatibleEntity(). $this->usage->removeByLayoutEntity($entity); } diff --git a/core/modules/node/node.module b/core/modules/node/node.module index f14d843faa10..1fb4071ba47d 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -36,8 +36,12 @@ use Drupal\node\NodeTypeInterface; * @return array|false * A renderable array containing a list of linked node titles fetched from * $result, or FALSE if there are no rows in $result. + * + * @deprecated in drupal:11.3.0 and is removed from drupal:12.0.0. There is no replacement. + * @see https://www.drupal.org/node/3531959 */ function node_title_list(StatementInterface $result, $title = NULL) { + @trigger_error(__FUNCTION__ . '() is deprecated in drupal:11.3.0 and is removed from drupal:12.0.0. There is no replacement. See https://www.drupal.org/node/3531959', E_USER_DEPRECATED); $items = []; $num_rows = FALSE; $nids = []; diff --git a/core/modules/system/tests/modules/container_initialize/container_initialize.info.yml b/core/modules/system/tests/modules/container_initialize/container_initialize.info.yml new file mode 100644 index 000000000000..46411d2ea544 --- /dev/null +++ b/core/modules/system/tests/modules/container_initialize/container_initialize.info.yml @@ -0,0 +1,5 @@ +name: 'Container initialize' +type: module +description: 'Support module for HookCollectorPass testing.' +package: Testing +version: VERSION diff --git a/core/modules/system/tests/modules/container_initialize/container_initialize.module b/core/modules/system/tests/modules/container_initialize/container_initialize.module new file mode 100644 index 000000000000..5c8e0aff74ea --- /dev/null +++ b/core/modules/system/tests/modules/container_initialize/container_initialize.module @@ -0,0 +1,10 @@ +<?php + +/** + * @file + * Used to test bare container calls in .module files. + */ + +declare(strict_types=1); + +\Drupal::getContainer()->getParameter('site.path'); diff --git a/core/modules/system/tests/src/Functional/Hook/HookCollectorPassTest.php b/core/modules/system/tests/src/Functional/Hook/HookCollectorPassTest.php new file mode 100644 index 000000000000..59d69d1242cb --- /dev/null +++ b/core/modules/system/tests/src/Functional/Hook/HookCollectorPassTest.php @@ -0,0 +1,61 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\system\Functional\Hook; + +use Drupal\Tests\BrowserTestBase; +use Drupal\Core\Url; + +/** + * Tests services in .module files. + * + * @group Hook + */ +class HookCollectorPassTest extends BrowserTestBase { + + /** + * {@inheritdoc} + */ + protected static $modules = ['container_initialize']; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + + /** + * Tests installing a module with a Drupal container call outside functions. + * + * If this is removed then it needs to be moved to a test that installs modules through + * admin/modules. + */ + public function testContainerOutsideFunction(): void { + $settings['settings']['rebuild_access'] = (object) [ + 'value' => TRUE, + 'required' => TRUE, + ]; + + // This simulates installing the module and running a cache rebuild in a + // separate request. + $this->writeSettings($settings); + $this->rebuildAll(); + $this->drupalGet(Url::fromUri('base:core/rebuild.php')); + $this->assertSession()->pageTextNotContains('ContainerNotInitializedException'); + // Successful response from rebuild.php should redirect to the front page. + $this->assertSession()->addressEquals('/'); + + // If this file is removed then this test needs to be updated to trigger + // the container rebuild error from https://www.drupal.org/i/3505049 + $config_module_file = $this->root . '/core/modules/system/tests/modules/container_initialize/container_initialize.module'; + $this->assertFileExists($config_module_file, 'This test depends on a container call in a .module file'); + // Confirm that the file still has a bare container call. + $bare_container = "declare(strict_types=1); + +\Drupal::getContainer()->getParameter('site.path'); +"; + $file_content = file_get_contents($config_module_file); + $this->assertStringContainsString($bare_container, $file_content, 'container_initialize.module container test feature is missing.'); + } + +} diff --git a/core/tests/Drupal/Tests/Composer/Plugin/Unpack/Functional/UnpackRecipeTest.php b/core/tests/Drupal/BuildTests/Composer/Plugin/Unpack/Functional/UnpackRecipeTest.php index b74349256892..1397a78cf694 100644 --- a/core/tests/Drupal/Tests/Composer/Plugin/Unpack/Functional/UnpackRecipeTest.php +++ b/core/tests/Drupal/BuildTests/Composer/Plugin/Unpack/Functional/UnpackRecipeTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Drupal\Tests\Composer\Plugin\Unpack\Functional; +namespace Drupal\BuildTests\Composer\Plugin\Unpack\Functional; use Composer\InstalledVersions; use Composer\Util\Filesystem; |