Issue #2545672 by mikeryan, benjy, phenaproxima: Handle various migration interruption scenarios

8.0.x
webchick 2015-08-25 14:55:42 -07:00
parent 2b0de9c17a
commit 8f94d83897
6 changed files with 120 additions and 8 deletions

View File

@ -458,6 +458,14 @@ class Migration extends ConfigEntityBase implements MigrationInterface, Requirem
return \Drupal::keyValue('migrate_result')->get($this->id(), static::RESULT_INCOMPLETE);
}
/**
* {@inheritdoc}
*/
public function interruptMigration($result) {
$this->setStatus(MigrationInterface::STATUS_STOPPING);
$this->setMigrationResult($result);
}
/**
* {@inheritdoc}
*/

View File

@ -206,6 +206,15 @@ interface MigrationInterface extends ConfigEntityInterface {
*/
public function getMigrationResult();
/**
* Signal that the migration should be interrupted with the specified result
* code.
*
* @param int $result
* One of the MigrationInterface::RESULT_* constants.
*/
public function interruptMigration($result);
/**
* Get the normalized process pipeline configuration describing the process
* plugins.

View File

@ -298,10 +298,17 @@ class MigrateExecutable implements MigrateExecutableInterface {
unset($sourceValues, $destinationValues);
$this->sourceRowStatus = MigrateIdMapInterface::STATUS_IMPORTED;
// Check for memory exhaustion.
if (($return = $this->checkStatus()) != MigrationInterface::RESULT_COMPLETED) {
break;
}
// If anyone has requested we stop, return the requested result.
if ($this->migration->getStatus() == MigrationInterface::STATUS_STOPPING) {
$return = $this->migration->getMigrationResult();
break;
}
try {
$source->next();
}

View File

@ -95,8 +95,9 @@ class MigrateEventsTest extends KernelTestBase {
$event = $this->state->get('migrate_events_test.map_save_event', []);
$this->assertIdentical($event['event_name'], MigrateEvents::MAP_SAVE);
$this->assertIdentical($event['fields']['sourceid1'], 'dummy value');
$this->assertIdentical($event['fields']['destid1'], 'dummy value');
// Validating the last row processed.
$this->assertIdentical($event['fields']['sourceid1'], 'dummy value2');
$this->assertIdentical($event['fields']['destid1'], 'dummy value2');
$this->assertIdentical($event['fields']['source_row_status'], 0);
$event = $this->state->get('migrate_events_test.map_delete_event', []);
@ -105,13 +106,15 @@ class MigrateEventsTest extends KernelTestBase {
$event = $this->state->get('migrate_events_test.pre_row_save_event', []);
$this->assertIdentical($event['event_name'], MigrateEvents::PRE_ROW_SAVE);
$this->assertIdentical($event['migration']->id(), $migration->id());
$this->assertIdentical($event['row']->getSourceProperty('data'), 'dummy value');
// Validating the last row processed.
$this->assertIdentical($event['row']->getSourceProperty('data'), 'dummy value2');
$event = $this->state->get('migrate_events_test.post_row_save_event', []);
$this->assertIdentical($event['event_name'], MigrateEvents::POST_ROW_SAVE);
$this->assertIdentical($event['migration']->id(), $migration->id());
$this->assertIdentical($event['row']->getSourceProperty('data'), 'dummy value');
$this->assertIdentical($event['destination_id_values']['value'], 'dummy value');
// Validating the last row processed.
$this->assertIdentical($event['row']->getSourceProperty('data'), 'dummy value2');
$this->assertIdentical($event['destination_id_values']['value'], 'dummy value2');
// Generate a map delete event.
$migration->getIdMap()->delete(['data' => 'dummy value']);

View File

@ -0,0 +1,81 @@
<?php
/**
* @file
* Contains \Drupal\migrate\Tests\MigrateInterruptionTest.
*/
namespace Drupal\migrate\Tests;
use Drupal\migrate\Entity\Migration;
use Drupal\migrate\Event\MigratePostRowSaveEvent;
use Drupal\migrate\MigrateMessage;
use Drupal\migrate\Entity\MigrationInterface;
use Drupal\migrate\Event\MigrateEvents;
use Drupal\migrate\MigrateExecutable;
use Drupal\simpletest\KernelTestBase;
/**
* Tests interruptions triggered during migrations.
*
* @group migrate
*/
class MigrateInterruptionTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['migrate', 'migrate_events_test'];
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
\Drupal::service('event_dispatcher')->addListener(MigrateEvents::POST_ROW_SAVE,
array($this, 'postRowSaveEventRecorder'));
}
/**
* Tests migration interruptions.
*/
public function testMigrateEvents() {
// Run a simple little migration, which should trigger one of each event
// other than map_delete.
$config = [
'id' => 'sample_data',
'migration_tags' => ['Event test'],
'source' => ['plugin' => 'data'],
'process' => ['value' => 'data'],
'destination' => ['plugin' => 'dummy'],
'load' => ['plugin' => 'null'],
];
$migration = Migration::create($config);
/** @var MigrationInterface $migration */
$executable = new MigrateExecutable($migration, new MigrateMessage);
// When the import runs, the first row imported will trigger an interruption.
$result = $executable->import();
$this->assertEqual($result, MigrationInterface::RESULT_INCOMPLETE);
// The status should have been reset to IDLE.
$this->assertEqual($migration->getStatus(), MigrationInterface::STATUS_IDLE);
}
/**
* Reacts to post-row-save event.
*
* @param \Drupal\Migrate\Event\MigratePostRowSaveEvent $event
* The migration event.
* @param string $name
* The event name.
*/
public function postRowSaveEventRecorder(MigratePostRowSaveEvent $event, $name) {
$event->getMigration()->interruptMigration(MigrationInterface::RESULT_INCOMPLETE);
}
}

View File

@ -31,11 +31,15 @@ class DataSource extends SourcePluginBase {
* {@inheritdoc}
*/
public function initializeIterator() {
return new \ArrayIterator(array(array('data' => 'dummy value')));
return new \ArrayIterator([
['data' => 'dummy value'],
['data' => 'dummy value2'],
]);
}
public function __toString() {
return '';
return 'Sample data for testing';
}
/**
@ -50,7 +54,7 @@ class DataSource extends SourcePluginBase {
* {@inheritdoc}
*/
public function count() {
return 1;
return 2;
}
}