Commit 5e619253 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #2710133 by vasi, mikeryan: Follow up to #2561697 - Migration should not...

Issue #2710133 by vasi, mikeryan: Follow up to #2561697 - Migration should not choke when the content_node_field table isn't available
parent ac4b5c7f
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -157,6 +157,7 @@ public function buildDependencyMigration(array $migrations, array $dynamic_ids)
    // current migration.
    $dependency_graph = [];
    $required_dependency_graph = [];
    $have_optional = FALSE;
    foreach ($migrations as $migration) {
      /** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
      $id = $migration->id();
@@ -172,14 +173,15 @@ public function buildDependencyMigration(array $migrations, array $dynamic_ids)
          $this->addDependency($dependency_graph, $id, $dependency, $dynamic_ids);
        }
      }
      if (isset($migration_dependencies['optional'])) {
      if (!empty($migration_dependencies['optional'])) {
        foreach ($migration_dependencies['optional'] as $dependency) {
          $this->addDependency($dependency_graph, $id, $dependency, $dynamic_ids);
        }
        $have_optional = TRUE;
      }
    }
    $dependency_graph = (new Graph($dependency_graph))->searchAndSort();
    if (!empty($migration_dependencies['optional'])) {
    if ($have_optional) {
      $required_dependency_graph = (new Graph($required_dependency_graph))->searchAndSort();
    }
    else {
+220 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Tests\migrate\Unit;

use Drupal\migrate\Plugin\Migration;
use Drupal\migrate\Plugin\MigrationPluginManager;
use Drupal\Tests\UnitTestCase;

/**
 * @coversDefaultClass \Drupal\migrate\Plugin\MigrationPluginManager
 * @group migrate
 */
class MigrationPluginManagerTest extends UnitTestCase {

  /**
   * A plugin manager.
   *
   * @param \Drupal\migrate\Plugin\MigrationPluginManager $pluginManager
   */
  protected $pluginManager;

  /**
   * {@inheritdoc}
   */
  public function setUp() {
    parent::setUp();

    // Get a plugin manager for testing.
    $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
    $cache_backend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
    $language_manager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
    $this->pluginManager = new MigrationPluginManager($module_handler, $cache_backend, $language_manager);
  }

  /**
   * Tests building dependencies for multiple migrations.
   *
   * @dataProvider dependencyProvider
   */
  public function testDependencyBuilding($migrations_data, $result_ids) {
    $migrations = [];
    foreach ($migrations_data as $migration_id => $migration_data) {
      $migrations[$migration_id] = new TestMigration($migration_id, $migration_data['dependencies']);
    }

    $ordered_migrations = $this->pluginManager->buildDependencyMigration($migrations, []);

    // Verify results.
    $this->assertEquals($result_ids, array_keys($ordered_migrations));
    foreach ($migrations_data as $migration_id => $migration_data) {
      $migration = $migrations[$migration_id];

      $requirements = $migration_data['result_requirements'];
      if (empty($requirements)) {
        $this->assertEquals([], $migration->set);
      }
      else {
        $requirements = array_combine($requirements, $requirements);

        $this->assertEquals(1, count($migration->set));
        list($set_prop, $set_requirements) = reset($migration->set);
        $this->assertEquals('requirements', $set_prop);
        $this->assertEquals($requirements, $set_requirements);
      }
    }
  }

  /**
   * Provide dependency data for testing.
   */
  public function dependencyProvider() {
    return [
      // Just one migration, with no dependencies.
      [
        [
          'm1' => [
            'dependencies' => [],
            'result_requirements' => [],
          ],
        ],
        ['m1'],
      ],

      // Just one migration, with required dependencies.
      [
        [
          'm1' => [
            'dependencies' => [
              'required' => ['required1', 'required2'],
            ],
            'result_requirements' => ['required1', 'required2'],
          ],
        ],
        ['m1'],
      ],

      // Just one migration, with optional dependencies.
      [
        [
          'm1' => [
            'dependencies' => [
              'optional' => ['optional1'],
            ],
            'result_requirements' => [],
          ],
        ],
        ['m1'],
      ],

      // Multiple migrations.
      [
        [
          'm1' => [
            'dependencies' => [
              'required' => ['required1', 'required2'],
            ],
            'result_requirements' => ['required1', 'required2'],
          ],
          'm2' => [
            'dependencies' => [
              'optional' => ['optional1'],
            ],
            'result_requirements' => [],
          ],
        ],
        ['m1', 'm2'],
      ],

      // Multiple migrations, reordered due to optional requirement.
      [
        [
          'm1' => [
            'dependencies' => [
              'optional' => ['m2'],
            ],
            'result_requirements' => [],
          ],
          'm2' => [
            'dependencies' => [
              'optional' => ['optional1'],
            ],
            'result_requirements' => [],
          ],
        ],
        ['m2', 'm1'],
      ],

      // Ensure that optional requirements aren't turned into required ones,
      // if the last migration has no optional deps.
      [
        [
          'm1' => [
            'dependencies' => [
              'optional' => ['m2'],
            ],
            'result_requirements' => [],
          ],
          'm2' => [
            'dependencies' => [],
            'result_requirements' => [],
          ],
        ],
        ['m2', 'm1'],
      ],
    ];
  }

}

/**
 * A mock migration plugin.
 *
 * Why are we using a custom class here?
 *
 * 1. The function buildDependencyMigration() calls $migration->set(), which
 * is not actually in MigrationInterface.
 *
 * 2. The function buildDependencyMigration() calls array_multisort on an
 * array with mocks in it. PHPUnit mocks are really complex, and if PHP tries
 * to compare them it will die with "Nesting level too deep".
 */
class TestMigration extends Migration {
  /**
   * The values passed into set().
   *
   * @var array $set
   */
  public $set = [];

  /**
   * TestMigration constructor.
   */
  public function __construct($id, $dependencies) {
    // Intentionally ignore parent constructor.
    $this->id = $id;
    $this->dependencies = $dependencies;
  }

  /**
   * {@inheritdoc}
   */
  public function id() {
    return $this->id;
  }

  /**
   * {@inheritdoc}
   */
  public function getMigrationDependencies() {
    return $this->dependencies;
  }

  /**
   * {@inheritdoc}
   */
  public function set($prop, $value) {
    $this->set[] = func_get_args();
  }

}