Update to Drupal 8.1.8. For more information, see https://www.drupal.org/project/drupal/releases/8.1.8

This commit is contained in:
Pantheon Automation 2016-08-03 13:22:33 -07:00 committed by Greg Anderson
parent e9f047ccf8
commit f9f23cdf38
312 changed files with 6751 additions and 1546 deletions

View file

@ -1,3 +1,4 @@
# The menu_settings migration is in the menu_ui module.
id: menu
label: Menus
migration_tags:

View file

@ -41,8 +41,9 @@ class SystemInfoController implements ContainerInjectionInterface {
/**
* Displays the site status report.
*
* @return string
* The current status of the Drupal installation.
* @return array
* A render array containing a list of system requirements for the Drupal
* installation and whether this installation meets the requirements.
*/
public function status() {
$requirements = $this->systemManager->listRequirements();

View file

@ -393,7 +393,15 @@ class GDToolkit extends ImageToolkitBase {
public static function getSupportedExtensions() {
$extensions = array();
foreach (static::supportedTypes() as $image_type) {
$extensions[] = Unicode::strtolower(image_type_to_extension($image_type, FALSE));
// @todo Automatically fetch possible extensions for each mime type.
// @see https://www.drupal.org/node/2311679
$extension = Unicode::strtolower(image_type_to_extension($image_type, FALSE));
$extensions[] = $extension;
// Add some known similar extensions.
if ($extension === 'jpeg') {
$extensions[] = 'jpg';
$extensions[] = 'jpe';
}
}
return $extensions;
}
@ -413,6 +421,9 @@ class GDToolkit extends ImageToolkitBase {
* @see image_type_to_extension()
*/
public function extensionToImageType($extension) {
if (in_array($extension, ['jpe', 'jpg'])) {
$extension = 'jpeg';
}
foreach ($this->supportedTypes() as $type) {
if (image_type_to_extension($type, FALSE) === $extension) {
return $type;

View file

@ -2,6 +2,8 @@
namespace Drupal\system\Tests\Entity;
use Drupal\entity_test\Entity\EntityTestMulRev;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\simpletest\WebTestBase;
/**
@ -17,7 +19,7 @@ class EntityRevisionsTest extends WebTestBase {
*
* @var array
*/
public static $modules = array('entity_test');
public static $modules = array('entity_test', 'language');
/**
* A user with permission to administer entity_test content.
@ -35,6 +37,9 @@ class EntityRevisionsTest extends WebTestBase {
'view test entity',
));
$this->drupalLogin($this->webUser);
// Enable an additional language.
ConfigurableLanguage::createFromLangcode('de')->save();
}
/**
@ -113,4 +118,41 @@ class EntityRevisionsTest extends WebTestBase {
$this->assertFieldById('edit-field-test-text-0-value', $entity->field_test_text->value, format_string('%entity_type: Text matches in UI.', array('%entity_type' => $entity_type)));
}
/**
* Tests that an entity revision is upcasted in the correct language.
*/
public function testEntityRevisionParamConverter() {
// Create a test entity with multiple revisions and translations for them.
$entity = EntityTestMulRev::create([
'name' => 'default revision - en',
'user_id' => $this->webUser,
'language' => 'en',
]);
$entity->addTranslation('de', ['name' => 'default revision - de']);
$entity->save();
$forward_revision = \Drupal::entityTypeManager()->getStorage('entity_test_mulrev')->loadUnchanged($entity->id());
$forward_revision->setNewRevision();
$forward_revision->isDefaultRevision(FALSE);
$forward_revision->name = 'forward revision - en';
$forward_revision->save();
$forward_revision_translation = $forward_revision->getTranslation('de');
$forward_revision_translation->name = 'forward revision - de';
$forward_revision_translation->save();
// Check that the entity revision is upcasted in the correct language.
$revision_url = 'entity_test_mulrev/' . $entity->id() . '/revision/' . $forward_revision->getRevisionId() . '/view';
$this->drupalGet($revision_url);
$this->assertText('forward revision - en');
$this->assertNoText('forward revision - de');
$this->drupalGet('de/' . $revision_url);
$this->assertText('forward revision - de');
$this->assertNoText('forward revision - en');
}
}

View file

@ -20,7 +20,7 @@ class MimeTypeTest extends FileTestBase {
* Test mapping of mimetypes from filenames.
*/
public function testFileMimeTypeDetection() {
$prefix = 'public://';
$prefixes = ['public://', 'private://', 'temporary://', 'dummy-remote://'];
$test_case = array(
'test.jar' => 'application/java-archive',
@ -43,8 +43,10 @@ class MimeTypeTest extends FileTestBase {
// Test using default mappings.
foreach ($test_case as $input => $expected) {
// Test stream [URI].
$output = $guesser->guess($prefix . $input);
$this->assertIdentical($output, $expected, format_string('Mimetype for %input is %output (expected: %expected).', array('%input' => $input, '%output' => $output, '%expected' => $expected)));
foreach ($prefixes as $prefix) {
$output = $guesser->guess($prefix . $input);
$this->assertIdentical($output, $expected, format_string('Mimetype for %input is %output (expected: %expected).', array('%input' => $prefix . $input, '%output' => $output, '%expected' => $expected)));
}
// Test normal path equivalent
$output = $guesser->guess($input);

View file

@ -2,6 +2,9 @@
namespace Drupal\system\Tests\File;
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
use Drupal\file_test\StreamWrapper\DummyReadOnlyStreamWrapper;
/**
* Tests the read-only stream wrapper write functions.
*
@ -27,6 +30,12 @@ class ReadOnlyStreamWrapperTest extends FileTestBase {
* Test read-only specific behavior.
*/
function testReadOnlyBehavior() {
$type = DummyReadOnlyStreamWrapper::getType();
// Checks that the stream wrapper type is not declared as writable.
$this->assertIdentical(0, $type & StreamWrapperInterface::WRITE);
// Checks that the stream wrapper type is declared as local.
$this->assertIdentical(1, $type & StreamWrapperInterface::LOCAL);
// Generate a test file
$filename = $this->randomMachineName();
$site_path = $this->container->get('site.path');

View file

@ -106,6 +106,26 @@ class ToolkitGdTest extends KernelTestBase {
// Test that the image factory is set to use the GD toolkit.
$this->assertEqual($this->imageFactory->getToolkitId(), 'gd', 'The image factory is set to use the \'gd\' image toolkit.');
// Test the list of supported extensions.
$expected_extensions = ['png', 'gif', 'jpeg', 'jpg', 'jpe'];
$supported_extensions = $this->imageFactory->getSupportedExtensions();
$this->assertEqual($expected_extensions, array_intersect($expected_extensions, $supported_extensions));
// Test that the supported extensions map to correct internal GD image
// types.
$expected_image_types = [
'png' => IMAGETYPE_PNG,
'gif' => IMAGETYPE_GIF,
'jpeg' => IMAGETYPE_JPEG,
'jpg' => IMAGETYPE_JPEG,
'jpe' => IMAGETYPE_JPEG
];
$image = $this->imageFactory->get();
foreach ($expected_image_types as $extension => $expected_image_type) {
$image_type = $image->getToolkit()->extensionToImageType($extension);
$this->assertEqual($expected_image_type, $image_type);
}
// Typically the corner colors will be unchanged. These colors are in the
// order of top-left, top-right, bottom-right, bottom-left.
$default_corners = array($this->red, $this->green, $this->blue, $this->transparent);

View file

@ -11,12 +11,21 @@ use Drupal\simpletest\InstallerTestBase;
*/
class InstallerExistingConfigDirectoryTest extends InstallerTestBase {
/**
* The expected file perms of the folder.
*
* @var int
*/
protected $expectedFilePerms;
/**
* {@inheritdoc}
*/
protected function setUp() {
mkdir($this->siteDirectory . '/config_read_only', 0444);
$this->expectedFilePerms = fileperms($this->siteDirectory . '/config_read_only');
$this->settings['config_directories'][CONFIG_SYNC_DIRECTORY] = (object) array(
'value' => $this->siteDirectory . '/config',
'value' => $this->siteDirectory . '/config_read_only',
'required' => TRUE,
);
parent::setUp();
@ -28,6 +37,8 @@ class InstallerExistingConfigDirectoryTest extends InstallerTestBase {
public function testInstaller() {
$this->assertUrl('user/1');
$this->assertResponse(200);
$this->assertEqual($this->expectedFilePerms, fileperms($this->siteDirectory . '/config_read_only'));
$this->assertEqual([], glob($this->siteDirectory . '/config_read_only/*'), 'The sync directory is empty after install because it is read-only.');
}
}

View file

@ -90,6 +90,89 @@ class PagerTest extends WebTestBase {
$this->assertCacheContext('url.query_args');
}
/**
* Test proper functioning of multiple pagers.
*/
protected function testMultiplePagers() {
// First page.
$this->drupalGet('pager-test/multiple-pagers');
// Test data.
// Expected URL query string param is 0-indexed.
// Expected page per pager is 1-indexed.
$test_data = [
// With no query, all pagers set to first page.
[
'input_query' => NULL,
'expected_page' => [0 => '1', 1 => '1', 4 => '1'],
'expected_query' => '?page=0,0,,,0',
],
// Blanks around page numbers should not be relevant.
[
'input_query' => '?page=2 , 10,,, 5 ,,',
'expected_page' => [0 => '3', 1 => '11', 4 => '6'],
'expected_query' => '?page=2,10,,,5',
],
// Blanks within page numbers should lead to only the first integer
// to be considered.
[
'input_query' => '?page=2 , 3 0,,, 4 13 ,,',
'expected_page' => [0 => '3', 1 => '4', 4 => '5'],
'expected_query' => '?page=2,3,,,4',
],
// If floats are passed as page numbers, only the integer part is
// returned.
[
'input_query' => '?page=2.1,6.999,,,5.',
'expected_page' => [0 => '3', 1 => '7', 4 => '6'],
'expected_query' => '?page=2,6,,,5',
],
// Partial page fragment, undefined pagers set to first page.
[
'input_query' => '?page=5,2',
'expected_page' => [0 => '6', 1 => '3', 4 => '1'],
'expected_query' => '?page=5,2,,,0',
],
// Partial page fragment, undefined pagers set to first page.
[
'input_query' => '?page=,2',
'expected_page' => [0 => '1', 1 => '3', 4 => '1'],
'expected_query' => '?page=0,2,,,0',
],
// Partial page fragment, undefined pagers set to first page.
[
'input_query' => '?page=,',
'expected_page' => [0 => '1', 1 => '1', 4 => '1'],
'expected_query' => '?page=0,0,,,0',
],
// With overflow pages, all pagers set to max page.
[
'input_query' => '?page=99,99,,,99',
'expected_page' => [0 => '16', 1 => '16', 4 => '16'],
'expected_query' => '?page=15,15,,,15',
],
// Wrong value for the page resets pager to first page.
[
'input_query' => '?page=bar,5,foo,qux,bet',
'expected_page' => [0 => '1', 1 => '6', 4 => '1'],
'expected_query' => '?page=0,5,,,0',
],
];
// We loop through the page with the test data query parameters, and check
// that the active page for each pager element has the expected page
// (1-indexed) and resulting query parameter
foreach ($test_data as $data) {
$input_query = str_replace(' ', '%20', $data['input_query']);
$this->drupalGet($GLOBALS['base_root'] . parse_url($this->getUrl())['path'] . $input_query, ['external' => TRUE]);
foreach ([0, 1, 4] as $pager_element) {
$active_page = $this->cssSelect("div.test-pager-{$pager_element} ul.pager__items li.is-active:contains('{$data['expected_page'][$pager_element]}')");
$destination = str_replace('%2C', ',', $active_page[0]->a['href'][0]->__toString());
$this->assertEqual($destination, $data['expected_query']);
}
}
}
/**
* Test proper functioning of the ellipsis.
*/

View file

@ -24,6 +24,16 @@ class StatusTest extends WebTestBase {
protected function setUp() {
parent::setUp();
// Unset the sync directory in settings.php to trigger $config_directories
// error.
$settings['config_directories'] = array(
CONFIG_SYNC_DIRECTORY => (object) array(
'value' => '',
'required' => TRUE,
),
);
$this->writeSettings($settings);
$admin_user = $this->drupalCreateUser(array(
'administer site configuration',
));
@ -60,6 +70,9 @@ class StatusTest extends WebTestBase {
// If a module is fully installed no pending updates exists.
$this->assertNoText(t('Out of date'));
// The global $config_directories is not properly formed.
$this->assertRaw(t('Your %file file must define the $config_directories variable as an array containing the names of directories in which configuration files can be found. It must contain a %sync_key key.', array('%file' => $this->siteDirectory . '/settings.php', '%sync_key' => CONFIG_SYNC_DIRECTORY)));
// Set the schema version of update_test_postupdate to a lower version, so
// update_test_postupdate_update_8001() needs to be executed.
drupal_set_installed_schema_version('update_test_postupdate', 8000);

View file

@ -549,15 +549,22 @@ function system_requirements($phase) {
// defined, the installer will create a valid config directory later, but
// during runtime we must always display an error.
if (!empty($GLOBALS['config_directories'])) {
foreach ($GLOBALS['config_directories'] as $type => $directory) {
$directories[] = config_get_config_directory($type);
foreach (array_keys(array_filter($GLOBALS['config_directories'])) as $type) {
$directory = config_get_config_directory($type);
if (!is_dir($directory)) {
$requirements['config directory ' . $type] = array(
'title' => t('Configuration directory: %type', ['%type' => $type]),
'description' => t('The directory %directory does not exist.', array('%directory' => $directory)),
'severity' => REQUIREMENT_ERROR,
);
}
}
}
elseif ($phase != 'install') {
if ($phase != 'install' && (empty($GLOBALS['config_directories']) || empty($GLOBALS['config_directories'][CONFIG_SYNC_DIRECTORY]) )) {
$requirements['config directories'] = array(
'title' => t('Configuration directories'),
'value' => t('Not present'),
'description' => t('Your %file file must define the $config_directories variable as an array containing the name of a directories in which configuration files can be written.', array('%file' => $site_path . '/settings.php')),
'description' => t('Your %file file must define the $config_directories variable as an array containing the names of directories in which configuration files can be found. It must contain a %sync_key key.', array('%file' => $site_path . '/settings.php', '%sync_key' => CONFIG_SYNC_DIRECTORY)),
'severity' => REQUIREMENT_ERROR,
);
}

View file

@ -1286,8 +1286,15 @@ function system_cron() {
}
// Clean up any garbage in the queue service.
if (\Drupal::service('queue') instanceof QueueGarbageCollectionInterface) {
\Drupal::service('queue')->garbageCollection();
$queue_worker_manager = \Drupal::service('plugin.manager.queue_worker');
$queue_factory = \Drupal::service('queue');
foreach (array_keys($queue_worker_manager->getDefinitions()) as $queue_name) {
$queue = $queue_factory->get($queue_name);
if ($queue instanceof QueueGarbageCollectionInterface) {
$queue->garbageCollection();
}
}
// Clean up PHP storage.

View file

@ -8,7 +8,7 @@ use Drupal\Core\Queue\QueueWorkerBase;
* @QueueWorker(
* id = "cron_queue_test_exception",
* title = @Translation("Exception test"),
* cron = {"time" = 60}
* cron = {"time" = 1}
* )
*/
class CronQueueTestException extends QueueWorkerBase {
@ -17,7 +17,14 @@ class CronQueueTestException extends QueueWorkerBase {
* {@inheritdoc}
*/
public function processItem($data) {
throw new \Exception('That is not supposed to happen.');
$state = \Drupal::state();
if (!$state->get('cron_queue_test_exception')) {
$state->set('cron_queue_test_exception', 1);
throw new \Exception('That is not supposed to happen.');
}
else {
$state->set('cron_queue_test_exception', 2);
}
}
}

View file

@ -114,6 +114,11 @@ function entity_test_entity_base_field_info(EntityTypeInterface $entity_type) {
->setRevisionable(TRUE)
->setTranslatable(TRUE);
}
if ($entity_type->id() == 'entity_test_mulrev' && \Drupal::state()->get('entity_test.multi_column')) {
$fields['description'] = BaseFieldDefinition::create('shape')
->setLabel(t('Some custom description'))
->setTranslatable(TRUE);
}
return $fields;
}
@ -665,6 +670,17 @@ function entity_test_entity_prepare_view($entity_type, array $entities, array $d
}
}
/**
* Implements hook_entity_display_build_alter().
*/
function entity_test_entity_display_build_alter(&$build, $context) {
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
$entity = $context['entity'];
if ($entity->getEntityTypeId() == 'entity_test' && $entity->bundle() == 'display_build_alter_bundle') {
$build['entity_display_build_alter']['#markup'] = 'Content added in hook_entity_display_build_alter for entity id ' . $entity->id();
}
}
/**
* Implements hook_entity_access().
*/

View file

@ -68,6 +68,19 @@ entity.entity_test_rev.revision:
requirements:
_access: 'TRUE'
entity.entity_test_mulrev.revision:
path: '/entity_test_mulrev/{entity_test_mulrev}/revision/{entity_test_mulrev_revision}/view'
defaults:
_controller: '\Drupal\Core\Entity\Controller\EntityViewController::viewRevision'
options:
parameters:
entity_test_mulrev:
type: entity:entity_test_mulrev
entity_test_mulrev_revision:
type: entity_revision:entity_test_mulrev
requirements:
_access: 'TRUE'
entity.block.test_operation:
path: '/admin/structure/block/manage/{block}/test_operation'
defaults:

View file

@ -15,7 +15,7 @@ namespace Drupal\entity_test\Entity;
* },
* "translation" = "Drupal\content_translation\ContentTranslationHandler"
* },
* base_table = "entity_test",
* base_table = "entity_test_cache",
* entity_keys = {
* "id" = "id",
* "uuid" = "uuid",

View file

@ -15,7 +15,7 @@ use Drupal\Core\Entity\EntityTypeInterface;
* "default" = "Drupal\entity_test\EntityTestForm"
* }
* },
* base_table = "entity_test",
* base_table = "entity_test_constraint_violation",
* persistent_cache = FALSE,
* entity_keys = {
* "id" = "id",

View file

@ -8,7 +8,7 @@ namespace Drupal\entity_test\Entity;
* @ContentEntityType(
* id = "entity_test_default_access",
* label = @Translation("Test entity with default access"),
* base_table = "entity_test",
* base_table = "entity_test_default_access",
* entity_keys = {
* "id" = "id",
* "bundle" = "type"

View file

@ -12,7 +12,7 @@ namespace Drupal\entity_test\Entity;
* "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
* "view_builder" = "Drupal\entity_test\EntityTestViewBuilder"
* },
* base_table = "entity_test",
* base_table = "entity_test_label",
* render_cache = FALSE,
* entity_keys = {
* "uuid" = "uuid",

View file

@ -9,7 +9,7 @@ namespace Drupal\entity_test\Entity;
* id = "entity_test_label_callback",
* label = @Translation("Entity test label callback"),
* persistent_cache = FALSE,
* base_table = "entity_test",
* base_table = "entity_test_label_callback",
* label_callback = "entity_test_label_callback",
* entity_keys = {
* "id" = "id",

View file

@ -9,7 +9,7 @@ namespace Drupal\entity_test\Entity;
* id = "entity_test_no_label",
* label = @Translation("Entity Test without label"),
* persistent_cache = FALSE,
* base_table = "entity_test",
* base_table = "entity_test_no_label",
* entity_keys = {
* "id" = "id",
* "bundle" = "type"

View file

@ -12,7 +12,7 @@ namespace Drupal\entity_test\Entity;
* "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
* "view_builder" = "Drupal\entity_test\EntityTestViewBuilderOverriddenView",
* },
* base_table = "entity_test",
* base_table = "entity_test_view_builder",
* render_cache = FALSE,
* entity_keys = {
* "id" = "id",

View file

@ -1,3 +1,11 @@
pager_test.multiple_pagers:
path: '/pager-test/multiple-pagers'
defaults:
_title: 'Page using multiple pagers for testing'
_controller: '\Drupal\pager_test\Controller\PagerTestController::multiplePagers'
requirements:
_access: 'TRUE'
pager_test.query_parameters:
path: '/pager-test/query-parameters'
defaults:

View file

@ -9,6 +9,41 @@ use Drupal\Core\Controller\ControllerBase;
*/
class PagerTestController extends ControllerBase {
/**
* Builds a render array for a pageable test table.
*
* @param int $element
* The pager element to be used for paging.
* @param int $limit
* The limit of rows per page for the specified element.
*
* @return array
* A render array.
*/
protected function buildTestTable($element, $limit) {
$header = [
['data' => 'wid'],
['data' => 'type'],
['data' => 'timestamp'],
];
$query = db_select('watchdog', 'd')->extend('Drupal\Core\Database\Query\PagerSelectExtender')->element($element);
$result = $query
->fields('d', array('wid', 'type', 'timestamp'))
->limit($limit)
->orderBy('d.wid')
->execute();
$rows = [];
foreach ($result as $row) {
$rows[] = ['data' => (array) $row];
}
return [
'#theme' => 'table',
'#header' => $header,
'#rows' => $rows,
'#empty' => $this->t("There are no watchdog records found in the db"),
];
}
/**
* Returns a pager with 'parameters' variable.
*
@ -18,27 +53,7 @@ class PagerTestController extends ControllerBase {
public function queryParameters() {
// Example query.
$header_0 = array(
array('data' => 'wid'),
array('data' => 'type'),
array('data' => 'timestamp'),
);
$query_0 = db_select('watchdog', 'd')->extend('Drupal\Core\Database\Query\PagerSelectExtender')->element(0);
$query_0->fields('d', array('wid', 'type', 'timestamp'));
$result_0 = $query_0
->limit(5)
->orderBy('d.wid')
->execute();
$rows_0 = array();
foreach ($result_0 as $row) {
$rows_0[] = array('data' => (array) $row);
}
$build['pager_table_0'] = array(
'#theme' => 'table',
'#header' => $header_0,
'#rows' => $rows_0,
'#empty' => $this->t("There are no watchdog records found in the db"),
);
$build['pager_table_0'] = $this->buildTestTable(0, 5);
// Counter of calls to the current pager.
$query_params = pager_get_query_parameters();
@ -60,6 +75,45 @@ class PagerTestController extends ControllerBase {
return $build;
}
/**
* Returns a page with multiple pagers.
*/
public function multiplePagers() {
// Build three tables with same query and different pagers.
$build['pager_table_0'] = $this->buildTestTable(0, 20);
$build['pager_pager_0'] = array(
'#type' => 'container',
'#attributes' => ['class' => ['test-pager-0']],
'pager' => [
'#type' => 'pager',
'#element' => 0,
],
);
$build['pager_table_1'] = $this->buildTestTable(1, 20);
$build['pager_pager_1'] = array(
'#type' => 'container',
'#attributes' => ['class' => ['test-pager-1']],
'pager' => [
'#type' => 'pager',
'#element' => 1,
],
);
$build['pager_table_4'] = $this->buildTestTable(4, 20);
$build['pager_pager_4'] = array(
'#type' => 'container',
'#attributes' => ['class' => ['test-pager-4']],
'pager' => [
'#type' => 'pager',
'#element' => 4,
],
);
return $build;
}
/**
* #pre_render callback for #type => pager that shows the pager cache context.
*/

View file

@ -0,0 +1,6 @@
name: 'Placeholder setting a message test'
type: module
description: 'Support module for PlaceholderMessageTest.'
package: Testing
version: VERSION
core: 8.x

View file

@ -0,0 +1,24 @@
render_placeholder_message_test.first:
path: '/render_placeholder_message_test/first'
defaults:
_controller: '\Drupal\render_placeholder_message_test\RenderPlaceholderMessageTestController::messagesPlaceholderFirst'
requirements:
_access: 'TRUE'
render_placeholder_message_test.middle:
path: '/render_placeholder_message_test/middle'
defaults:
_controller: '\Drupal\render_placeholder_message_test\RenderPlaceholderMessageTestController::messagesPlaceholderMiddle'
requirements:
_access: 'TRUE'
render_placeholder_message_test.last:
path: '/render_placeholder_message_test/last'
defaults:
_controller: '\Drupal\render_placeholder_message_test\RenderPlaceholderMessageTestController::messagesPlaceholderLast'
requirements:
_access: 'TRUE'
render_placeholder_message_test.queued:
path: '/render_placeholder_message_test/queued'
defaults:
_controller: '\Drupal\render_placeholder_message_test\RenderPlaceholderMessageTestController::queuedMessages'
requirements:
_access: 'TRUE'

View file

@ -0,0 +1,99 @@
<?php
namespace Drupal\render_placeholder_message_test;
use Drupal\Core\Render\RenderContext;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
class RenderPlaceholderMessageTestController implements ContainerAwareInterface {
use ContainerAwareTrait;
/**
* @return array
*/
public function messagesPlaceholderFirst() {
return $this->build([
'<drupal-render-placeholder callback="Drupal\Core\Render\Element\StatusMessages::renderMessages" arguments="0" token="a8c34b5e"></drupal-render-placeholder>',
'<drupal-render-placeholder callback="\Drupal\render_placeholder_message_test\RenderPlaceholderMessageTestController::setAndLogMessage" arguments="0=P1" token="0546ada3"></drupal-render-placeholder>',
'<drupal-render-placeholder callback="\Drupal\render_placeholder_message_test\RenderPlaceholderMessageTestController::setAndLogMessage" arguments="0=P2" token="83d2df0d"></drupal-render-placeholder>',
]);
}
/**
* @return array
*/
public function messagesPlaceholderMiddle() {
return $this->build([
'<drupal-render-placeholder callback="\Drupal\render_placeholder_message_test\RenderPlaceholderMessageTestController::setAndLogMessage" arguments="0=P1" token="0546ada3"></drupal-render-placeholder>',
'<drupal-render-placeholder callback="Drupal\Core\Render\Element\StatusMessages::renderMessages" arguments="0" token="a8c34b5e"></drupal-render-placeholder>',
'<drupal-render-placeholder callback="\Drupal\render_placeholder_message_test\RenderPlaceholderMessageTestController::setAndLogMessage" arguments="0=P2" token="83d2df0d"></drupal-render-placeholder>',
]);
}
/**
* @return array
*/
public function messagesPlaceholderLast() {
return $this->build([
'<drupal-render-placeholder callback="\Drupal\render_placeholder_message_test\RenderPlaceholderMessageTestController::setAndLogMessage" arguments="0=P1" token="0546ada3"></drupal-render-placeholder>',
'<drupal-render-placeholder callback="\Drupal\render_placeholder_message_test\RenderPlaceholderMessageTestController::setAndLogMessage" arguments="0=P2" token="83d2df0d"></drupal-render-placeholder>',
'<drupal-render-placeholder callback="Drupal\Core\Render\Element\StatusMessages::renderMessages" arguments="0" token="a8c34b5e"></drupal-render-placeholder>',
]);
}
/**
* @return array
*/
public function queuedMessages() {
return ['#type' => 'status_messages'];
}
/**
* @return array
*/
protected function build(array $placeholder_order) {
$build = [];
$build['messages'] = ['#type' => 'status_messages'];
$build['p1'] = [
'#lazy_builder' => ['\Drupal\render_placeholder_message_test\RenderPlaceholderMessageTestController::setAndLogMessage', ['P1']],
'#create_placeholder' => TRUE,
];
$build['p2'] = [
'#lazy_builder' => ['\Drupal\render_placeholder_message_test\RenderPlaceholderMessageTestController::setAndLogMessage', ['P2']],
'#create_placeholder' => TRUE,
];
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
$renderer->executeInRenderContext(new RenderContext(), function () use (&$build, $renderer) {
return $renderer->render($build, FALSE);
});
$reordered = [];
foreach ($placeholder_order as $placeholder) {
$reordered[$placeholder] = $build['#attached']['placeholders'][$placeholder];
}
$build['#attached']['placeholders'] = $reordered;
return $build;
}
/**
* #lazy_builder callback; sets and prints a message.
*
* @param string $message
* The message to send.
*
* @return array
* A renderable array containing the message.
*/
public static function setAndLogMessage($message) {
// Set message.
drupal_set_message($message);
// Print which message is expected.
return ['#markup' => '<p class="logged-message">Message: ' . $message . '</p>'];
}
}

View file

@ -114,3 +114,10 @@ function _test_theme_twig_php_values() {
),
);
}
/**
* Implements template_preprocess_status_messages().
*/
function twig_theme_test_preprocess_status_messages(&$variables) {
$variables['attributes']['class'][] = 'custom-test-messages-class';
}

View file

@ -0,0 +1,58 @@
<?php
namespace Drupal\Tests\system\Functional\Render;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
/**
* Functional test verifying that messages set in placeholders always appear.
*
* @group Render
*/
class PlaceholderMessageTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['render_placeholder_message_test'];
/**
* Test rendering of message placeholder.
*/
public function testMessagePlaceholder() {
$messages_markup = '<div role="contentinfo" aria-label="Status message"';
$test_routes = [
// Messages placeholder rendered first.
'render_placeholder_message_test.first',
// Messages placeholder rendered after one, before another.
'render_placeholder_message_test.middle',
// Messages placeholder rendered last.
'render_placeholder_message_test.last',
];
$assert = $this->assertSession();
foreach ($test_routes as $route) {
// Verify that we start off with zero messages queued.
$this->drupalGet(Url::fromRoute('render_placeholder_message_test.queued'));
$assert->responseNotContains($messages_markup);
// Verify the test case at this route behaves as expected.
$this->drupalGet(Url::fromRoute($route));
$assert->elementContains('css', 'p.logged-message:nth-of-type(1)', 'Message: P1');
$assert->elementContains('css', 'p.logged-message:nth-of-type(2)', 'Message: P2');
$assert->responseContains($messages_markup);
$assert->elementExists('css', 'div[aria-label="Status message"] ul');
$assert->elementContains('css', 'div[aria-label="Status message"] ul li:nth-of-type(1)', 'P1');
$assert->elementContains('css', 'div[aria-label="Status message"] ul li:nth-of-type(2)', 'P2');
// Verify that we end with all messages printed, hence again zero queued.
$this->drupalGet(Url::fromRoute('render_placeholder_message_test.queued'));
$assert->responseNotContains($messages_markup);
}
}
}

View file

@ -126,7 +126,7 @@ class ModuleHandlerTest extends KernelTestBase {
$this->pass(t('ModuleInstaller::install() throws an exception if dependencies are missing.'));
}
$this->assertFalse($this->moduleHandler()->moduleExists('color'), 'ModuleHandler::install() aborts if dependencies are missing.');
$this->assertFalse($this->moduleHandler()->moduleExists('color'), 'ModuleInstaller::install() aborts if dependencies are missing.');
// Fix the missing dependency.
// Color module depends on Config. Config depends on Help module.
@ -134,7 +134,7 @@ class ModuleHandlerTest extends KernelTestBase {
drupal_static_reset('system_rebuild_module_data');
$result = $this->moduleInstaller()->install(array('color'));
$this->assertTrue($result, 'ModuleHandler::install() returns the correct value.');
$this->assertTrue($result, 'ModuleInstaller::install() returns the correct value.');
// Verify that the fake dependency chain was installed.
$this->assertTrue($this->moduleHandler()->moduleExists('config') && $this->moduleHandler()->moduleExists('help'), 'Dependency chain was installed.');
@ -147,10 +147,10 @@ class ModuleHandlerTest extends KernelTestBase {
$this->assertEqual($module_order, array('help', 'config', 'color'));
// Uninstall all three modules explicitly, but in the incorrect order,
// and make sure that ModuleHandler::uninstall() uninstalled them in the
// and make sure that ModuleInstaller::uninstall() uninstalled them in the
// correct sequence.
$result = $this->moduleInstaller()->uninstall(array('config', 'help', 'color'));
$this->assertTrue($result, 'ModuleHandler::uninstall() returned TRUE.');
$this->assertTrue($result, 'ModuleInstaller::uninstall() returned TRUE.');
foreach (array('color', 'config', 'help') as $module) {
$this->assertEqual(drupal_get_installed_schema_version($module), SCHEMA_UNINSTALLED, "$module module was uninstalled.");
@ -161,12 +161,12 @@ class ModuleHandlerTest extends KernelTestBase {
// Enable Color module again, which should enable both the Config module and
// Help module. But, this time do it with Config module declaring a
// dependency on a specific version of Help module in its info file. Make
// sure that Drupal\Core\Extension\ModuleHandler::install() still works.
// sure that Drupal\Core\Extension\ModuleInstaller::install() still works.
\Drupal::state()->set('module_test.dependency', 'version dependency');
drupal_static_reset('system_rebuild_module_data');
$result = $this->moduleInstaller()->install(array('color'));
$this->assertTrue($result, 'ModuleHandler::install() returns the correct value.');
$this->assertTrue($result, 'ModuleInstaller::install() returns the correct value.');
// Verify that the fake dependency chain was installed.
$this->assertTrue($this->moduleHandler()->moduleExists('config') && $this->moduleHandler()->moduleExists('help'), 'Dependency chain was installed.');
@ -202,7 +202,7 @@ class ModuleHandlerTest extends KernelTestBase {
// Uninstall the profile module "dependency".
$result = $this->moduleInstaller()->uninstall(array($dependency));
$this->assertTrue($result, 'ModuleHandler::uninstall() returns TRUE.');
$this->assertTrue($result, 'ModuleInstaller::uninstall() returns TRUE.');
$this->assertFalse($this->moduleHandler()->moduleExists($dependency));
$this->assertEqual(drupal_get_installed_schema_version($dependency), SCHEMA_UNINSTALLED, "$dependency module was uninstalled.");
@ -240,7 +240,7 @@ class ModuleHandlerTest extends KernelTestBase {
// Uninstalling entity_test is not possible when there is content.
try {
$message = 'ModuleHandler::uninstall() throws ModuleUninstallValidatorException upon uninstalling a module which does not pass validation.';
$message = 'ModuleInstaller::uninstall() throws ModuleUninstallValidatorException upon uninstalling a module which does not pass validation.';
$this->moduleInstaller()->uninstall(array('entity_test'));
$this->fail($message);
}
@ -250,7 +250,7 @@ class ModuleHandlerTest extends KernelTestBase {
// Uninstalling help needs entity_test to be un-installable.
try {
$message = 'ModuleHandler::uninstall() throws ModuleUninstallValidatorException upon uninstalling a module which does not pass validation.';
$message = 'ModuleInstaller::uninstall() throws ModuleUninstallValidatorException upon uninstalling a module which does not pass validation.';
$this->moduleInstaller()->uninstall(array('help'));
$this->fail($message);
}
@ -262,7 +262,7 @@ class ModuleHandlerTest extends KernelTestBase {
$entity->delete();
$result = $this->moduleInstaller()->uninstall(array('help'));
$this->assertTrue($result, 'ModuleHandler::uninstall() returns TRUE.');
$this->assertTrue($result, 'ModuleInstaller::uninstall() returns TRUE.');
$this->assertEqual(drupal_get_installed_schema_version('entity_test'), SCHEMA_UNINSTALLED, "entity_test module was uninstalled.");
}

View file

@ -0,0 +1,49 @@
<?php
namespace Drupal\Tests\system\Kernel\Render;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests the Classy theme.
*
* @group Theme
*/
class ClassyTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = array('system', 'twig_theme_test');
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
// Use the classy theme.
$this->container->get('theme_installer')->install(['classy']);
$this->container->get('config.factory')
->getEditable('system.theme')
->set('default', 'classy')
->save();
// Clear the theme registry.
$this->container->set('theme.registry', NULL);
}
/**
* Test the classy theme.
*/
function testClassyTheme() {
drupal_set_message('An error occurred', 'error');
drupal_set_message('But then something nice happened');
$messages = array(
'#type' => 'status_messages',
);
$this->render($messages);
$this->assertNoText('custom-test-messages-class', 'The custom class attribute value added in the status messages preprocess function is not displayed as page content.');
}
}

View file

@ -1,22 +1,51 @@
<?php
namespace Drupal\system\Tests\System;
namespace Drupal\Tests\system\Kernel\System;
use Drupal\simpletest\WebTestBase;
use Drupal\Core\Database\Database;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests the Cron Queue runner.
*
* @group system
*/
class CronQueueTest extends WebTestBase {
class CronQueueTest extends KernelTestBase {
/**
* The modules to enable.
*
* @var array
*/
public static $modules = array('cron_queue_test');
public static $modules = ['system', 'cron_queue_test'];
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* The cron service.
*
* @var \Drupal\Core\Cron
*/
protected $cron;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// These additional tables are necessary because $this->cron->run() calls
// system_cron().
$this->installSchema('system', ['key_value_expire']);
$this->connection = Database::getConnection();
$this->cron = \Drupal::service('cron');
}
/**
* Tests that exceptions thrown by workers are handled properly.
@ -30,11 +59,25 @@ class CronQueueTest extends WebTestBase {
// Run cron; the worker for this queue should throw an exception and handle
// it.
$this->cronRun();
$this->cron->run();
$this->assertEqual(\Drupal::state()->get('cron_queue_test_exception'), 1);
// The item should be left in the queue.
$this->assertEqual($queue->numberOfItems(), 1, 'Failing item still in the queue after throwing an exception.');
// Expire the queue item manually. system_cron() relies in REQUEST_TIME to
// find queue items whose expire field needs to be reset to 0. This is a
// Kernel test, so REQUEST_TIME won't change when cron runs.
// @see system_cron()
// @see \Drupal\Core\Cron::processQueues()
$this->connection->update('queue')
->condition('name', 'cron_queue_test_exception')
->fields(['expire' => REQUEST_TIME - 1])
->execute();
$this->cron->run();
$this->assertEqual(\Drupal::state()->get('cron_queue_test_exception'), 2);
$this->assertEqual($queue->numberOfItems(), 0, 'Item was processed and removed from the queue.');
// Get the queue to test the specific SuspendQueueException.
$queue = $this->container->get('queue')->get('cron_queue_test_broken_queue');
@ -45,7 +88,7 @@ class CronQueueTest extends WebTestBase {
// Run cron; the worker for this queue should process as far as the crashing
// item.
$this->cronRun();
$this->cron->run();
// Only one item should have been processed.
$this->assertEqual($queue->numberOfItems(), 2, 'Failing queue stopped processing at the failing item.');
@ -60,7 +103,8 @@ class CronQueueTest extends WebTestBase {
// Test the requeueing functionality.
$queue = $this->container->get('queue')->get('cron_queue_test_requeue_exception');
$queue->createItem([]);
$this->cronRun();
$this->cron->run();
$this->assertEqual(\Drupal::state()->get('cron_queue_test_requeue_exception'), 2);
$this->assertFalse($queue->numberOfItems());
}