Update to Drupal 8.2.5. For more information, see https://www.drupal.org/project/drupal/releases/8.2.5
This commit is contained in:
parent
8544b60b39
commit
db56c09587
86 changed files with 2413 additions and 488 deletions
|
|
@ -0,0 +1,7 @@
|
|||
type: module
|
||||
name: Migrate query batch Source test
|
||||
description: 'Provides a database table and records for SQL import with batch testing.'
|
||||
package: Testing
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- migrate
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\migrate_query_batch_test\Plugin\migrate\source;
|
||||
|
||||
use Drupal\migrate\Plugin\migrate\source\SqlBase;
|
||||
|
||||
/**
|
||||
* Source plugin for migration high water tests.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "query_batch_test"
|
||||
* )
|
||||
*/
|
||||
class QueryBatchTest extends SqlBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
return ($this->select('query_batch_test', 'q')->fields('q'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
$fields = [
|
||||
'id' => $this->t('Id'),
|
||||
'data' => $this->t('data'),
|
||||
];
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
return [
|
||||
'id' => [
|
||||
'type' => 'integer',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\migrate\Functional\process;
|
||||
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\migrate\MigrateMessage;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the 'download' process plugin.
|
||||
*
|
||||
* @group migrate
|
||||
*/
|
||||
class DownloadFunctionalTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['migrate', 'file'];
|
||||
|
||||
/**
|
||||
* Tests that an exception is thrown bu migration continues with the next row.
|
||||
*/
|
||||
public function testExceptionThrow() {
|
||||
$invalid_url = "{$this->baseUrl}/not-existent-404";
|
||||
$valid_url = "{$this->baseUrl}/core/misc/favicon.ico";
|
||||
|
||||
$definition = [
|
||||
'source' => [
|
||||
'plugin' => 'embedded_data',
|
||||
'data_rows' => [
|
||||
['url' => $invalid_url, 'uri' => 'public://first.txt'],
|
||||
['url' => $valid_url, 'uri' => 'public://second.ico'],
|
||||
],
|
||||
'ids' => [
|
||||
'url' => ['type' => 'string'],
|
||||
],
|
||||
],
|
||||
'process' => [
|
||||
'uri' => [
|
||||
'plugin' => 'download',
|
||||
'source' => ['url', 'uri'],
|
||||
]
|
||||
],
|
||||
'destination' => [
|
||||
'plugin' => 'entity:file',
|
||||
],
|
||||
];
|
||||
|
||||
$migration = \Drupal::service('plugin.manager.migration')->createStubMigration($definition);
|
||||
|
||||
$executable = new MigrateExecutable($migration, new MigrateMessage());
|
||||
$result = $executable->import();
|
||||
|
||||
// Check that the migration has completed.
|
||||
$this->assertEquals($result, MigrationInterface::RESULT_COMPLETED);
|
||||
|
||||
/** @var \Drupal\migrate\Plugin\MigrateIdMapInterface $id_map_plugin */
|
||||
$id_map_plugin = $migration->getIdMap();
|
||||
|
||||
// Check that the first row was marked as failed in the id map table.
|
||||
$map_row = $id_map_plugin->getRowBySource(['url' => $invalid_url]);
|
||||
$this->assertEquals(MigrateIdMapInterface::STATUS_FAILED, $map_row['source_row_status']);
|
||||
$this->assertNull($map_row['destid1']);
|
||||
|
||||
// Check that a message with the thrown exception has been logged.
|
||||
$messages = $id_map_plugin->getMessageIterator(['url' => $invalid_url])->fetchAll();
|
||||
$this->assertCount(1, $messages);
|
||||
$message = reset($messages);
|
||||
$this->assertEquals("Cannot read from non-readable stream ($invalid_url)", $message->message);
|
||||
$this->assertEquals(MigrationInterface::MESSAGE_ERROR, $message->level);
|
||||
|
||||
// Check that the second row was migrated successfully.
|
||||
$map_row = $id_map_plugin->getRowBySource(['url' => $valid_url]);
|
||||
$this->assertEquals(MigrateIdMapInterface::STATUS_IMPORTED, $map_row['source_row_status']);
|
||||
$this->assertEquals(1, $map_row['destid1']);
|
||||
}
|
||||
|
||||
}
|
||||
261
core/modules/migrate/tests/src/Kernel/QueryBatchTest.php
Normal file
261
core/modules/migrate/tests/src/Kernel/QueryBatchTest.php
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\migrate\Kernel;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\Core\Database\Driver\sqlite\Connection;
|
||||
|
||||
/**
|
||||
* Tests query batching.
|
||||
*
|
||||
* @covers \Drupal\migrate_query_batch_test\Plugin\migrate\source\QueryBatchTest
|
||||
* @group migrate
|
||||
*/
|
||||
class QueryBatchTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* The mocked migration.
|
||||
*
|
||||
* @var MigrationInterface|\Prophecy\Prophecy\ObjectProphecy
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'migrate',
|
||||
'migrate_query_batch_test',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create a mock migration. This will be injected into the source plugin
|
||||
// under test.
|
||||
$this->migration = $this->prophesize(MigrationInterface::class);
|
||||
|
||||
$this->migration->id()->willReturn(
|
||||
$this->randomMachineName(16)
|
||||
);
|
||||
// Prophesize a useless ID map plugin and an empty set of destination IDs.
|
||||
// Calling code can override these prophecies later and set up different
|
||||
// behaviors.
|
||||
$this->migration->getIdMap()->willReturn(
|
||||
$this->prophesize(MigrateIdMapInterface::class)->reveal()
|
||||
);
|
||||
$this->migration->getDestinationIds()->willReturn([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a negative batch size throws an exception.
|
||||
*/
|
||||
public function testBatchSizeNegative() {
|
||||
$this->setExpectedException(MigrateException::class, 'batch_size must be greater than or equal to zero');
|
||||
$plugin = $this->getPlugin(['batch_size' => -1]);
|
||||
$plugin->next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a non integer batch size throws an exception.
|
||||
*/
|
||||
public function testBatchSizeNonInteger() {
|
||||
$this->setExpectedException(MigrateException::class, 'batch_size must be greater than or equal to zero');
|
||||
$plugin = $this->getPlugin(['batch_size' => '1']);
|
||||
$plugin->next();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function queryDataProvider() {
|
||||
// Define the parameters for building the data array. The first element is
|
||||
// the number of source data rows, the second is the batch size to set on
|
||||
// the plugin configuration.
|
||||
$test_parameters = [
|
||||
// Test when batch size is 0.
|
||||
[200, 0],
|
||||
// Test when rows mod batch size is 0.
|
||||
[200, 20],
|
||||
// Test when rows mod batch size is > 0.
|
||||
[200, 30],
|
||||
// Test when batch size = row count.
|
||||
[200, 200],
|
||||
// Test when batch size > row count.
|
||||
[200, 300],
|
||||
];
|
||||
|
||||
// Build the data provider array. The provider array consists of the source
|
||||
// data rows, the expected result data, the expected count, the plugin
|
||||
// configuration, the expected batch size and the expected batch count.
|
||||
$table = 'query_batch_test';
|
||||
$tests = [];
|
||||
$data_set = 0;
|
||||
foreach ($test_parameters as $data) {
|
||||
list($num_rows, $batch_size) = $data;
|
||||
for ($i = 0; $i < $num_rows; $i++) {
|
||||
$tests[$data_set]['source_data'][$table][] = [
|
||||
'id' => $i,
|
||||
'data' => $this->randomString(),
|
||||
];
|
||||
}
|
||||
$tests[$data_set]['expected_data'] = $tests[$data_set]['source_data'][$table];
|
||||
$tests[$data_set][2] = $num_rows;
|
||||
// Plugin configuration array.
|
||||
$tests[$data_set][3] = ['batch_size' => $batch_size];
|
||||
// Expected batch size.
|
||||
$tests[$data_set][4] = $batch_size;
|
||||
// Expected batch count is 0 unless a batch size is set.
|
||||
$expected_batch_count = 0;
|
||||
if ($batch_size > 0) {
|
||||
$expected_batch_count = (int) ($num_rows / $batch_size);
|
||||
if ($num_rows % $batch_size) {
|
||||
// If there is a remainder an extra batch is needed to get the
|
||||
// remaining rows.
|
||||
$expected_batch_count++;
|
||||
}
|
||||
}
|
||||
$tests[$data_set][5] = $expected_batch_count;
|
||||
$data_set++;
|
||||
}
|
||||
return $tests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests query batch size.
|
||||
*
|
||||
* @param array $source_data
|
||||
* The source data, keyed by table name. Each table is an array containing
|
||||
* the rows in that table.
|
||||
* @param array $expected_data
|
||||
* The result rows the plugin is expected to return.
|
||||
* @param int $num_rows
|
||||
* How many rows the source plugin is expected to return.
|
||||
* @param array $configuration
|
||||
* Configuration for the source plugin specifying the batch size.
|
||||
* @param int $expected_batch_size
|
||||
* The expected batch size, will be set to zero for invalid batch sizes.
|
||||
* @param int $expected_batch_count
|
||||
* The total number of batches.
|
||||
*
|
||||
* @dataProvider queryDataProvider
|
||||
*/
|
||||
public function testQueryBatch($source_data, $expected_data, $num_rows, $configuration, $expected_batch_size, $expected_batch_count) {
|
||||
$plugin = $this->getPlugin($configuration);
|
||||
|
||||
// Since we don't yet inject the database connection, we need to use a
|
||||
// reflection hack to set it in the plugin instance.
|
||||
$reflector = new \ReflectionObject($plugin);
|
||||
$property = $reflector->getProperty('database');
|
||||
$property->setAccessible(TRUE);
|
||||
|
||||
$connection = $this->getDatabase($source_data);
|
||||
$property->setValue($plugin, $connection);
|
||||
|
||||
// Test the results.
|
||||
$i = 0;
|
||||
/** @var \Drupal\migrate\Row $row */
|
||||
foreach ($plugin as $row) {
|
||||
|
||||
$expected = $expected_data[$i++];
|
||||
$actual = $row->getSource();
|
||||
|
||||
foreach ($expected as $key => $value) {
|
||||
$this->assertArrayHasKey($key, $actual);
|
||||
$this->assertSame((string) $value, (string) $actual[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that all rows were retrieved.
|
||||
self::assertSame($num_rows, $i);
|
||||
|
||||
// Test the batch size.
|
||||
if (is_null($expected_batch_size)) {
|
||||
$expected_batch_size = $configuration['batch_size'];
|
||||
}
|
||||
$property = $reflector->getProperty('batchSize');
|
||||
$property->setAccessible(TRUE);
|
||||
self::assertSame($expected_batch_size, $property->getValue($plugin));
|
||||
|
||||
// Test the batch count.
|
||||
if (is_null($expected_batch_count)) {
|
||||
$expected_batch_count = intdiv($num_rows, $expected_batch_size);
|
||||
if ($num_rows % $configuration['batch_size']) {
|
||||
$expected_batch_count++;
|
||||
}
|
||||
}
|
||||
$property = $reflector->getProperty('batch');
|
||||
$property->setAccessible(TRUE);
|
||||
self::assertSame($expected_batch_count, $property->getValue($plugin));
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates the source plugin under test.
|
||||
*
|
||||
* @param array $configuration
|
||||
* The source plugin configuration.
|
||||
*
|
||||
* @return \Drupal\migrate\Plugin\MigrateSourceInterface|object
|
||||
* The fully configured source plugin.
|
||||
*/
|
||||
protected function getPlugin($configuration) {
|
||||
/** @var \Drupal\migrate\Plugin\MigratePluginManager $plugin_manager */
|
||||
$plugin_manager = $this->container->get('plugin.manager.migrate.source');
|
||||
$plugin = $plugin_manager->createInstance('query_batch_test', $configuration, $this->migration->reveal());
|
||||
|
||||
$this->migration
|
||||
->getSourcePlugin()
|
||||
->willReturn($plugin);
|
||||
return $plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an in-memory SQLite database from a set of source data.
|
||||
*
|
||||
* @param array $source_data
|
||||
* The source data, keyed by table name. Each table is an array containing
|
||||
* the rows in that table.
|
||||
*
|
||||
* @return \Drupal\Core\Database\Driver\sqlite\Connection
|
||||
* The SQLite database connection.
|
||||
*/
|
||||
protected function getDatabase(array $source_data) {
|
||||
// Create an in-memory SQLite database. Plugins can interact with it like
|
||||
// any other database, and it will cease to exist when the connection is
|
||||
// closed.
|
||||
$connection_options = ['database' => ':memory:'];
|
||||
$pdo = Connection::open($connection_options);
|
||||
$connection = new Connection($pdo, $connection_options);
|
||||
|
||||
// Create the tables and fill them with data.
|
||||
foreach ($source_data as $table => $rows) {
|
||||
// Use the biggest row to build the table schema.
|
||||
$counts = array_map('count', $rows);
|
||||
asort($counts);
|
||||
end($counts);
|
||||
$pilot = $rows[key($counts)];
|
||||
|
||||
$connection->schema()
|
||||
->createTable($table, [
|
||||
// SQLite uses loose affinity typing, so it's OK for every field to
|
||||
// be a text field.
|
||||
'fields' => array_map(function () {
|
||||
return ['type' => 'text'];
|
||||
}, $pilot),
|
||||
]);
|
||||
|
||||
$fields = array_keys($pilot);
|
||||
$insert = $connection->insert($table)->fields($fields);
|
||||
array_walk($rows, [$insert, 'values']);
|
||||
$insert->execute();
|
||||
}
|
||||
return $connection;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ namespace Drupal\Tests\migrate\Kernel\process;
|
|||
|
||||
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
|
||||
use Drupal\KernelTests\Core\File\FileTestBase;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\Plugin\migrate\process\FileCopy;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Plugin\MigrateProcessInterface;
|
||||
|
|
@ -12,6 +13,8 @@ use Drupal\migrate\Row;
|
|||
/**
|
||||
* Tests the file_copy process plugin.
|
||||
*
|
||||
* @coversDefaultClass \Drupal\migrate\Plugin\migrate\process\FileCopy
|
||||
*
|
||||
* @group migrate
|
||||
*/
|
||||
class FileCopyTest extends FileTestBase {
|
||||
|
|
@ -120,6 +123,32 @@ class FileCopyTest extends FileTestBase {
|
|||
$this->doTransform($source, 'public://wontmatter.jpg');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that non-writable destination throw an exception.
|
||||
*
|
||||
* @covers ::transform
|
||||
*/
|
||||
public function testNonWritableDestination() {
|
||||
$source = $this->createUri('file.txt', NULL, 'temporary');
|
||||
|
||||
// Create the parent location.
|
||||
$this->createDirectory('public://dir');
|
||||
|
||||
// Copy the file under public://dir/subdir1/.
|
||||
$this->doTransform($source, 'public://dir/subdir1/file.txt');
|
||||
|
||||
// Check that 'subdir1' was created and the file was successfully migrated.
|
||||
$this->assertFileExists('public://dir/subdir1/file.txt');
|
||||
|
||||
// Remove all permissions from public://dir to trigger a failure when
|
||||
// trying to create a subdirectory 'subdir2' inside public://dir.
|
||||
$this->fileSystem->chmod('public://dir', 0);
|
||||
|
||||
// Check that the proper exception is raised.
|
||||
$this->setExpectedException(MigrateException::class, "Could not create or write to directory 'public://dir/subdir2'");
|
||||
$this->doTransform($source, 'public://dir/subdir2/file.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the 'rename' overwrite mode.
|
||||
*/
|
||||
|
|
|
|||
Reference in a new issue