reverted: --- b/core/modules/aggregator/src/Plugin/migrate/destination/AggregatorItem.php +++ /dev/null @@ -1,42 +0,0 @@ -getDestinationProperty('fid')) { - $field_definitions = \Drupal::entityManager() - ->getFieldDefinitions($this->storage->getEntityTypeId(), - $this->getKey('bundle')); - $value = EntityReferenceItem::generateSampleValue($field_definitions['fid']); - if (is_null($value)) { - throw new MigrateException($this->t('Stubbing failed, unable to generate value for field @name', - ['@name' => 'fid'])); - } - $row->setDestinationProperty('fid', $value); - } - } - -} diff -u b/core/modules/aggregator/src/Tests/Migrate/MigrateAggregatorStubTest.php b/core/modules/aggregator/src/Tests/Migrate/MigrateAggregatorStubTest.php --- b/core/modules/aggregator/src/Tests/Migrate/MigrateAggregatorStubTest.php +++ b/core/modules/aggregator/src/Tests/Migrate/MigrateAggregatorStubTest.php @@ -9,6 +9,7 @@ use Drupal\migrate\MigrateException; use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase; +use Drupal\migrate_drupal\Tests\StubTestTrait; /** * Test stub creation for aggregator feeds and items. @@ -17,6 +18,8 @@ */ class MigrateAggregatorStubTest extends MigrateDrupalTestBase { + use StubTestTrait; + /** * {@inheritdoc} */ @@ -45,7 +48,7 @@ try { // We expect an exception, because there's no feed to reference. $this->performStubTest('aggregator_item'); - $this->fail(t('Expected exception has not been thrown.')); + $this->fail('Expected exception has not been thrown.'); } catch (MigrateException $e) { $this->assertIdentical($e->getMessage(), diff -u b/core/modules/block_content/src/Tests/Migrate/MigrateBlockContentStubTest.php b/core/modules/block_content/src/Tests/Migrate/MigrateBlockContentStubTest.php --- b/core/modules/block_content/src/Tests/Migrate/MigrateBlockContentStubTest.php +++ b/core/modules/block_content/src/Tests/Migrate/MigrateBlockContentStubTest.php @@ -7,7 +7,9 @@ namespace Drupal\block_content\Tests\Migrate; +use Drupal\block_content\Entity\BlockContentType; use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase; +use Drupal\migrate_drupal\Tests\StubTestTrait; /** * Test stub creation for block_content entities. @@ -16,6 +18,8 @@ */ class MigrateBlockContentStubTest extends MigrateDrupalTestBase { + use StubTestTrait; + /** * {@inheritdoc} */ @@ -30,9 +34,26 @@ } /** - * Tests creation of block content stubs. + * Tests creation of block content stubs with no block_content_type available. + */ + public function testStubFailure() { + $entity_id = $this->createStub('block_content'); + $violations = $this->validateStub('block_content', $entity_id); + $this->assertIdentical(count($violations), 1); + $this->assertEqual($violations[0]->getMessage(), t('The referenced entity (%type: %id) does not exist.', [ + '%type' => 'block_content_type', + '%id' => 'block_content', + ])); + } + + /** + * Tests creation of block content stubs when there is a block_content_type. */ - public function testStub() { + public function testStubSuccess() { + BlockContentType::create([ + 'id' => 'test_block_content_type', + 'label' => 'Test block content type', + ])->save(); $this->performStubTest('block_content'); } diff -u b/core/modules/comment/src/Tests/Migrate/MigrateCommentStubTest.php b/core/modules/comment/src/Tests/Migrate/MigrateCommentStubTest.php --- b/core/modules/comment/src/Tests/Migrate/MigrateCommentStubTest.php +++ b/core/modules/comment/src/Tests/Migrate/MigrateCommentStubTest.php @@ -7,8 +7,11 @@ namespace Drupal\comment\Tests\Migrate; +use Drupal\comment\Entity\CommentType; use Drupal\migrate\MigrateException; use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase; +use Drupal\migrate_drupal\Tests\StubTestTrait; +use Drupal\node\Entity\NodeType; /** * Test stub creation for comment entities. @@ -17,6 +20,8 @@ */ class MigrateCommentStubTest extends MigrateDrupalTestBase { + use StubTestTrait; + /** * {@inheritdoc} */ @@ -29,6 +34,26 @@ parent::setUp(); $this->installEntitySchema('comment'); $this->installEntitySchema('node'); + // Make sure uid 0 is created (default uid for comments is 0). + $storage = \Drupal::entityManager()->getStorage('user'); + // Insert a row for the anonymous user. + $storage + ->create(array( + 'uid' => 0, + 'status' => 0, + 'name' => '', + )) + ->save(); + // Need at least one node type and comment type present. + NodeType::create([ + 'type' => 'testnodetype', + 'name' => 'Test node type', + ])->save(); + CommentType::create([ + 'id' => 'testcommenttype', + 'label' => 'Test comment type', + 'target_entity_type_id' => 'node', + ])->save(); } /** @@ -38,7 +63,7 @@ try { // We expect an exception, because there's no node to reference. $this->performStubTest('comment'); - $this->fail(t('Expected exception has not been thrown.')); + $this->fail('Expected exception has not been thrown.'); } catch (MigrateException $e) { $this->assertIdentical($e->getMessage(), diff -u b/core/modules/file/src/Plugin/migrate/destination/EntityFile.php b/core/modules/file/src/Plugin/migrate/destination/EntityFile.php --- b/core/modules/file/src/Plugin/migrate/destination/EntityFile.php +++ b/core/modules/file/src/Plugin/migrate/destination/EntityFile.php @@ -275,17 +275,22 @@ protected function processStubRow(Row $row) { // We stub the uri value ourselves so we can create a real stub file for it. if (!$row->getDestinationProperty('uri')) { + // @todo Inject the entity manager. + // @see https://www.drupal.org/node/2604566 $field_definitions = \Drupal::entityManager() ->getFieldDefinitions($this->storage->getEntityTypeId(), $this->getKey('bundle')); $value = UriItem::generateSampleValue($field_definitions['uri']); - if (is_null($value)) { - throw new MigrateException($this->t('Stubbing failed, unable to generate value for field @name', - ['@name' => 'uri'])); + if (empty($value)) { + throw new MigrateException('Stubbing failed, unable to generate value for field uri'); } // generateSampleValue() wraps the value in an array. $value = reset($value); - // Make it into a proper public file uri. + // Make it into a proper public file uri, stripping off the existing + // scheme if present. + if (strpos($value, 'http://') === 0) { + $value = substr($value, 7); + } $value = 'public://' . substr($value, 9); // Create a real file, so File::preSave() can do filesize() on it. touch($value); diff -u b/core/modules/file/src/Tests/Migrate/MigrateFileStubTest.php b/core/modules/file/src/Tests/Migrate/MigrateFileStubTest.php --- b/core/modules/file/src/Tests/Migrate/MigrateFileStubTest.php +++ b/core/modules/file/src/Tests/Migrate/MigrateFileStubTest.php @@ -8,6 +8,7 @@ namespace Drupal\file\Tests\Migrate; use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase; +use Drupal\migrate_drupal\Tests\StubTestTrait; /** * Test stub creation for file entities. @@ -16,6 +17,8 @@ */ class MigrateFileStubTest extends MigrateDrupalTestBase { + use StubTestTrait; + /** * {@inheritdoc} */ diff -u b/core/modules/menu_link_content/src/Tests/Migrate/MigrateMenuLinkContentStubTest.php b/core/modules/menu_link_content/src/Tests/Migrate/MigrateMenuLinkContentStubTest.php --- b/core/modules/menu_link_content/src/Tests/Migrate/MigrateMenuLinkContentStubTest.php +++ b/core/modules/menu_link_content/src/Tests/Migrate/MigrateMenuLinkContentStubTest.php @@ -8,6 +8,7 @@ namespace Drupal\menu_link_content\Tests\Migrate; use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase; +use Drupal\migrate_drupal\Tests\StubTestTrait; /** * Test stub creation for menu link content entities. @@ -16,6 +17,8 @@ */ class MigrateMenuLinkContentStubTest extends MigrateDrupalTestBase { + use StubTestTrait; + /** * {@inheritdoc} */ diff -u b/core/modules/migrate/src/Plugin/migrate/destination/Entity.php b/core/modules/migrate/src/Plugin/migrate/destination/Entity.php --- b/core/modules/migrate/src/Plugin/migrate/destination/Entity.php +++ b/core/modules/migrate/src/Plugin/migrate/destination/Entity.php @@ -8,10 +8,13 @@ namespace Drupal\migrate\Plugin\migrate\destination; use Drupal\Component\Plugin\DependentPluginInterface; +use Drupal\Component\Utility\Random; +use Drupal\Component\Utility\Unicode; use Drupal\Core\Entity\DependencyTrait; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Field\FieldItemInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\link\LinkItemInterface; use Drupal\migrate\Entity\MigrationInterface; use Drupal\migrate\MigrateException; use Drupal\migrate\Plugin\MigrateIdMapInterface; @@ -152,36 +155,60 @@ } // Populate any required fields not already populated. + // @todo Inject the entity manager. + // @see https://www.drupal.org/node/2604566 $fields = \Drupal::entityManager() ->getFieldDefinitions($this->storage->getEntityTypeId(), $bundle_key); foreach ($fields as $field_name => $field_definition) { if ($field_definition->isRequired() && is_null($row->getDestinationProperty($field_name))) { // Use the configured default value for this specific field, if any. if ($default_value = $field_definition->getDefaultValueLiteral()) { - $value = $default_value; + $values[] = $default_value; } else { // Otherwise, ask the field type to generate a sample value. + // @todo Inject the field type manager. + // @see https://www.drupal.org/node/2604566 + $field_type = $field_definition->getType(); /** @var \Drupal\Core\Field\FieldItemInterface $field_type_class */ $field_type_class = \Drupal::service('plugin.manager.field.field_type') ->getPluginClass($field_definition->getType()); - $value = $field_type_class::generateSampleValue($field_definition); - if (is_null($value)) { + $values = $field_type_class::generateSampleValue($field_definition); + if (is_null($values)) { // Handle failure to generate a sample value. - switch ($field_definition->getType()) { - case 'list_integer': - // @todo Remove when https://www.drupal.org/node/2536374 is committed. - $value = 1; - break; - default: - throw new MigrateException($this->t('Stubbing failed, unable to generate value for field @name', - ['@name' => $field_name])); - break; + if ($field_type == 'list_integer') { + // @todo Remove when https://www.drupal.org/node/2536374 is committed. + $allowed_options = options_allowed_values($field_definition->getFieldStorageDefinition()); + $values['value'] = array_rand($allowed_options); + } + else { + throw new MigrateException('Stubbing failed, unable to generate value for field ' . $field_name); + break; + } + } + else { + // @todo UriItem does not generate a valid uri. + // @see https://www.drupal.org/node/2605150 + if ($field_type == 'uri') { + foreach ($values as $key => $value) { + if (!strpos($value, '://')) { + $suffix_length = Unicode::strlen($value) - 7; + $values[$key] = 'http://' . Unicode::substr($value, 0, $suffix_length); + } + } + } + // @todo LinkItem does not generate a valid internal link. + // @see https://www.drupal.org/node/2605254 + elseif ($field_type == 'link') { + if ($field_definition->getItemDefinition()->getSetting('link_type') & LinkItemInterface::LINK_INTERNAL) { + $random = new Random(); + $values['uri'] = 'base:' . $random->name(mt_rand(1, 64)); + } } } } - $row->setDestinationProperty($field_name, $value); + $row->setDestinationProperty($field_name, $values); } } } reverted: --- b/core/modules/migrate_drupal/src/Tests/MigrateDrupalTestBase.php +++ a/core/modules/migrate_drupal/src/Tests/MigrateDrupalTestBase.php @@ -8,9 +8,6 @@ namespace Drupal\migrate_drupal\Tests; use Drupal\Core\Database\Database; -use Drupal\Core\Entity\ContentEntityBase; -use Drupal\migrate\Entity\Migration; -use Drupal\migrate\Row; use Drupal\migrate\Tests\MigrateTestBase; use Drupal\Component\Plugin\Exception\PluginNotFoundException; @@ -76,47 +73,4 @@ } } - /** - * Test that creating a stub of the given entity type results in a valid - * entity. - * - * @param string $entity_type_id - * The entity type we are stubbing. - */ - protected function performStubTest($entity_type_id) { - $destination_id = $this->createStub($entity_type_id); - $controller = \Drupal::entityManager()->getStorage($entity_type_id); - /** @var \Drupal\Core\Entity\ContentEntityBase $stub_entity */ - $stub_entity = $controller->load($destination_id); - $this->assertTrue($stub_entity, 'Stub successfully created'); - if ($stub_entity) { - $this->assertTrue($stub_entity->validate(), 'Stub is a valid entity'); - } - } - - /** - * Create a stub of the given entity type. - * - * @param string $entity_type_id - * The entity type we are stubbing. - * - * @return int - * ID of the created entity. - */ - protected function createStub($entity_type_id) { - // Create a dummy migration to pass to the destination plugin. - $config = [ - 'id' => 'dummy', - 'migration_tags' => ['Stub test'], - 'source' => ['plugin' => 'empty'], - 'process' => [], - 'destination' => ['plugin' => 'entity:' . $entity_type_id], - ]; - $migration = Migration::create($config); - $destination_plugin = $migration->getDestinationPlugin(TRUE); - $stub_row = new Row([], [], TRUE); - $destination_ids = $destination_plugin->import($stub_row); - return reset($destination_ids); - } - } diff -u b/core/modules/node/src/Tests/Migrate/MigrateNodeStubTest.php b/core/modules/node/src/Tests/Migrate/MigrateNodeStubTest.php --- b/core/modules/node/src/Tests/Migrate/MigrateNodeStubTest.php +++ b/core/modules/node/src/Tests/Migrate/MigrateNodeStubTest.php @@ -8,6 +8,8 @@ namespace Drupal\node\Tests\Migrate; use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase; +use Drupal\migrate_drupal\Tests\StubTestTrait; +use Drupal\node\Entity\NodeType; /** * Test stub creation for nodes. @@ -16,6 +18,8 @@ */ class MigrateNodeStubTest extends MigrateDrupalTestBase { + use StubTestTrait; + /** * {@inheritdoc} */ @@ -27,6 +31,11 @@ protected function setUp() { parent::setUp(); $this->installEntitySchema('node'); + // Need at least one node type present. + NodeType::create([ + 'type' => 'testnodetype', + 'name' => 'Test node type', + ])->save(); } /** diff -u b/core/modules/shortcut/src/Tests/Migrate/MigrateShortcutStubTest.php b/core/modules/shortcut/src/Tests/Migrate/MigrateShortcutStubTest.php --- b/core/modules/shortcut/src/Tests/Migrate/MigrateShortcutStubTest.php +++ b/core/modules/shortcut/src/Tests/Migrate/MigrateShortcutStubTest.php @@ -8,6 +8,7 @@ namespace Drupal\shortcut\Tests\Migrate; use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase; +use Drupal\migrate_drupal\Tests\StubTestTrait; /** * Test stub creation for shortcut entities. @@ -16,6 +17,8 @@ */ class MigrateShortcutStubTest extends MigrateDrupalTestBase { + use StubTestTrait; + /** * {@inheritdoc} */ diff -u b/core/modules/taxonomy/src/Tests/Migrate/MigrateTaxonomyTermStubTest.php b/core/modules/taxonomy/src/Tests/Migrate/MigrateTaxonomyTermStubTest.php --- b/core/modules/taxonomy/src/Tests/Migrate/MigrateTaxonomyTermStubTest.php +++ b/core/modules/taxonomy/src/Tests/Migrate/MigrateTaxonomyTermStubTest.php @@ -10,7 +10,9 @@ use Drupal\migrate\Entity\Migration; use Drupal\migrate\MigrateExecutable; use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase; +use Drupal\migrate_drupal\Tests\StubTestTrait; use Drupal\taxonomy\Entity\Term; +use Drupal\taxonomy\Entity\Vocabulary; /** * Test stub creation for taxonomy terms. @@ -19,6 +21,8 @@ */ class MigrateTaxonomyTermStubTest extends MigrateDrupalTestBase { + use StubTestTrait; + /** * {@inheritdoc} */ @@ -36,6 +40,10 @@ * Tests creation of taxonomy term stubs. */ public function testStub() { + Vocabulary::create([ + 'vid' => 'test_vocabulary', + 'name' => 'Test vocabulary', + ])->save(); $this->performStubTest('taxonomy_term'); } @@ -104,7 +112,7 @@ $stub_entity = Term::load(2); $this->assertTrue($stub_entity, 'Stub successfully created'); if ($stub_entity) { - $this->assertTrue($stub_entity->validate(), 'Stub is a valid entity'); + $this->assertIdentical(count($stub_entity->validate()), 0, 'Stub is a valid entity'); } } } diff -u b/core/modules/user/src/Plugin/migrate/destination/EntityUser.php b/core/modules/user/src/Plugin/migrate/destination/EntityUser.php --- b/core/modules/user/src/Plugin/migrate/destination/EntityUser.php +++ b/core/modules/user/src/Plugin/migrate/destination/EntityUser.php @@ -10,6 +10,7 @@ use Drupal\Component\Utility\Unicode; use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Entity\EntityStorageInterface; +use Drupal\Core\Field\Plugin\Field\FieldType\EmailItem; use Drupal\Core\Password\PasswordInterface; use Drupal\migrate\Entity\MigrationInterface; use Drupal\migrate\MigrateException; @@ -104,8 +105,18 @@ */ protected function processStubRow(Row $row) { parent::processStubRow($row); - // Work-around for https://www.drupal.org/node/2602066 - this function can - // be removed when that's committed. + // Email address is not defined as required in the base field definition but + // is effectively required by the UserMailRequired constraint. This means + // that Entity::processStubRow() did not populate it - we do it here. + // @todo Inject the entity manager. + // @see https://www.drupal.org/node/2604566 + $field_definitions = \Drupal::entityManager() + ->getFieldDefinitions($this->storage->getEntityTypeId(), + $this->getKey('bundle')); + $mail = EmailItem::generateSampleValue($field_definitions['mail']); + $row->setDestinationProperty('mail', reset($mail)); + + // %todo Work-around for https://www.drupal.org/node/2602066. $name = $row->getDestinationProperty('name'); if (is_array($name)) { $name = reset($name); diff -u b/core/modules/user/src/Tests/Migrate/MigrateUserStubTest.php b/core/modules/user/src/Tests/Migrate/MigrateUserStubTest.php --- b/core/modules/user/src/Tests/Migrate/MigrateUserStubTest.php +++ b/core/modules/user/src/Tests/Migrate/MigrateUserStubTest.php @@ -8,6 +8,7 @@ namespace Drupal\user\Tests\Migrate; use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase; +use Drupal\migrate_drupal\Tests\StubTestTrait; /** * Test stub creation for user entities. @@ -16,6 +17,8 @@ */ class MigrateUserStubTest extends MigrateDrupalTestBase { + use StubTestTrait; + /** * {@inheritdoc} */ only in patch2: unchanged: --- /dev/null +++ b/core/modules/migrate_drupal/src/Tests/StubTestTrait.php @@ -0,0 +1,80 @@ +createStub($entity_type_id); + $this->assertTrue($entity_id, 'Stub successfully created'); + if ($entity_id) { + $violations = $this->validateStub($entity_type_id, $entity_id); + if (!$this->assertIdentical(count($violations), 0, 'Stub is a valid entity')) { + foreach ($violations as $violation) { + $this->fail((string)$violation->getMessage()); + } + } + } + } + + /** + * Create a stub of the given entity type. + * + * @param string $entity_type_id + * The entity type we are stubbing. + * + * @return int + * ID of the created entity. + */ + protected function createStub($entity_type_id) { + // Create a dummy migration to pass to the destination plugin. + $config = [ + 'id' => 'dummy', + 'migration_tags' => ['Stub test'], + 'source' => ['plugin' => 'empty'], + 'process' => [], + 'destination' => ['plugin' => 'entity:' . $entity_type_id], + ]; + $migration = Migration::create($config); + $destination_plugin = $migration->getDestinationPlugin(TRUE); + $stub_row = new Row([], [], TRUE); + $destination_ids = $destination_plugin->import($stub_row); + return reset($destination_ids); + } + + /** + * Perform validation on a stub entity. + * + * @param string $entity_type_id + * The entity type we are stubbing. + * @param string $entity_id + * ID of the stubbed entity to validate. + * + * @return \Drupal\Core\Entity\EntityConstraintViolationListInterface + * List of constraint violations identified. + */ + protected function validateStub($entity_type_id, $entity_id) { + $controller = \Drupal::entityManager()->getStorage($entity_type_id); + /** @var \Drupal\Core\Entity\ContentEntityInterface $stub_entity */ + $stub_entity = $controller->load($entity_id); + return $stub_entity->validate(); + } + +} only in patch2: unchanged: --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Field/FieldGenerateSampleValueTest.php @@ -0,0 +1,63 @@ +getMock('\Symfony\Component\Validator\Context\ExecutionContextInterface'); + $context->expects($this->any()) + ->method('getObject') + ->willReturn($typed_data); + + $context->expects($this->never()) + ->method('addViolation'); + + $constraint = new PrimitiveTypeConstraint(); + + $validate = new PrimitiveTypeConstraintValidator(); + $validate->initialize($context); + $validate->validate($value, $constraint); + } + + public function provideTestValidate() { + $data = []; + $field_definition = FieldItemDataDefinition::createFromDataType('field_item:boolean'); + $data[] = [new BooleanData(DataDefinition::create('boolean')), BooleanItem::generateSampleValue($field_definition->getFieldDefinition())]; + $data[] = [new FloatData(DataDefinition::create('float')), 'test']; + $data[] = [new IntegerData(DataDefinition::create('integer')), 'test']; + $data[] = [new StringData(DataDefinition::create('string')), []]; + $data[] = [new Uri(DataDefinition::create('uri')), 'drupal.org']; + + return $data; + } + +}