Newer
Older
catch
committed
<?php
Dries Buytaert
committed
namespace Drupal\Tests\migrate\Unit;
catch
committed
use Drupal\Core\Database\Driver\sqlite\Connection;
use Drupal\migrate\Plugin\MigrationInterface;
catch
committed
use Drupal\migrate\MigrateException;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
use Drupal\migrate\Row;
/**
* Tests the SQL ID map plugin.
catch
committed
*
* @group migrate
*/
class MigrateSqlIdMapTest extends MigrateTestCase {
/**
* The migration configuration, initialized to set the ID and destination IDs.
*
* @var array
*/
protected $migrationConfiguration = [
catch
committed
'id' => 'sql_idmap_test',
Dries Buytaert
committed
/**
* The source IDs.
*
* @var array
*/
protected $sourceIds = [
'source_id_property' => [
'type' => 'string',
],
];
Dries Buytaert
committed
/**
* The destination IDs.
*
* @var array
*/
protected $destinationIds = [
'destination_id_property' => [
'type' => 'string',
],
];
catch
committed
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* {@inheritdoc}
*/
Alex Pott
committed
protected function setUp() {
$this->database = $this->getDatabase([]);
}
catch
committed
/**
* Saves a single ID mapping row in the database.
catch
committed
*
* @param array $map
catch
committed
* The row to save.
*/
protected function saveMap(array $map) {
$table = 'migrate_map_sql_idmap_test';
$schema = $this->database->schema();
// If the table already exists, add any columns which are in the map array,
// but don't yet exist in the table. Yay, flexibility!
if ($schema->tableExists($table)) {
foreach (array_keys($map) as $field) {
if (!$schema->fieldExists($table, $field)) {
$schema->addField($table, $field, ['type' => 'text']);
}
}
}
else {
$schema->createTable($table, $this->createSchemaFromRow($map));
}
$this->database->insert($table)->fields($map)->execute();
}
/**
* Creates a test SQL ID map plugin.
catch
committed
*
Dries Buytaert
committed
* @return \Drupal\Tests\migrate\Unit\TestSqlIdMap
catch
committed
* A SQL ID map plugin test instance.
*/
protected function getIdMap() {
catch
committed
$migration = $this->getMigration();
Dries Buytaert
committed
$plugin = $this->getMock('Drupal\migrate\Plugin\MigrateSourceInterface');
$plugin
Dries Buytaert
committed
->method('getIds')
->willReturn($this->sourceIds);
$migration
Dries Buytaert
committed
->method('getSourcePlugin')
->willReturn($plugin);
$plugin = $this->getMock('Drupal\migrate\Plugin\MigrateDestinationInterface');
$plugin
Dries Buytaert
committed
->method('getIds')
->willReturn($this->destinationIds);
$migration
Dries Buytaert
committed
->method('getDestinationPlugin')
->willReturn($plugin);
Angie Byron
committed
$event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
Angie Byron
committed
$id_map = new TestSqlIdMap($this->database, [], 'sql', [], $migration, $event_dispatcher);
$migration
catch
committed
->method('getIdMap')
->willReturn($id_map);
catch
committed
return $id_map;
}
/**
* Sets defaults for SQL ID map plugin tests.
catch
committed
*
* @return array
* An associative array with the following keys:
* - source_row_status
* - rollback_action
* - hash
catch
committed
*/
protected function idMapDefaults() {
$defaults = [
catch
committed
'source_row_status' => MigrateIdMapInterface::STATUS_IMPORTED,
'rollback_action' => MigrateIdMapInterface::ROLLBACK_DELETE,
'hash' => '',
];
// By default, the PDO SQLite driver strongly prefers to return strings
// from SELECT queries. Even for columns that don't store strings. Even
// if the connection's STRINGIFY_FETCHES attribute is FALSE. This can cause
// assertSame() calls to fail, since 0 !== '0'. Casting these values to
// strings isn't the most elegant workaround, but it allows the assertions
// to pass properly.
if ($this->database->driver() == 'sqlite') {
$defaults['source_row_status'] = (string) $defaults['source_row_status'];
$defaults['rollback_action'] = (string) $defaults['rollback_action'];
}
return $defaults;
catch
committed
}
/**
* Tests the ID mapping method.
*
* Create two ID mappings and update the second to verify that:
* - saving new to empty tables work.
* - saving new to nonempty tables work.
* - updating work.
*/
public function testSaveIdMapping() {
$source = [
catch
committed
'source_id_property' => 'source_value',
];
$row = new Row($source, ['source_id_property' => []]);
catch
committed
$id_map = $this->getIdMap();
$id_map->saveIdMapping($row, ['destination_id_property' => 2]);
$expected_result = [
[
catch
committed
'sourceid1' => 'source_value',
Alex Pott
committed
'source_ids_hash' => $this->getIdMap()->getSourceIDsHash($source),
catch
committed
'destid1' => 2,
] + $this->idMapDefaults(),
];
$this->queryResultTest($this->getIdMapContents(), $expected_result);
$source = [
catch
committed
'source_id_property' => 'source_value_1',
];
$row = new Row($source, ['source_id_property' => []]);
$id_map->saveIdMapping($row, ['destination_id_property' => 3]);
$expected_result[] = [
catch
committed
'sourceid1' => 'source_value_1',
Alex Pott
committed
'source_ids_hash' => $this->getIdMap()->getSourceIDsHash($source),
catch
committed
'destid1' => 3,
] + $this->idMapDefaults();
$this->queryResultTest($this->getIdMapContents(), $expected_result);
$id_map->saveIdMapping($row, ['destination_id_property' => 4]);
catch
committed
$expected_result[1]['destid1'] = 4;
$this->queryResultTest($this->getIdMapContents(), $expected_result);
catch
committed
}
/**
* Tests the SQL ID map set message method.
*/
public function testSetMessage() {
$message = $this->getMock('Drupal\migrate\MigrateMessageInterface');
$id_map = $this->getIdMap();
$id_map->setMessage($message);
$this->assertAttributeEquals($message, 'message', $id_map);
}
/**
* Tests the clear messages method.
*/
public function testClearMessages() {
$message = 'Hello world.';
$expected_results = [0, 1, 2, 3];
catch
committed
$id_map = $this->getIdMap();
// Insert 4 message for later delete.
foreach ($expected_results as $key => $expected_result) {
Angie Byron
committed
$id_map->saveMessage(['source_id_property' => $key], $message);
catch
committed
}
// Truncate and check that 4 messages were deleted.
catch
committed
$this->assertSame($id_map->messageCount(), 4);
catch
committed
$id_map->clearMessages();
$count = $id_map->messageCount();
catch
committed
$this->assertSame($count, 0);
catch
committed
}
/**
* Tests the getRowsNeedingUpdate method for rows that need an update.
*/
public function testGetRowsNeedingUpdate() {
$id_map = $this->getIdMap();
$row_statuses = [
catch
committed
MigrateIdMapInterface::STATUS_IMPORTED,
MigrateIdMapInterface::STATUS_NEEDS_UPDATE,
MigrateIdMapInterface::STATUS_IGNORED,
MigrateIdMapInterface::STATUS_FAILED,
catch
committed
// Create a mapping row for each STATUS constant.
foreach ($row_statuses as $status) {
$source = ['source_id_property' => 'source_value_' . $status];
$row = new Row($source, ['source_id_property' => []]);
$destination = ['destination_id_property' => 'destination_value_' . $status];
catch
committed
$id_map->saveIdMapping($row, $destination, $status);
$expected_results[] = [
catch
committed
'sourceid1' => 'source_value_' . $status,
Alex Pott
committed
'source_ids_hash' => $this->getIdMap()->getSourceIDsHash($source),
catch
committed
'destid1' => 'destination_value_' . $status,
'source_row_status' => $status,
'rollback_action' => MigrateIdMapInterface::ROLLBACK_DELETE,
'hash' => '',
catch
committed
// Assert zero rows need an update.
if ($status == MigrateIdMapInterface::STATUS_IMPORTED) {
$rows_needing_update = $id_map->getRowsNeedingUpdate(1);
$this->assertCount(0, $rows_needing_update);
}
}
// Assert that test values exist.
$this->queryResultTest($this->getIdMapContents(), $expected_results);
catch
committed
// Assert a single row needs an update.
$row_needing_update = $id_map->getRowsNeedingUpdate(1);
$this->assertCount(1, $row_needing_update);
// Assert the row matches its original source.
$source_id = $expected_results[MigrateIdMapInterface::STATUS_NEEDS_UPDATE]['sourceid1'];
Angie Byron
committed
$test_row = $id_map->getRowBySource(['source_id_property' => $source_id]);
// $row_needing_update is an array of objects returned from the database,
// but $test_row is an array, so the cast is necessary.
$this->assertSame($test_row, (array) $row_needing_update[0]);
catch
committed
// Add additional row that needs an update.
$source = ['source_id_property' => 'source_value_multiple'];
$row = new Row($source, ['source_id_property' => []]);
$destination = ['destination_id_property' => 'destination_value_multiple'];
catch
committed
$id_map->saveIdMapping($row, $destination, MigrateIdMapInterface::STATUS_NEEDS_UPDATE);
// Assert multiple rows need an update.
$rows_needing_update = $id_map->getRowsNeedingUpdate(2);
$this->assertCount(2, $rows_needing_update);
}
/**
* Tests the SQL ID map message count method by counting and saving messages.
*/
public function testMessageCount() {
$message = 'Hello world.';
$expected_results = [0, 1, 2, 3];
catch
committed
$id_map = $this->getIdMap();
// Test count message multiple times starting from 0.
foreach ($expected_results as $key => $expected_result) {
$count = $id_map->messageCount();
catch
committed
$this->assertSame($expected_result, $count);
Angie Byron
committed
$id_map->saveMessage(['source_id_property' => $key], $message);
catch
committed
}
}
/**
* Tests the SQL ID map save message method.
*/
public function testMessageSave() {
$message = 'Hello world.';
Alex Pott
committed
$original_values = [
1 => ['message' => $message, 'level' => MigrationInterface::MESSAGE_ERROR],
2 => ['message' => $message, 'level' => MigrationInterface::MESSAGE_WARNING],
3 => ['message' => $message, 'level' => MigrationInterface::MESSAGE_NOTICE],
4 => ['message' => $message, 'level' => MigrationInterface::MESSAGE_INFORMATIONAL],
];
Alex Pott
committed
$expected_results = [
'7ad742edb7e866caa78ced1e4455d2e9cbd8adb2074e7c323d21b4e67732e755' => ['message' => $message, 'level' => MigrationInterface::MESSAGE_ERROR],
'2d3ec2b0c547e819346e6ae03f881fd9f5c978ff3cbe29dfb807d40735e53703' => ['message' => $message, 'level' => MigrationInterface::MESSAGE_WARNING],
'12a042f72cad9a2a8c7715df0c7695d762975f0687d87f5d480725dae1432a6f' => ['message' => $message, 'level' => MigrationInterface::MESSAGE_NOTICE],
'd9d1fd27a2447ace48f47a2e9ff649673f67b446d9381a7963c949fc083f8791' => ['message' => $message, 'level' => MigrationInterface::MESSAGE_INFORMATIONAL],
];
catch
committed
$id_map = $this->getIdMap();
Alex Pott
committed
foreach ($original_values as $key => $original_value) {
$id_map->saveMessage(['source_id_property' => $key], $message, $original_value['level']);
Angie Byron
committed
}
foreach ($id_map->getMessageIterator() as $message_row) {
Alex Pott
committed
$key = $message_row->source_ids_hash;
Angie Byron
committed
$this->assertEquals($expected_results[$key]['message'], $message_row->message);
$this->assertEquals($expected_results[$key]['level'], $message_row->level);
catch
committed
}
// Insert with default level.
$message_default = 'Hello world default.';
Angie Byron
committed
$id_map->saveMessage(['source_id_property' => 5], $message_default);
$messages = $id_map->getMessageIterator(['source_id_property' => 5]);
Angie Byron
committed
$count = 0;
foreach ($messages as $key => $message_row) {
$count = 1;
$this->assertEquals($message_default, $message_row->message);
$this->assertEquals(MigrationInterface::MESSAGE_ERROR, $message_row->level);
}
$this->assertEquals($count, 1);
// Retrieve messages with a specific level.
$messages = $id_map->getMessageIterator([], MigrationInterface::MESSAGE_WARNING);
$count = 0;
foreach ($messages as $key => $message_row) {
$count = 1;
$this->assertEquals(MigrationInterface::MESSAGE_WARNING, $message_row->level);
}
$this->assertEquals($count, 1);
catch
committed
}
/**
* Tests the getRowBySource method.
*/
public function testGetRowBySource() {
$this->getDatabase([]);
$row = [
catch
committed
'sourceid1' => 'source_id_value_1',
'sourceid2' => 'source_id_value_2',
Alex Pott
committed
'source_ids_hash' => $this->getIdMap()->getSourceIDsHash(['source_id_property' => 'source_id_value_1']),
catch
committed
'destid1' => 'destination_id_value_1',
] + $this->idMapDefaults();
$this->saveMap($row);
$row = [
catch
committed
'sourceid1' => 'source_id_value_3',
'sourceid2' => 'source_id_value_4',
Alex Pott
committed
'source_ids_hash' => $this->getIdMap()->getSourceIDsHash(['source_id_property' => 'source_id_value_3', 'sourceid2' => 'source_id_value_4']),
catch
committed
'destid1' => 'destination_id_value_2',
] + $this->idMapDefaults();
$this->saveMap($row);
Angie Byron
committed
$source_id_values = ['source_id_property' => $row['sourceid1'], 'sourceid2' => $row['sourceid2']];
$id_map = $this->getIdMap();
catch
committed
$result_row = $id_map->getRowBySource($source_id_values);
$this->assertSame($row, $result_row);
Angie Byron
committed
$source_id_values = ['source_id_property' => 'missing_value_1', 'sourceid2' => 'missing_value_2'];
catch
committed
$result_row = $id_map->getRowBySource($source_id_values);
$this->assertFalse($result_row);
}
/**
* Data provider for testLookupDestinationIdMapping().
catch
committed
*
* Scenarios to test (for both hits and misses) are:
* - Single-value source ID to single-value destination ID.
* - Multi-value source ID to multi-value destination ID.
* - Single-value source ID to multi-value destination ID.
* - Multi-value source ID to single-value destination ID.
*
* @return array
* An array of data values.
catch
committed
*/
public function lookupDestinationIdMappingDataProvider() {
return [
[1, 1],
[2, 2],
[1, 2],
[2, 1],
];
catch
committed
}
/**
* Performs destination ID test on source and destination fields.
*
* @param int $num_source_fields
* Number of source fields to test.
* @param int $num_destination_fields
* Number of destination fields to test.
*
* @dataProvider lookupDestinationIdMappingDataProvider
catch
committed
*/
public function testLookupDestinationIdMapping($num_source_fields, $num_destination_fields) {
catch
committed
// Adjust the migration configuration according to the number of source and
// destination fields.
$this->sourceIds = [];
$this->destinationIds = [];
$source_id_values = [];
$nonexistent_id_values = [];
catch
committed
$row = $this->idMapDefaults();
for ($i = 1; $i <= $num_source_fields; $i++) {
$row["sourceid$i"] = "source_id_value_$i";
$source_id_values[] = "source_id_value_$i";
$nonexistent_id_values[] = "nonexistent_source_id_value_$i";
$this->sourceIds["source_id_property_$i"] = [];
catch
committed
}
$expected_result = [];
catch
committed
for ($i = 1; $i <= $num_destination_fields; $i++) {
$row["destid$i"] = "destination_id_value_$i";
$expected_result[] = "destination_id_value_$i";
$this->destinationIds["destination_id_property_$i"] = [];
catch
committed
}
Alex Pott
committed
$row['source_ids_hash'] = $this->getIdMap()->getSourceIDsHash($source_id_values);
$this->saveMap($row);
$id_map = $this->getIdMap();
catch
committed
// Test for a valid hit.
$destination_id = $id_map->lookupDestinationId($source_id_values);
$this->assertSame($expected_result, $destination_id);
// Test for a miss.
$destination_id = $id_map->lookupDestinationId($nonexistent_id_values);
$this->assertSame(0, count($destination_id));
}
Alex Pott
committed
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
/**
* Setup a database with the given rows.
*
* @param array $source_keys
* The source keys for the ID map table.
* @param array $dest_keys
* The destination keys for the ID map table.
* @param array $rows
* An array of source and destination value arrays for the ID map table.
*
* @return \Drupal\Tests\migrate\Unit\TestSqlIdMap
* An ID map instance for testing.
*/
protected function setupRows($source_keys, $dest_keys, $rows) {
$this->database = $this->getDatabase([]);
$this->sourceIds = array_fill_keys($source_keys, []);
$this->destinationIds = array_fill_keys($dest_keys, []);
$db_keys = [];
foreach (array_keys($source_keys) as $i) {
$db_keys[] = 'sourceid' . ($i + 1);
}
foreach (array_keys($dest_keys) as $i) {
$db_keys[] = 'destid' . ($i + 1);
}
foreach ($rows as $row) {
$values = array_combine($db_keys, $row);
$source_values = array_slice($row, 0, count($source_keys));
$values['source_ids_hash'] = $this->getIdMap()->getSourceIDsHash($source_values);
$this->saveMap($values);
}
return $this->getIdMap();
}
/**
* Tests lookupDestinationIds().
*/
public function testLookupDestinationIds() {
// Simple map with one source and one destination ID.
$id_map = $this->setupRows(['nid'], ['nid'], [
[1, 101],
[2, 102],
[3, 103],
]);
// Lookup nothing, gives nothing.
$this->assertEquals([], $id_map->lookupDestinationIds([]));
// Lookup by complete non-associative list.
$this->assertEquals([[101]], $id_map->lookupDestinationIds([1]));
$this->assertEquals([[102]], $id_map->lookupDestinationIds([2]));
$this->assertEquals([], $id_map->lookupDestinationIds([99]));
// Lookup by complete associative list.
$this->assertEquals([[101]], $id_map->lookupDestinationIds(['nid' => 1]));
$this->assertEquals([[102]], $id_map->lookupDestinationIds(['nid' => 2]));
$this->assertEquals([], $id_map->lookupDestinationIds(['nid' => 99]));
// Map with multiple source and destination IDs.
$id_map = $this->setupRows(['nid', 'language'], ['nid', 'langcode'], [
[1, 'en', 101, 'en'],
[1, 'fr', 101, 'fr'],
[1, 'de', 101, 'de'],
[2, 'en', 102, 'en'],
]);
// Lookup nothing, gives nothing.
$this->assertEquals([], $id_map->lookupDestinationIds([]));
// Lookup by complete non-associative list.
$this->assertEquals([[101, 'en']], $id_map->lookupDestinationIds([1, 'en']));
$this->assertEquals([[101, 'fr']], $id_map->lookupDestinationIds([1, 'fr']));
$this->assertEquals([[102, 'en']], $id_map->lookupDestinationIds([2, 'en']));
$this->assertEquals([], $id_map->lookupDestinationIds([2, 'fr']));
$this->assertEquals([], $id_map->lookupDestinationIds([99, 'en']));
// Lookup by complete associative list.
$this->assertEquals([[101, 'en']], $id_map->lookupDestinationIds(['nid' => 1, 'language' => 'en']));
$this->assertEquals([[101, 'fr']], $id_map->lookupDestinationIds(['nid' => 1, 'language' => 'fr']));
$this->assertEquals([[102, 'en']], $id_map->lookupDestinationIds(['nid' => 2, 'language' => 'en']));
$this->assertEquals([], $id_map->lookupDestinationIds(['nid' => 2, 'language' => 'fr']));
$this->assertEquals([], $id_map->lookupDestinationIds(['nid' => 99, 'language' => 'en']));
// Lookup by partial non-associative list.
$this->assertEquals([[101, 'en'], [101, 'fr'], [101, 'de']], $id_map->lookupDestinationIds([1]));
$this->assertEquals([[102, 'en']], $id_map->lookupDestinationIds([2]));
$this->assertEquals([], $id_map->lookupDestinationIds([99]));
// Lookup by partial associative list.
$this->assertEquals([[101, 'en'], [101, 'fr'], [101, 'de']], $id_map->lookupDestinationIds(['nid' => 1]));
$this->assertEquals([[102, 'en']], $id_map->lookupDestinationIds(['nid' => 2]));
$this->assertEquals([], $id_map->lookupDestinationIds(['nid' => 99]));
// Out-of-order partial associative list.
$this->assertEquals([[101, 'en'], [102, 'en']], $id_map->lookupDestinationIds(['language' => 'en']));
$this->assertEquals([[101, 'fr']], $id_map->lookupDestinationIds(['language' => 'fr']));
$this->assertEquals([], $id_map->lookupDestinationIds(['language' => 'zh']));
// Error conditions.
try {
$id_map->lookupDestinationIds([1, 2, 3]);
$this->fail('Too many source IDs should throw');
}
catch (MigrateException $e) {
$this->assertEquals("Extra unknown items in source IDs", $e->getMessage());
}
try {
$id_map->lookupDestinationIds(['nid' => 1, 'aaa' => '2']);
$this->fail('Unknown source ID key should throw');
}
catch (MigrateException $e) {
$this->assertEquals("Extra unknown items in source IDs", $e->getMessage());
}
// Verify that we are looking up by source_id_hash when all source IDs are
// passed in.
$id_map->getDatabase()->update($id_map->mapTableName())
->condition('sourceid1', 1)
->condition('sourceid2', 'en')
->fields([TestSqlIdMap::SOURCE_IDS_HASH => uniqid()])
->execute();
$this->assertNotEquals([[101, 'en']], $id_map->lookupDestinationIds([1, 'en']));
}
catch
committed
/**
* Tests the getRowByDestination method.
*/
public function testGetRowByDestination() {
$row = [
catch
committed
'sourceid1' => 'source_id_value_1',
'sourceid2' => 'source_id_value_2',
Alex Pott
committed
'source_ids_hash' => $this->getIdMap()->getSourceIDsHash(['source_id_property' => 'source_id_value_1']),
catch
committed
'destid1' => 'destination_id_value_1',
] + $this->idMapDefaults();
$this->saveMap($row);
$row = [
catch
committed
'sourceid1' => 'source_id_value_3',
'sourceid2' => 'source_id_value_4',
Alex Pott
committed
'source_ids_hash' => $this->getIdMap()->getSourceIDsHash(['source_id_property' => 'source_id_value_3']),
catch
committed
'destid1' => 'destination_id_value_2',
] + $this->idMapDefaults();
$this->saveMap($row);
Angie Byron
committed
$dest_id_values = ['destination_id_property' => $row['destid1']];
$id_map = $this->getIdMap();
catch
committed
$result_row = $id_map->getRowByDestination($dest_id_values);
$this->assertSame($row, $result_row);
// This value does not exist.
Angie Byron
committed
$dest_id_values = ['destination_id_property' => 'invalid_destination_id_property'];
$id_map = $this->getIdMap();
catch
committed
$result_row = $id_map->getRowByDestination($dest_id_values);
$this->assertFalse($result_row);
}
/**
* Data provider for testLookupSourceIDMapping().
catch
committed
*
* Scenarios to test (for both hits and misses) are:
* - Single-value destination ID to single-value source ID.
* - Multi-value destination ID to multi-value source ID.
* - Single-value destination ID to multi-value source ID.
* - Multi-value destination ID to single-value source ID.
*
* @return array
* An array of data values.
catch
committed
*/
public function lookupSourceIDMappingDataProvider() {
return [
[1, 1],
[2, 2],
[1, 2],
[2, 1],
];
catch
committed
}
/**
* Performs the source ID test on source and destination fields.
*
* @param int $num_source_fields
* Number of source fields to test.
* @param int $num_destination_fields
* Number of destination fields to test.
*
* @dataProvider lookupSourceIDMappingDataProvider
catch
committed
*/
public function testLookupSourceIDMapping($num_source_fields, $num_destination_fields) {
catch
committed
// Adjust the migration configuration according to the number of source and
// destination fields.
$this->sourceIds = [];
$this->destinationIds = [];
catch
committed
$row = $this->idMapDefaults();
Alex Pott
committed
$source_ids_values = [];
$expected_result = [];
catch
committed
for ($i = 1; $i <= $num_source_fields; $i++) {
$row["sourceid$i"] = "source_id_value_$i";
Alex Pott
committed
$source_ids_values = [$row["sourceid$i"]];
Angie Byron
committed
$expected_result["source_id_property_$i"] = "source_id_value_$i";
$this->sourceIds["source_id_property_$i"] = [];
catch
committed
}
$destination_id_values = [];
$nonexistent_id_values = [];
catch
committed
for ($i = 1; $i <= $num_destination_fields; $i++) {
$row["destid$i"] = "destination_id_value_$i";
Angie Byron
committed
$destination_id_values["destination_id_property_$i"] = "destination_id_value_$i";
$nonexistent_id_values["destination_id_property_$i"] = "nonexistent_destination_id_value_$i";
$this->destinationIds["destination_id_property_$i"] = [];
catch
committed
}
Alex Pott
committed
$row['source_ids_hash'] = $this->getIdMap()->getSourceIDsHash($source_ids_values);
$this->saveMap($row);
$id_map = $this->getIdMap();
catch
committed
// Test for a valid hit.
$source_id = $id_map->lookupSourceID($destination_id_values);
$this->assertSame($expected_result, $source_id);
// Test for a miss.
$source_id = $id_map->lookupSourceID($nonexistent_id_values);
$this->assertSame(0, count($source_id));
}
Alex Pott
committed
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
/**
* Tests currentDestination() and currentSource().
*/
public function testCurrentDestinationAndSource() {
// Simple map with one source and one destination ID.
$id_map = $this->setupRows(['nid'], ['nid'], [
[1, 101],
[2, 102],
[3, 103],
// Mock a failed row by setting the destination ID to NULL.
[4, NULL],
]);
// The rows are ordered by destination ID so the failed row should be first.
$id_map->rewind();
$this->assertEquals([], $id_map->currentDestination());
$this->assertEquals(['nid' => 4], $id_map->currentSource());
$id_map->next();
$this->assertEquals(['nid' => 101], $id_map->currentDestination());
$this->assertEquals(['nid' => 1], $id_map->currentSource());
$id_map->next();
$this->assertEquals(['nid' => 102], $id_map->currentDestination());
$this->assertEquals(['nid' => 2], $id_map->currentSource());
$id_map->next();
$this->assertEquals(['nid' => 103], $id_map->currentDestination());
$this->assertEquals(['nid' => 3], $id_map->currentSource());
$id_map->next();
}
catch
committed
/**
* Tests the imported count method.
*
* Scenarios to test for:
* - No imports.
* - One import.
* - Multiple imports.
*/
public function testImportedCount() {
$id_map = $this->getIdMap();
// Add a single failed row and assert zero imported rows.
$source = ['source_id_property' => 'source_value_failed'];
$row = new Row($source, ['source_id_property' => []]);
$destination = ['destination_id_property' => 'destination_value_failed'];
catch
committed
$id_map->saveIdMapping($row, $destination, MigrateIdMapInterface::STATUS_FAILED);
catch
committed
$this->assertSame(0, $id_map->importedCount());
catch
committed
// Add an imported row and assert single count.
$source = ['source_id_property' => 'source_value_imported'];
$row = new Row($source, ['source_id_property' => []]);
$destination = ['destination_id_property' => 'destination_value_imported'];
catch
committed
$id_map->saveIdMapping($row, $destination, MigrateIdMapInterface::STATUS_IMPORTED);
catch
committed
$this->assertSame(1, $id_map->importedCount());
catch
committed
// Add a row needing update and assert multiple imported rows.
$source = ['source_id_property' => 'source_value_update'];
$row = new Row($source, ['source_id_property' => []]);
$destination = ['destination_id_property' => 'destination_value_update'];
catch
committed
$id_map->saveIdMapping($row, $destination, MigrateIdMapInterface::STATUS_NEEDS_UPDATE);
catch
committed
$this->assertSame(2, $id_map->importedCount());
catch
committed
}
/**
* Tests the number of processed source rows.
*
* Scenarios to test for:
* - No processed rows.
* - One processed row.
* - Multiple processed rows.
*/
public function testProcessedCount() {
$id_map = $this->getIdMap();
// Assert zero rows have been processed before adding rows.
catch
committed
$this->assertSame(0, $id_map->processedCount());
$row_statuses = [
catch
committed
MigrateIdMapInterface::STATUS_IMPORTED,
MigrateIdMapInterface::STATUS_NEEDS_UPDATE,
MigrateIdMapInterface::STATUS_IGNORED,
MigrateIdMapInterface::STATUS_FAILED,
catch
committed
// Create a mapping row for each STATUS constant.
foreach ($row_statuses as $status) {
$source = ['source_id_property' => 'source_value_' . $status];
$row = new Row($source, ['source_id_property' => []]);
$destination = ['destination_id_property' => 'destination_value_' . $status];
catch
committed
$id_map->saveIdMapping($row, $destination, $status);
if ($status == MigrateIdMapInterface::STATUS_IMPORTED) {
// Assert a single row has been processed.
catch
committed
$this->assertSame(1, $id_map->processedCount());
catch
committed
}
}
// Assert multiple rows have been processed.
catch
committed
$this->assertSame(count($row_statuses), $id_map->processedCount());
catch
committed
}
/**
* Data provider for testUpdateCount().
catch
committed
*
* Scenarios to test for:
* - No updates.
* - One update.
* - Multiple updates.
*
* @return array
* An array of data values.
catch
committed
*/
public function updateCountDataProvider() {
return [
[0],
[1],
[3],
];
catch
committed
}
/**
* Performs the update count test with a given number of update rows.
*
* @param int $num_update_rows
* The number of update rows to test.
*
* @dataProvider updateCountDataProvider
catch
committed
*/
public function testUpdateCount($num_update_rows) {
catch
committed
for ($i = 0; $i < 5; $i++) {
$row = $this->idMapDefaults();
$row['sourceid1'] = "source_id_value_$i";
Alex Pott
committed
$row['source_ids_hash'] = $this->getIdMap()->getSourceIDsHash(['source_id_property' => $row['sourceid1']]);
catch
committed
$row['destid1'] = "destination_id_value_$i";
$row['source_row_status'] = MigrateIdMapInterface::STATUS_IMPORTED;
$this->saveMap($row);
catch
committed
}
for (; $i < 5 + $num_update_rows; $i++) {
$row = $this->idMapDefaults();
$row['sourceid1'] = "source_id_value_$i";
Alex Pott
committed
$row['source_ids_hash'] = $this->getIdMap()->getSourceIDsHash(['source_id_property' => $row['sourceid1']]);
catch
committed
$row['destid1'] = "destination_id_value_$i";
$row['source_row_status'] = MigrateIdMapInterface::STATUS_NEEDS_UPDATE;
$this->saveMap($row);
catch
committed
}
$id_map = $this->getIdMap();
catch
committed
$this->assertSame($num_update_rows, $id_map->updateCount());
catch
committed
}
/**
* Data provider for testErrorCount().
catch
committed
*
* Scenarios to test for:
* - No errors.
* - One error.
* - Multiple errors.
*
* @return array
* An array of data values.
catch
committed
*/
public function errorCountDataProvider() {
return [
[0],
[1],
[3],
];
catch
committed
}
/**
* Performs error count test with a given number of error rows.
*
* @param int $num_error_rows
* Number of error rows to test.
*
* @dataProvider errorCountDataProvider
catch
committed
*/
public function testErrorCount($num_error_rows) {
catch
committed
for ($i = 0; $i < 5; $i++) {
$row = $this->idMapDefaults();
$row['sourceid1'] = "source_id_value_$i";
Alex Pott
committed
$row['source_ids_hash'] = $this->getIdMap()->getSourceIDsHash(['source_id_property' => $row['sourceid1']]);
catch
committed
$row['destid1'] = "destination_id_value_$i";
$row['source_row_status'] = MigrateIdMapInterface::STATUS_IMPORTED;
$this->saveMap($row);
catch
committed
}
for (; $i < 5 + $num_error_rows; $i++) {
$row = $this->idMapDefaults();
$row['sourceid1'] = "source_id_value_$i";
Alex Pott
committed
$row['source_ids_hash'] = $this->getIdMap()->getSourceIDsHash(['source_id_property' => $row['sourceid1']]);
catch
committed
$row['destid1'] = "destination_id_value_$i";
$row['source_row_status'] = MigrateIdMapInterface::STATUS_FAILED;
$this->saveMap($row);
catch
committed
}
catch
committed
$this->assertSame($num_error_rows, $this->getIdMap()->errorCount());
catch
committed
}
/**
* Tests setting a row source_row_status to STATUS_NEEDS_UPDATE.
*/
public function testSetUpdate() {
$id_map = $this->getIdMap();
$row_statuses = [
catch
committed
MigrateIdMapInterface::STATUS_IMPORTED,
MigrateIdMapInterface::STATUS_NEEDS_UPDATE,
MigrateIdMapInterface::STATUS_IGNORED,
MigrateIdMapInterface::STATUS_FAILED,
catch
committed
// Create a mapping row for each STATUS constant.
foreach ($row_statuses as $status) {
$source = ['source_id_property' => 'source_value_' . $status];
$row = new Row($source, ['source_id_property' => []]);
$destination = ['destination_id_property' => 'destination_value_' . $status];
catch
committed
$id_map->saveIdMapping($row, $destination, $status);
$expected_results[] = [
catch
committed
'sourceid1' => 'source_value_' . $status,
Alex Pott
committed
'source_ids_hash' => $this->getIdMap()->getSourceIDsHash($source),
catch
committed
'destid1' => 'destination_value_' . $status,
'source_row_status' => $status,
'rollback_action' => MigrateIdMapInterface::ROLLBACK_DELETE,
'hash' => '',
catch
committed
}
// Assert that test values exist.
$this->queryResultTest($this->getIdMapContents(), $expected_results);
catch
committed
// Mark each row as STATUS_NEEDS_UPDATE.
foreach ($row_statuses as $status) {
Angie Byron
committed
$id_map->setUpdate(['source_id_property' => 'source_value_' . $status]);
catch
committed
}
// Update expected results.
foreach ($expected_results as $key => $value) {
$expected_results[$key]['source_row_status'] = MigrateIdMapInterface::STATUS_NEEDS_UPDATE;
}
// Assert that updated expected values match.
$this->queryResultTest($this->getIdMapContents(), $expected_results);
catch
committed
// Assert an exception is thrown when source identifiers are not provided.
try {
$id_map->setUpdate([]);
catch
committed
$this->assertFalse(FALSE, 'MigrateException not thrown, when source identifiers were provided to update.');
}
catch (MigrateException $e) {
$this->assertTrue(TRUE, "MigrateException thrown, when source identifiers were not provided to update.");
}
}
/**
* Tests prepareUpdate().
*/
public function testPrepareUpdate() {
$id_map = $this->getIdMap();
$row_statuses = [
catch
committed
MigrateIdMapInterface::STATUS_IMPORTED,
MigrateIdMapInterface::STATUS_NEEDS_UPDATE,
MigrateIdMapInterface::STATUS_IGNORED,
MigrateIdMapInterface::STATUS_FAILED,
catch
committed
// Create a mapping row for each STATUS constant.
foreach ($row_statuses as $status) {
$source = ['source_id_property' => 'source_value_' . $status];
$row = new Row($source, ['source_id_property' => []]);
$destination = ['destination_id_property' => 'destination_value_' . $status];
catch
committed
$id_map->saveIdMapping($row, $destination, $status);
$expected_results[] = [
catch
committed
'sourceid1' => 'source_value_' . $status,
'destid1' => 'destination_value_' . $status,
'source_row_status' => $status,
'rollback_action' => MigrateIdMapInterface::ROLLBACK_DELETE,
'hash' => '',
catch
committed
}
// Assert that test values exist.
$this->queryResultTest($this->getIdMapContents(), $expected_results);
catch
committed
// Mark all rows as STATUS_NEEDS_UPDATE.
$id_map->prepareUpdate();
// Update expected results.
foreach ($expected_results as $key => $value) {
$expected_results[$key]['source_row_status'] = MigrateIdMapInterface::STATUS_NEEDS_UPDATE;
}
// Assert that updated expected values match.
$this->queryResultTest($this->getIdMapContents(), $expected_results);
catch
committed
}
/**
* Tests the destroy method.
*
* Scenarios to test for:
* - No errors.
* - One error.
* - Multiple errors.
*/
public function testDestroy() {
$id_map = $this->getIdMap();
catch
committed
// Initialize the ID map.
Dries Buytaert
committed
$id_map->getDatabase();
$map_table_name = $id_map->mapTableName();
$message_table_name = $id_map->messageTableName();
$row = new Row(['source_id_property' => 'source_value'], ['source_id_property' => []]);
$id_map->saveIdMapping($row, ['destination_id_property' => 2]);
Angie Byron
committed
$id_map->saveMessage(['source_id_property' => 'source_value'], 'A message');
catch
committed
$this->assertTrue($this->database->schema()->tableExists($map_table_name),
"$map_table_name exists");
$this->assertTrue($this->database->schema()->tableExists($message_table_name),
"$message_table_name exists");
$id_map->destroy();
$this->assertFalse($this->database->schema()->tableExists($map_table_name),
"$map_table_name does not exist");
$this->assertFalse($this->database->schema()->tableExists($message_table_name),
"$message_table_name does not exist");
}
/**
* Tests the getQualifiedMapTable method with a prefixed database.
*/
public function testGetQualifiedMapTablePrefix() {
$connection_options = [
'database' => ':memory:',
'prefix' => 'prefix',
];
$pdo = Connection::open($connection_options);
$this->database = new Connection($pdo, $connection_options);
$qualified_map_table = $this->getIdMap()->getQualifiedMapTableName();
// The SQLite driver is a special flower. It will prefix tables with
// PREFIX.TABLE, instead of the standard PREFIXTABLE.
// @see \Drupal\Core\Database\Driver\sqlite\Connection::__construct()
$this->assertEquals('prefix.migrate_map_sql_idmap_test', $qualified_map_table);
catch
committed
}
/**
* Tests all the iterator methods in one swing.
*
* The iterator methods are:
* - Sql::rewind()
* - Sql::next()
* - Sql::valid()
* - Sql::key()
* - Sql::current()
*/
public function testIterators() {
for ($i = 0; $i < 3; $i++) {
$row = $this->idMapDefaults();
$row['sourceid1'] = "source_id_value_$i";
Alex Pott
committed
$row['source_ids_hash'] = $this->getIdMap()->getSourceIDsHash(['source_id_property' => $row['sourceid1']]);
catch
committed
$row['destid1'] = "destination_id_value_$i";
$row['source_row_status'] = MigrateIdMapInterface::STATUS_IMPORTED;
$expected_results[serialize(['sourceid1' => $row['sourceid1']])] = ['destid1' => $row['destid1']];
$this->saveMap($row);
catch
committed
}
$this->assertSame(iterator_to_array($this->getIdMap()), $expected_results);
}
/**
* Retrieves the contents of an ID map.
*
* @return array
* The contents of an ID map.
*/