Mercurial > hg > isophonics-drupal-site
comparison core/modules/migrate/tests/src/Kernel/QueryBatchTest.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 7a779792577d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\Tests\migrate\Kernel; | |
4 | |
5 use Drupal\KernelTests\KernelTestBase; | |
6 use Drupal\migrate\MigrateException; | |
7 use Drupal\migrate\Plugin\MigrateIdMapInterface; | |
8 use Drupal\migrate\Plugin\MigrationInterface; | |
9 use Drupal\Core\Database\Driver\sqlite\Connection; | |
10 | |
11 /** | |
12 * Tests query batching. | |
13 * | |
14 * @covers \Drupal\migrate_query_batch_test\Plugin\migrate\source\QueryBatchTest | |
15 * @group migrate | |
16 */ | |
17 class QueryBatchTest extends KernelTestBase { | |
18 | |
19 /** | |
20 * The mocked migration. | |
21 * | |
22 * @var MigrationInterface|\Prophecy\Prophecy\ObjectProphecy | |
23 */ | |
24 protected $migration; | |
25 | |
26 /** | |
27 * {@inheritdoc} | |
28 */ | |
29 public static $modules = [ | |
30 'migrate', | |
31 'migrate_query_batch_test', | |
32 ]; | |
33 | |
34 /** | |
35 * {@inheritdoc} | |
36 */ | |
37 protected function setUp() { | |
38 parent::setUp(); | |
39 | |
40 // Create a mock migration. This will be injected into the source plugin | |
41 // under test. | |
42 $this->migration = $this->prophesize(MigrationInterface::class); | |
43 | |
44 $this->migration->id()->willReturn( | |
45 $this->randomMachineName(16) | |
46 ); | |
47 // Prophesize a useless ID map plugin and an empty set of destination IDs. | |
48 // Calling code can override these prophecies later and set up different | |
49 // behaviors. | |
50 $this->migration->getIdMap()->willReturn( | |
51 $this->prophesize(MigrateIdMapInterface::class)->reveal() | |
52 ); | |
53 $this->migration->getDestinationIds()->willReturn([]); | |
54 } | |
55 | |
56 /** | |
57 * Tests a negative batch size throws an exception. | |
58 */ | |
59 public function testBatchSizeNegative() { | |
60 $this->setExpectedException(MigrateException::class, 'batch_size must be greater than or equal to zero'); | |
61 $plugin = $this->getPlugin(['batch_size' => -1]); | |
62 $plugin->next(); | |
63 } | |
64 | |
65 /** | |
66 * Tests a non integer batch size throws an exception. | |
67 */ | |
68 public function testBatchSizeNonInteger() { | |
69 $this->setExpectedException(MigrateException::class, 'batch_size must be greater than or equal to zero'); | |
70 $plugin = $this->getPlugin(['batch_size' => '1']); | |
71 $plugin->next(); | |
72 } | |
73 | |
74 /** | |
75 * {@inheritdoc} | |
76 */ | |
77 public function queryDataProvider() { | |
78 // Define the parameters for building the data array. The first element is | |
79 // the number of source data rows, the second is the batch size to set on | |
80 // the plugin configuration. | |
81 $test_parameters = [ | |
82 // Test when batch size is 0. | |
83 [200, 0], | |
84 // Test when rows mod batch size is 0. | |
85 [200, 20], | |
86 // Test when rows mod batch size is > 0. | |
87 [200, 30], | |
88 // Test when batch size = row count. | |
89 [200, 200], | |
90 // Test when batch size > row count. | |
91 [200, 300], | |
92 ]; | |
93 | |
94 // Build the data provider array. The provider array consists of the source | |
95 // data rows, the expected result data, the expected count, the plugin | |
96 // configuration, the expected batch size and the expected batch count. | |
97 $table = 'query_batch_test'; | |
98 $tests = []; | |
99 $data_set = 0; | |
100 foreach ($test_parameters as $data) { | |
101 list($num_rows, $batch_size) = $data; | |
102 for ($i = 0; $i < $num_rows; $i++) { | |
103 $tests[$data_set]['source_data'][$table][] = [ | |
104 'id' => $i, | |
105 'data' => $this->randomString(), | |
106 ]; | |
107 } | |
108 $tests[$data_set]['expected_data'] = $tests[$data_set]['source_data'][$table]; | |
109 $tests[$data_set][2] = $num_rows; | |
110 // Plugin configuration array. | |
111 $tests[$data_set][3] = ['batch_size' => $batch_size]; | |
112 // Expected batch size. | |
113 $tests[$data_set][4] = $batch_size; | |
114 // Expected batch count is 0 unless a batch size is set. | |
115 $expected_batch_count = 0; | |
116 if ($batch_size > 0) { | |
117 $expected_batch_count = (int) ($num_rows / $batch_size); | |
118 if ($num_rows % $batch_size) { | |
119 // If there is a remainder an extra batch is needed to get the | |
120 // remaining rows. | |
121 $expected_batch_count++; | |
122 } | |
123 } | |
124 $tests[$data_set][5] = $expected_batch_count; | |
125 $data_set++; | |
126 } | |
127 return $tests; | |
128 } | |
129 | |
130 /** | |
131 * Tests query batch size. | |
132 * | |
133 * @param array $source_data | |
134 * The source data, keyed by table name. Each table is an array containing | |
135 * the rows in that table. | |
136 * @param array $expected_data | |
137 * The result rows the plugin is expected to return. | |
138 * @param int $num_rows | |
139 * How many rows the source plugin is expected to return. | |
140 * @param array $configuration | |
141 * Configuration for the source plugin specifying the batch size. | |
142 * @param int $expected_batch_size | |
143 * The expected batch size, will be set to zero for invalid batch sizes. | |
144 * @param int $expected_batch_count | |
145 * The total number of batches. | |
146 * | |
147 * @dataProvider queryDataProvider | |
148 */ | |
149 public function testQueryBatch($source_data, $expected_data, $num_rows, $configuration, $expected_batch_size, $expected_batch_count) { | |
150 $plugin = $this->getPlugin($configuration); | |
151 | |
152 // Since we don't yet inject the database connection, we need to use a | |
153 // reflection hack to set it in the plugin instance. | |
154 $reflector = new \ReflectionObject($plugin); | |
155 $property = $reflector->getProperty('database'); | |
156 $property->setAccessible(TRUE); | |
157 | |
158 $connection = $this->getDatabase($source_data); | |
159 $property->setValue($plugin, $connection); | |
160 | |
161 // Test the results. | |
162 $i = 0; | |
163 /** @var \Drupal\migrate\Row $row */ | |
164 foreach ($plugin as $row) { | |
165 | |
166 $expected = $expected_data[$i++]; | |
167 $actual = $row->getSource(); | |
168 | |
169 foreach ($expected as $key => $value) { | |
170 $this->assertArrayHasKey($key, $actual); | |
171 $this->assertSame((string) $value, (string) $actual[$key]); | |
172 } | |
173 } | |
174 | |
175 // Test that all rows were retrieved. | |
176 self::assertSame($num_rows, $i); | |
177 | |
178 // Test the batch size. | |
179 if (is_null($expected_batch_size)) { | |
180 $expected_batch_size = $configuration['batch_size']; | |
181 } | |
182 $property = $reflector->getProperty('batchSize'); | |
183 $property->setAccessible(TRUE); | |
184 self::assertSame($expected_batch_size, $property->getValue($plugin)); | |
185 | |
186 // Test the batch count. | |
187 if (is_null($expected_batch_count)) { | |
188 $expected_batch_count = intdiv($num_rows, $expected_batch_size); | |
189 if ($num_rows % $configuration['batch_size']) { | |
190 $expected_batch_count++; | |
191 } | |
192 } | |
193 $property = $reflector->getProperty('batch'); | |
194 $property->setAccessible(TRUE); | |
195 self::assertSame($expected_batch_count, $property->getValue($plugin)); | |
196 } | |
197 | |
198 /** | |
199 * Instantiates the source plugin under test. | |
200 * | |
201 * @param array $configuration | |
202 * The source plugin configuration. | |
203 * | |
204 * @return \Drupal\migrate\Plugin\MigrateSourceInterface|object | |
205 * The fully configured source plugin. | |
206 */ | |
207 protected function getPlugin($configuration) { | |
208 /** @var \Drupal\migrate\Plugin\MigratePluginManager $plugin_manager */ | |
209 $plugin_manager = $this->container->get('plugin.manager.migrate.source'); | |
210 $plugin = $plugin_manager->createInstance('query_batch_test', $configuration, $this->migration->reveal()); | |
211 | |
212 $this->migration | |
213 ->getSourcePlugin() | |
214 ->willReturn($plugin); | |
215 return $plugin; | |
216 } | |
217 | |
218 /** | |
219 * Builds an in-memory SQLite database from a set of source data. | |
220 * | |
221 * @param array $source_data | |
222 * The source data, keyed by table name. Each table is an array containing | |
223 * the rows in that table. | |
224 * | |
225 * @return \Drupal\Core\Database\Driver\sqlite\Connection | |
226 * The SQLite database connection. | |
227 */ | |
228 protected function getDatabase(array $source_data) { | |
229 // Create an in-memory SQLite database. Plugins can interact with it like | |
230 // any other database, and it will cease to exist when the connection is | |
231 // closed. | |
232 $connection_options = ['database' => ':memory:']; | |
233 $pdo = Connection::open($connection_options); | |
234 $connection = new Connection($pdo, $connection_options); | |
235 | |
236 // Create the tables and fill them with data. | |
237 foreach ($source_data as $table => $rows) { | |
238 // Use the biggest row to build the table schema. | |
239 $counts = array_map('count', $rows); | |
240 asort($counts); | |
241 end($counts); | |
242 $pilot = $rows[key($counts)]; | |
243 | |
244 $connection->schema() | |
245 ->createTable($table, [ | |
246 // SQLite uses loose affinity typing, so it's OK for every field to | |
247 // be a text field. | |
248 'fields' => array_map(function () { | |
249 return ['type' => 'text']; | |
250 }, $pilot), | |
251 ]); | |
252 | |
253 $fields = array_keys($pilot); | |
254 $insert = $connection->insert($table)->fields($fields); | |
255 array_walk($rows, [$insert, 'values']); | |
256 $insert->execute(); | |
257 } | |
258 return $connection; | |
259 } | |
260 | |
261 } |