Upgraded drupal core with security updates
[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
10 /**
11  * Provides a base class for testing migration upgrades in the UI.
12  */
13 abstract class MigrateUpgradeTestBase extends BrowserTestBase {
14   use MigrationConfigurationTrait;
15
16   /**
17    * Use the Standard profile to test help implementations of many core modules.
18    */
19   protected $profile = 'standard';
20
21   /**
22    * The source database connection.
23    *
24    * @var \Drupal\Core\Database\Connection
25    */
26   protected $sourceDatabase;
27
28   /**
29    * Modules to enable.
30    *
31    * @var array
32    */
33   public static $modules = [
34     'language',
35     'content_translation',
36     'migrate_drupal_ui',
37     'telephone',
38     'aggregator',
39     'book',
40     'forum',
41     'statistics',
42   ];
43
44   /**
45    * {@inheritdoc}
46    */
47   protected function setUp() {
48     parent::setUp();
49     $this->createMigrationConnection();
50     $this->sourceDatabase = Database::getConnection('default', 'migrate_drupal_ui');
51
52     // Log in as user 1. Migrations in the UI can only be performed as user 1.
53     $this->drupalLogin($this->rootUser);
54   }
55
56   /**
57    * Loads a database fixture into the source database connection.
58    *
59    * @param string $path
60    *   Path to the dump file.
61    */
62   protected function loadFixture($path) {
63     $default_db = Database::getConnection()->getKey();
64     Database::setActiveConnection($this->sourceDatabase->getKey());
65
66     if (substr($path, -3) == '.gz') {
67       $path = 'compress.zlib://' . $path;
68     }
69     require $path;
70
71     Database::setActiveConnection($default_db);
72   }
73
74   /**
75    * Changes the database connection to the prefixed one.
76    *
77    * @todo Remove when we don't use global. https://www.drupal.org/node/2552791
78    */
79   protected function createMigrationConnection() {
80     $connection_info = Database::getConnectionInfo('default')['default'];
81     if ($connection_info['driver'] === 'sqlite') {
82       // Create database file in the test site's public file directory so that
83       // \Drupal\simpletest\TestBase::restoreEnvironment() will delete this once
84       // the test is complete.
85       $file = $this->publicFilesDirectory . '/' . $this->testId . '-migrate.db.sqlite';
86       touch($file);
87       $connection_info['database'] = $file;
88       $connection_info['prefix'] = '';
89     }
90     else {
91       $prefix = is_array($connection_info['prefix']) ? $connection_info['prefix']['default'] : $connection_info['prefix'];
92       // Simpletest uses fixed length prefixes. Create a new prefix for the
93       // source database. Adding to the end of the prefix ensures that
94       // \Drupal\simpletest\TestBase::restoreEnvironment() will remove the
95       // additional tables.
96       $connection_info['prefix'] = $prefix . '0';
97     }
98
99     Database::addConnectionInfo('migrate_drupal_ui', 'default', $connection_info);
100   }
101
102   /**
103    * {@inheritdoc}
104    */
105   protected function tearDown() {
106     Database::removeConnection('migrate_drupal_ui');
107     parent::tearDown();
108   }
109
110   /**
111    * Executes all steps of migrations upgrade.
112    */
113   public function testMigrateUpgrade() {
114     $connection_options = $this->sourceDatabase->getConnectionOptions();
115     $this->drupalGet('/upgrade');
116     $this->assertText('Upgrade a site by importing it into a clean and empty new install of Drupal 8. You will lose any existing configuration once you import your site into it. See the online documentation for Drupal site upgrades for more detailed information.');
117
118     $this->drupalPostForm(NULL, [], t('Continue'));
119     $this->assertText('Provide credentials for the database of the Drupal site you want to upgrade.');
120     $this->assertFieldByName('mysql[host]');
121
122     $driver = $connection_options['driver'];
123     $connection_options['prefix'] = $connection_options['prefix']['default'];
124
125     // Use the driver connection form to get the correct options out of the
126     // database settings. This supports all of the databases we test against.
127     $drivers = drupal_get_database_types();
128     $form = $drivers[$driver]->getFormOptions($connection_options);
129     $connection_options = array_intersect_key($connection_options, $form + $form['advanced_options']);
130     $version = $this->getLegacyDrupalVersion($this->sourceDatabase);
131     $edit = [
132       $driver => $connection_options,
133       'source_base_path' => $this->getSourceBasePath(),
134       'source_private_file_path' => $this->getSourceBasePath(),
135       'version' => $version,
136     ];
137     if (count($drivers) !== 1) {
138       $edit['driver'] = $driver;
139     }
140     $edits = $this->translatePostValues($edit);
141
142     // Ensure submitting the form with invalid database credentials gives us a
143     // nice warning.
144     $this->drupalPostForm(NULL, [$driver . '[database]' => 'wrong'] + $edits, t('Review upgrade'));
145     $this->assertText('Resolve the issue below to continue the upgrade.');
146
147     $this->drupalPostForm(NULL, $edits, t('Review upgrade'));
148     $this->assertResponse(200);
149     $this->assertText('Are you sure?');
150     $this->drupalPostForm(NULL, [], t('Perform upgrade'));
151     $this->assertText(t('Congratulations, you upgraded Drupal!'));
152
153     // Have to reset all the statics after migration to ensure entities are
154     // loadable.
155     $this->resetAll();
156
157     $expected_counts = $this->getEntityCounts();
158     foreach (array_keys(\Drupal::entityTypeManager()
159       ->getDefinitions()) as $entity_type) {
160       $real_count = \Drupal::entityQuery($entity_type)->count()->execute();
161       $expected_count = isset($expected_counts[$entity_type]) ? $expected_counts[$entity_type] : 0;
162       $this->assertEqual($expected_count, $real_count, "Found $real_count $entity_type entities, expected $expected_count.");
163     }
164
165     $plugin_manager = \Drupal::service('plugin.manager.migration');
166     /** @var \Drupal\migrate\Plugin\Migration[] $all_migrations */
167     $all_migrations = $plugin_manager->createInstancesByTag('Drupal ' . $version);
168     foreach ($all_migrations as $migration) {
169       $id_map = $migration->getIdMap();
170       foreach ($id_map as $source_id => $map) {
171         // Convert $source_id into a keyless array so that
172         // \Drupal\migrate\Plugin\migrate\id_map\Sql::getSourceHash() works as
173         // expected.
174         $source_id_values = array_values(unserialize($source_id));
175         $row = $id_map->getRowBySource($source_id_values);
176         $destination = serialize($id_map->currentDestination());
177         $message = "Migration of $source_id to $destination as part of the {$migration->id()} migration. The source row status is " . $row['source_row_status'];
178         // A completed migration should have maps with
179         // MigrateIdMapInterface::STATUS_IGNORED or
180         // MigrateIdMapInterface::STATUS_IMPORTED.
181         if ($row['source_row_status'] == MigrateIdMapInterface::STATUS_FAILED || $row['source_row_status'] == MigrateIdMapInterface::STATUS_NEEDS_UPDATE) {
182           $this->fail($message);
183         }
184         else {
185           $this->pass($message);
186         }
187       }
188     }
189     \Drupal::service('module_installer')->install(['forum']);
190     \Drupal::service('module_installer')->install(['book']);
191   }
192
193   /**
194    * Transforms a nested array into a flat array suitable for BrowserTestBase::drupalPostForm().
195    *
196    * @param array $values
197    *   A multi-dimensional form values array to convert.
198    *
199    * @return array
200    *   The flattened $edit array suitable for BrowserTestBase::drupalPostForm().
201    */
202   protected function translatePostValues(array $values) {
203     $edit = [];
204     // The easiest and most straightforward way to translate values suitable for
205     // BrowserTestBase::drupalPostForm() is to actually build the POST data string
206     // and convert the resulting key/value pairs back into a flat array.
207     $query = http_build_query($values);
208     foreach (explode('&', $query) as $item) {
209       list($key, $value) = explode('=', $item);
210       $edit[urldecode($key)] = urldecode($value);
211     }
212     return $edit;
213   }
214
215   /**
216    * Gets the source base path for the concrete test.
217    *
218    * @return string
219    *   The source base path.
220    */
221   abstract protected function getSourceBasePath();
222
223   /**
224    * Gets the expected number of entities per entity type after migration.
225    *
226    * @return int[]
227    *   An array of expected counts keyed by entity type ID.
228    */
229   abstract protected function getEntityCounts();
230
231 }