Further Drupal 8.6.4 changes. Some core files were not committed before a commit...
[yaffs-website] / web / core / modules / migrate_drupal_ui / tests / src / Functional / MigrateUpgradeTestBase.php
1 <?php
2
3 namespace Drupal\Tests\migrate_drupal_ui\Functional;
4
5 use Drupal\Core\Database\Database;
6 use Drupal\migrate\Plugin\MigrateIdMapInterface;
7 use Drupal\migrate_drupal\MigrationConfigurationTrait;
8 use Drupal\Tests\BrowserTestBase;
9 use Drupal\Tests\migrate_drupal\Traits\CreateTestContentEntitiesTrait;
10 use Drupal\Tests\WebAssert;
11
12 /**
13  * Provides a base class for testing migration upgrades in the UI.
14  */
15 abstract class MigrateUpgradeTestBase extends BrowserTestBase {
16
17   use MigrationConfigurationTrait;
18   use CreateTestContentEntitiesTrait;
19
20   /**
21    * Use the Standard profile to test help implementations of many core modules.
22    *
23    * @var string
24    */
25   protected $profile = 'standard';
26
27   /**
28    * The source database connection.
29    *
30    * @var \Drupal\Core\Database\Connection
31    */
32   protected $sourceDatabase;
33
34   /**
35    * {@inheritdoc}
36    */
37   protected function setUp() {
38     parent::setUp();
39     $this->createMigrationConnection();
40     $this->sourceDatabase = Database::getConnection('default', 'migrate_drupal_ui');
41
42     // Log in as user 1. Migrations in the UI can only be performed as user 1.
43     $this->drupalLogin($this->rootUser);
44   }
45
46   /**
47    * Loads a database fixture into the source database connection.
48    *
49    * @param string $path
50    *   Path to the dump file.
51    */
52   protected function loadFixture($path) {
53     $default_db = Database::getConnection()->getKey();
54     Database::setActiveConnection($this->sourceDatabase->getKey());
55
56     if (substr($path, -3) == '.gz') {
57       $path = 'compress.zlib://' . $path;
58     }
59     require $path;
60
61     Database::setActiveConnection($default_db);
62   }
63
64   /**
65    * Changes the database connection to the prefixed one.
66    *
67    * @todo Remove when we don't use global. https://www.drupal.org/node/2552791
68    */
69   protected function createMigrationConnection() {
70     $connection_info = Database::getConnectionInfo('default')['default'];
71     if ($connection_info['driver'] === 'sqlite') {
72       // Create database file in the test site's public file directory so that
73       // \Drupal\simpletest\TestBase::restoreEnvironment() will delete this once
74       // the test is complete.
75       $file = $this->publicFilesDirectory . '/' . $this->testId . '-migrate.db.sqlite';
76       touch($file);
77       $connection_info['database'] = $file;
78       $connection_info['prefix'] = '';
79     }
80     else {
81       $prefix = is_array($connection_info['prefix']) ? $connection_info['prefix']['default'] : $connection_info['prefix'];
82       // Simpletest uses fixed length prefixes. Create a new prefix for the
83       // source database. Adding to the end of the prefix ensures that
84       // \Drupal\simpletest\TestBase::restoreEnvironment() will remove the
85       // additional tables.
86       $connection_info['prefix'] = $prefix . '0';
87     }
88
89     Database::addConnectionInfo('migrate_drupal_ui', 'default', $connection_info);
90   }
91
92   /**
93    * {@inheritdoc}
94    */
95   protected function tearDown() {
96     Database::removeConnection('migrate_drupal_ui');
97     parent::tearDown();
98   }
99
100   /**
101    * Tests the displayed upgrade paths.
102    *
103    * @param \Drupal\Tests\WebAssert $session
104    *   The web-assert session.
105    * @param array $available_paths
106    *   An array of modules that will be upgraded.
107    * @param array $missing_paths
108    *   An array of modules that will not be upgraded.
109    */
110   protected function assertUpgradePaths(WebAssert $session, array $available_paths, array $missing_paths) {
111     // Test the available migration paths.
112     foreach ($available_paths as $available) {
113       $session->elementExists('xpath', "//span[contains(@class, 'checked') and text() = '$available']");
114       $session->elementNotExists('xpath', "//span[contains(@class, 'error') and text() = '$available']");
115     }
116
117     // Test the missing migration paths.
118     foreach ($missing_paths as $missing) {
119       $session->elementExists('xpath', "//span[contains(@class, 'error') and text() = '$missing']");
120       $session->elementNotExists('xpath', "//span[contains(@class, 'checked') and text() = '$missing']");
121     }
122
123     // Test the total count of missing and available paths.
124     $session->elementsCount('xpath', "//span[contains(@class, 'upgrade-analysis-report__status-icon--error')]", count($missing_paths));
125     $session->elementsCount('xpath', "//span[contains(@class, 'upgrade-analysis-report__status-icon--checked')]", count($available_paths));
126   }
127
128   /**
129    * Gets the source base path for the concrete test.
130    *
131    * @return string
132    *   The source base path.
133    */
134   abstract protected function getSourceBasePath();
135
136   /**
137    * Gets the expected number of entities per entity type after migration.
138    *
139    * @return int[]
140    *   An array of expected counts keyed by entity type ID.
141    */
142   abstract protected function getEntityCounts();
143
144   /**
145    * Gets the available upgrade paths.
146    *
147    * @return string[]
148    *   An array of available upgrade paths.
149    */
150   abstract protected function getAvailablePaths();
151
152   /**
153    * Gets the missing upgrade paths.
154    *
155    * @return string[]
156    *   An array of missing upgrade paths.
157    */
158   abstract protected function getMissingPaths();
159
160   /**
161    * Gets expected number of entities per entity after incremental migration.
162    *
163    * @return int[]
164    *   An array of expected counts keyed by entity type ID.
165    */
166   abstract protected function getEntityCountsIncremental();
167
168   /**
169    * Helper method to assert the text on the 'Upgrade analysis report' page.
170    *
171    * @param \Drupal\Tests\WebAssert $session
172    *   The current session.
173    * @param array $all_available
174    *   Array of modules that will be upgraded.
175    * @param array $all_missing
176    *   Array of modules that will not be upgraded.
177    */
178   protected function assertReviewPage(WebAssert $session, array $all_available, array $all_missing) {
179     $this->assertText('What will be upgraded?');
180
181     // Ensure there are no errors about the missing modules from the test module.
182     $session->pageTextNotContains(t('Source module not found for migration_provider_no_annotation.'));
183     $session->pageTextNotContains(t('Source module not found for migration_provider_test.'));
184     $session->pageTextNotContains(t('Destination module not found for migration_provider_test'));
185     // Ensure there are no errors about any other missing migration providers.
186     $session->pageTextNotContains(t('module not found'));
187
188     // Test the available migration paths.
189     foreach ($all_available as $available) {
190       $session->elementExists('xpath', "//span[contains(@class, 'checked') and text() = '$available']");
191       $session->elementNotExists('xpath', "//span[contains(@class, 'error') and text() = '$available']");
192     }
193
194     // Test the missing migration paths.
195     foreach ($all_missing as $missing) {
196       $session->elementExists('xpath', "//span[contains(@class, 'error') and text() = '$missing']");
197       $session->elementNotExists('xpath', "//span[contains(@class, 'checked') and text() = '$missing']");
198     }
199   }
200
201   /**
202    * Helper method that asserts text on the ID conflict form.
203    *
204    * @param \Drupal\Tests\WebAssert $session
205    *   The current session.
206    * @param $session
207    *   The current session.
208    */
209   protected function assertIdConflict(WebAssert $session) {
210     $session->pageTextContains('WARNING: Content may be overwritten on your new site.');
211     $session->pageTextContains('There is conflicting content of these types:');
212     $session->pageTextContains('custom blocks');
213     $session->pageTextContains('custom menu links');
214     $session->pageTextContains('files');
215     $session->pageTextContains('taxonomy terms');
216     $session->pageTextContains('users');
217     $session->pageTextContains('comments');
218     $session->pageTextContains('content item revisions');
219     $session->pageTextContains('content items');
220     $session->pageTextContains('There is translated content of these types:');
221   }
222
223   /**
224    * Checks that migrations have been performed successfully.
225    *
226    * @param array $expected_counts
227    *   The expected counts of each entity type.
228    * @param int $version
229    *   The Drupal version.
230    */
231   protected function assertMigrationResults(array $expected_counts, $version) {
232     // Have to reset all the statics after migration to ensure entities are
233     // loadable.
234     $this->resetAll();
235     foreach (array_keys(\Drupal::entityTypeManager()->getDefinitions()) as $entity_type) {
236       $real_count = (int) \Drupal::entityQuery($entity_type)->count()->execute();
237       $expected_count = isset($expected_counts[$entity_type]) ? $expected_counts[$entity_type] : 0;
238       $this->assertSame($expected_count, $real_count, "Found $real_count $entity_type entities, expected $expected_count.");
239     }
240
241     $plugin_manager = \Drupal::service('plugin.manager.migration');
242     /** @var \Drupal\migrate\Plugin\Migration[] $all_migrations */
243     $all_migrations = $plugin_manager->createInstancesByTag('Drupal ' . $version);
244     foreach ($all_migrations as $migration) {
245       $id_map = $migration->getIdMap();
246       foreach ($id_map as $source_id => $map) {
247         // Convert $source_id into a keyless array so that
248         // \Drupal\migrate\Plugin\migrate\id_map\Sql::getSourceHash() works as
249         // expected.
250         $source_id_values = array_values(unserialize($source_id));
251         $row = $id_map->getRowBySource($source_id_values);
252         $destination = serialize($id_map->currentDestination());
253         $message = "Migration of $source_id to $destination as part of the {$migration->id()} migration. The source row status is " . $row['source_row_status'];
254         // A completed migration should have maps with
255         // MigrateIdMapInterface::STATUS_IGNORED or
256         // MigrateIdMapInterface::STATUS_IMPORTED.
257         $this->assertNotSame(MigrateIdMapInterface::STATUS_FAILED, $row['source_row_status'], $message);
258         $this->assertNotSame(MigrateIdMapInterface::STATUS_NEEDS_UPDATE, $row['source_row_status'], $message);
259       }
260     }
261   }
262
263 }