Core and composer updates

This commit is contained in:
Rob Davies 2017-07-03 16:47:07 +01:00
parent a82634bb98
commit 62cac30480
1118 changed files with 21770 additions and 6306 deletions

View file

@ -202,6 +202,15 @@ class ConfigInstallTest extends KernelTestBase {
$this->assertEqual($e->getConfigObjects(), ['config_test.dynamic.other_module_test_with_dependency' => ['config_other_module_config_test', 'config_test.dynamic.dotted.english']]);
$this->assertEqual($e->getMessage(), 'Configuration objects provided by <em class="placeholder">config_install_dependency_test</em> have unmet dependencies: <em class="placeholder">config_test.dynamic.other_module_test_with_dependency (config_other_module_config_test, config_test.dynamic.dotted.english)</em>');
}
try {
$this->installModules(['config_install_double_dependency_test']);
$this->fail('Expected UnmetDependenciesException not thrown.');
}
catch (UnmetDependenciesException $e) {
$this->assertEquals('config_install_double_dependency_test', $e->getExtension());
$this->assertEquals(['config_test.dynamic.other_module_test_with_dependency' => ['config_other_module_config_test', 'config_test.dynamic.dotted.english']], $e->getConfigObjects());
$this->assertEquals('Configuration objects provided by <em class="placeholder">config_install_double_dependency_test</em> have unmet dependencies: <em class="placeholder">config_test.dynamic.other_module_test_with_dependency (config_other_module_config_test, config_test.dynamic.dotted.english)</em>', $e->getMessage());
}
$this->installModules(['config_test_language']);
try {
$this->installModules(['config_install_dependency_test']);

View file

@ -221,6 +221,12 @@ class ConnectionUnitTest extends KernelTestBase {
$reflection = new \ReflectionObject($connection);
$connection_property = $reflection->getProperty('connection');
$connection_property->setAccessible(TRUE);
// Skip this test when a database driver does not implement PDO.
// An alternative database driver that does not implement PDO
// should implement its own connection test.
if (get_class($connection_property->getValue($connection)) !== 'PDO') {
$this->markTestSkipped('Ignored PDO connection unit test for this driver because it does not implement PDO.');
}
$error_mode = $connection_property->getValue($connection)
->getAttribute(\PDO::ATTR_ERRMODE);
$this->assertEqual($error_mode, \PDO::ERRMODE_EXCEPTION, 'Ensure the default error mode is set to exception.');

View file

@ -251,4 +251,87 @@ class ContentEntityCloneTest extends EntityKernelTestBase {
$this->assertEquals('clone', $clone->getName());
}
/**
* Tests changing the default revision flag.
*/
public function testDefaultRevision() {
// Create a test entity with a translation, which will internally trigger
// entity cloning for the new translation and create references for some of
// the entity properties.
$entity = EntityTestMulRev::create([
'name' => 'original',
'language' => 'en',
]);
$entity->addTranslation('de');
$entity->save();
// Assert that the entity is in the default revision.
$this->assertTrue($entity->isDefaultRevision());
// Clone the entity and modify its default revision flag.
$clone = clone $entity;
$clone->isDefaultRevision(FALSE);
// Assert that the clone is not in default revision, but the original entity
// is still in the default revision.
$this->assertFalse($clone->isDefaultRevision());
$this->assertTrue($entity->isDefaultRevision());
}
/**
* Tests references of entity properties after entity cloning.
*/
public function testEntityPropertiesModifications() {
// Create a test entity with a translation, which will internally trigger
// entity cloning for the new translation and create references for some of
// the entity properties.
$entity = EntityTestMulRev::create([
'name' => 'original',
'language' => 'en',
]);
$translation = $entity->addTranslation('de');
$entity->save();
// Clone the entity.
$clone = clone $entity;
// Retrieve the entity properties.
$reflection = new \ReflectionClass($entity);
$properties = $reflection->getProperties(~\ReflectionProperty::IS_STATIC);
$translation_unique_properties = ['activeLangcode', 'translationInitialize', 'fieldDefinitions', 'languages', 'langcodeKey', 'defaultLangcode', 'defaultLangcodeKey', 'validated', 'validationRequired', 'entityTypeId', 'typedData', 'cacheContexts', 'cacheTags', 'cacheMaxAge', '_serviceIds'];
foreach ($properties as $property) {
// Modify each entity property on the clone and assert that the change is
// not propagated to the original entity.
$property->setAccessible(TRUE);
$property->setValue($entity, 'default-value');
$property->setValue($translation, 'default-value');
$property->setValue($clone, 'test-entity-cloning');
$this->assertEquals('default-value', $property->getValue($entity), (string) new FormattableMarkup('Entity property %property_name is not cloned properly.', ['%property_name' => $property->getName()]));
$this->assertEquals('default-value', $property->getValue($translation), (string) new FormattableMarkup('Entity property %property_name is not cloned properly.', ['%property_name' => $property->getName()]));
$this->assertEquals('test-entity-cloning', $property->getValue($clone), (string) new FormattableMarkup('Entity property %property_name is not cloned properly.', ['%property_name' => $property->getName()]));
// Modify each entity property on the translation entity object and assert
// that the change is propagated to the default translation entity object
// except for the properties that are unique for each entity translation
// object.
$property->setValue($translation, 'test-translation-cloning');
// Using assertEquals or assertNotEquals here is dangerous as if the
// assertion fails and the property for some reasons contains the entity
// object e.g. the "typedData" property then the property will be
// serialized, but this will cause exceptions because the entity is
// modified in a non-consistent way and ContentEntityBase::__sleep() will
// not be able to properly access all properties and this will cause
// exceptions without a proper backtrace.
if (in_array($property->getName(), $translation_unique_properties)) {
$this->assertEquals('default-value', $property->getValue($entity), (string) new FormattableMarkup('Entity property %property_name is not cloned properly.', ['%property_name' => $property->getName()]));
$this->assertEquals('test-translation-cloning', $property->getValue($translation), (string) new FormattableMarkup('Entity property %property_name is not cloned properly.', ['%property_name' => $property->getName()]));
}
else {
$this->assertEquals('test-translation-cloning', $property->getValue($entity), (string) new FormattableMarkup('Entity property %property_name is not cloned properly.', ['%property_name' => $property->getName()]));
$this->assertEquals('test-translation-cloning', $property->getValue($translation), (string) new FormattableMarkup('Entity property %property_name is not cloned properly.', ['%property_name' => $property->getName()]));
}
}
}
}

View file

@ -101,6 +101,9 @@ class EntityApiTest extends EntityKernelTestBase {
if ($revision_table = $definition->getRevisionTable()) {
$this->assertEqual(0, db_query('SELECT COUNT(*) FROM {' . $revision_table . '}')->fetchField(), 'Data table was emptied');
}
if ($revision_data_table = $definition->getRevisionDataTable()) {
$this->assertEqual(0, db_query('SELECT COUNT(*) FROM {' . $revision_data_table . '}')->fetchField(), 'Data table was emptied');
}
// Test deleting a list of entities not indexed by entity id.
$entities = [];
@ -126,6 +129,9 @@ class EntityApiTest extends EntityKernelTestBase {
if ($revision_table = $definition->getRevisionTable()) {
$this->assertEqual(0, db_query('SELECT COUNT(*) FROM {' . $revision_table . '}')->fetchField(), 'Data table was emptied');
}
if ($revision_data_table = $definition->getRevisionDataTable()) {
$this->assertEqual(0, db_query('SELECT COUNT(*) FROM {' . $revision_data_table . '}')->fetchField(), 'Data table was emptied');
}
}
/**

View file

@ -132,4 +132,29 @@ class EntityRevisionTranslationTest extends EntityKernelTestBase {
$this->assertEquals($forward_revision->getTranslation('de')->name->value, 'forward revision - de');
}
/**
* Tests changing the default revision flag is propagated to all translations.
*/
public function testDefaultRevision() {
// Create a test entity with a translation, which will internally trigger
// entity cloning for the new translation and create references for some of
// the entity properties.
$entity = EntityTestMulRev::create([
'name' => 'original',
'language' => 'en',
]);
$translation = $entity->addTranslation('de');
$entity->save();
// Assert that the entity is in the default revision.
$this->assertTrue($entity->isDefaultRevision());
$this->assertTrue($translation->isDefaultRevision());
// Change the default revision flag on one of the entity translations and
// assert that the change is propagated to all entity translation objects.
$translation->isDefaultRevision(FALSE);
$this->assertFalse($entity->isDefaultRevision());
$this->assertFalse($translation->isDefaultRevision());
}
}

View file

@ -47,7 +47,7 @@ class UnmanagedCopyTest extends FileTestBase {
public function testNonExistent() {
// Copy non-existent file
$desired_filepath = $this->randomMachineName();
$this->assertFalse(file_exists($desired_filepath), "Randomly named file doesn't exists.");
$this->assertFalse(file_exists($desired_filepath), "Randomly named file doesn't exist.");
$new_filepath = file_unmanaged_copy($desired_filepath, $this->randomMachineName());
$this->assertFalse($new_filepath, 'Copying a missing file fails.');
}

View file

@ -1,84 +0,0 @@
<?php
namespace Drupal\KernelTests\Core\HttpKernel;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceModifierInterface;
use Drupal\KernelTests\KernelTestBase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* Tests CORS provided by Drupal.
*
* @see sites/default/default.services.yml
* @see \Asm89\Stack\Cors
* @see \Asm89\Stack\CorsService
*
* @group Http
*/
class CorsIntegrationTest extends KernelTestBase implements ServiceModifierInterface {
/**
* The cors container configuration.
*
* @var null|array
*/
protected $corsConfig = NULL;
/**
* {@inheritdoc}
*/
public static $modules = ['system', 'test_page_test'];
protected function setUp() {
parent::setUp();
$this->installSchema('system', 'router');
\Drupal::service('router.builder')->rebuild();
}
public function testCrossSiteRequest() {
// Test default parameters.
$cors_config = $this->container->getParameter('cors.config');
$this->assertSame(FALSE, $cors_config['enabled']);
$this->assertSame([], $cors_config['allowedHeaders']);
$this->assertSame([], $cors_config['allowedMethods']);
$this->assertSame(['*'], $cors_config['allowedOrigins']);
$this->assertSame(FALSE, $cors_config['exposedHeaders']);
$this->assertSame(FALSE, $cors_config['maxAge']);
$this->assertSame(FALSE, $cors_config['supportsCredentials']);
// Configure the CORS stack to allow a specific set of origins, but don't
// specify an origin header.
$request = Request::create('/test-page');
$request->headers->set('Origin', '');
$cors_config['enabled'] = TRUE;
$cors_config['allowedOrigins'] = ['http://example.com'];
$this->corsConfig = $cors_config;
$this->container->get('kernel')->rebuildContainer();
/** @var \Symfony\Component\HttpFoundation\Response $response */
$response = $this->container->get('http_kernel')->handle($request);
$this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode());
$this->assertEquals('Not allowed.', $response->getContent());
// Specify a valid origin.
$request->headers->set('Origin', 'http://example.com');
$response = $this->container->get('http_kernel')->handle($request);
$this->assertEquals(Response::HTTP_OK, $response->getStatusCode());
}
/**
* {@inheritdoc}
*/
public function alter(ContainerBuilder $container) {
if (isset($this->corsConfig)) {
$container->setParameter('cors.config', $this->corsConfig);
}
}
}

View file

@ -69,8 +69,10 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
/**
* {@inheritdoc}
*
* Kernel tests are run in separate processes to prevent collisions between
* code that may be loaded by tests.
* 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.
*/
protected $runTestInSeparateProcess = TRUE;
@ -130,11 +132,6 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
*/
protected $container;
/**
* @var \Drupal\Core\DependencyInjection\ContainerBuilder
*/
private static $initialContainerBuilder;
/**
* Modules to enable.
*
@ -343,23 +340,13 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
// PHPUnit's @test annotations are intentionally ignored/not supported.
return strpos($method->getName(), 'test') === 0;
}));
if ($test_method_count > 1 && !$this->isTestInIsolation()) {
// Clone a precompiled, empty ContainerBuilder instance for each test.
$container = $this->getCompiledContainerBuilder($modules);
}
// Bootstrap the kernel. Do not use createFromRequest() to retain Settings.
$kernel = new DrupalKernel('testing', $this->classLoader, FALSE);
$kernel->setSitePath($this->siteDirectory);
// Boot the precompiled container. The kernel will enhance it with synthetic
// services.
if (isset($container)) {
$kernel->setContainer($container);
unset($container);
}
// Boot a new one-time container from scratch. Ensure to set the module list
// upfront to avoid a subsequent rebuild.
elseif ($modules && $extensions = $this->getExtensionsForModules($modules)) {
if ($modules && $extensions = $this->getExtensionsForModules($modules)) {
$kernel->updateModules($extensions, $extensions);
}
// DrupalKernel::boot() is not sufficient as it does not invoke preHandle(),
@ -469,68 +456,6 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
return $connection_info;
}
/**
* Prepares a precompiled ContainerBuilder for all tests of this class.
*
* Avoids repetitive calls to ContainerBuilder::compile(), which is very slow.
*
* Based on the (always identical) list of $modules to enable, an initial
* container is compiled, all instantiated services are reset/removed, and
* this precompiled container is stored in a static class property. (Static,
* because PHPUnit instantiates a new class instance for each test *method*.)
*
* This method is not invoked if there is only a single test method. It is
* also not invoked for tests running in process isolation (since each test
* method runs in a separate process).
*
* The ContainerBuilder is not dumped into the filesystem (which would yield
* an actually compiled Container class), because
*
* 1. PHP code cannot be unloaded, so e.g. 900 tests would load 900 different,
* full Container classes into memory, quickly exceeding any sensible
* memory consumption (GigaBytes).
* 2. Dumping a Container class requires to actually write to the system's
* temporary directory. This is not really easy with vfs, because vfs
* doesn't support yet "include 'vfs://container.php'.". Maybe we could fix
* that upstream.
* 3. PhpDumper is very slow on its own.
*
* @param string[] $modules
* The list of modules to enable.
*
* @return \Drupal\Core\DependencyInjection\ContainerBuilder
* A clone of the precompiled, empty service container.
*/
private function getCompiledContainerBuilder(array $modules) {
if (!isset(self::$initialContainerBuilder)) {
$kernel = new DrupalKernel('testing', $this->classLoader, FALSE);
$kernel->setSitePath($this->siteDirectory);
if ($modules && $extensions = $this->getExtensionsForModules($modules)) {
$kernel->updateModules($extensions, $extensions);
}
$kernel->boot();
self::$initialContainerBuilder = $kernel->getContainer();
// Remove all instantiated services, so the container is safe for cloning.
// Technically, ContainerBuilder::set($id, NULL) removes each definition,
// but the container is compiled/frozen already.
foreach (self::$initialContainerBuilder->getServiceIds() as $id) {
self::$initialContainerBuilder->set($id, NULL);
}
// Destruct and trigger garbage collection.
\Drupal::unsetContainer();
$kernel->shutdown();
$kernel = NULL;
// @see register()
$this->container = NULL;
}
$container = clone self::$initialContainerBuilder;
return $container;
}
/**
* Initializes the FileCache component.
*
@ -749,15 +674,6 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
}
}
/**
* {@inheritdoc}
*/
public static function tearDownAfterClass() {
// Free up memory: Precompiled container.
self::$initialContainerBuilder = NULL;
parent::tearDownAfterClass();
}
/**
* Installs default configuration for a given list of modules.
*
@ -1072,13 +988,20 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
}
/**
* Returns whether the current test runs in isolation.
* Returns whether the current test method is running in a separate process.
*
* Note that KernelTestBase will run in a separate process by default.
*
* @return bool
*
* @see \Drupal\KernelTests\KernelTestBase::$runTestInSeparateProcess
* @see https://github.com/sebastianbergmann/phpunit/pull/1350
*
* @deprecated in Drupal 8.4.x, for removal before the Drupal 9.0.0 release.
* KernelTestBase tests are always run in isolated processes.
*/
protected function isTestInIsolation() {
@trigger_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated in Drupal 8.4.x, for removal before the Drupal 9.0.0 release. KernelTestBase tests are always run in isolated processes.', E_USER_DEPRECATED);
return function_exists('__phpunit_run_isolated_test');
}

View file

@ -10,6 +10,8 @@ use org\bovigo\vfs\visitor\vfsStreamStructureVisitor;
/**
* @coversDefaultClass \Drupal\KernelTests\KernelTestBase
* @group PHPUnit
* @group Test
* @group KernelTests
*/
class KernelTestBaseTest extends KernelTestBase {
@ -137,22 +139,21 @@ class KernelTestBaseTest extends KernelTestBase {
}
/**
* @covers ::getCompiledContainerBuilder
* Tests whether the fixture allows us to install modules and configuration.
*
* The point of this test is to have integration level testing.
* @see ::testSubsequentContainerIsolation()
*/
public function testCompiledContainer() {
public function testContainerIsolation() {
$this->enableModules(['system', 'user']);
$this->assertNull($this->installConfig('user'));
}
/**
* @covers ::getCompiledContainerBuilder
* @depends testCompiledContainer
* Tests whether the fixture can re-install modules and configuration.
*
* The point of this test is to have integration level testing.
* @depends testContainerIsolation
*/
public function testCompiledContainerIsDestructed() {
public function testSubsequentContainerIsolation() {
$this->enableModules(['system', 'user']);
$this->assertNull($this->installConfig('user'));
}