Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
PatchApplierTest.php
Go to the documentation of this file.
1 <?php
8 
23 
29 class PatchApplierTest extends \PHPUnit\Framework\TestCase
30 {
34  private $patchRegistryFactoryMock;
35 
39  private $dataPatchReaderMock;
40 
44  private $schemaPatchReaderMock;
45 
49  private $resourceConnectionMock;
50 
54  private $moduleResourceMock;
55 
59  private $patchHistoryMock;
60 
64  private $patchFactoryMock;
65 
69  private $schemaSetupMock;
70 
74  private $moduleDataSetupMock;
75 
79  private $objectManagerMock;
80 
84  private $patchApllier;
85 
89  private $connectionMock;
90 
94  private $patchBacwardCompatability;
95 
96  protected function setUp()
97  {
98  $this->patchRegistryFactoryMock = $this->createMock(PatchRegistryFactory::class);
99  $this->dataPatchReaderMock = $this->createMock(PatchReader::class);
100  $this->schemaPatchReaderMock = $this->createMock(PatchReader::class);
101  $this->resourceConnectionMock = $this->createMock(ResourceConnection::class);
102  $this->moduleResourceMock = $this->createMock(ModuleResource::class);
103  $this->patchHistoryMock = $this->createMock(PatchHistory::class);
104  $this->patchFactoryMock = $this->createMock(PatchFactory::class);
105  $this->schemaSetupMock = $this->createMock(SchemaSetupInterface::class);
106  $this->moduleDataSetupMock = $this->createMock(ModuleDataSetupInterface::class);
107  $this->objectManagerMock = $this->createMock(ObjectManagerInterface::class);
108  $this->connectionMock = $this->createMock(AdapterInterface::class);
109  $this->moduleDataSetupMock->expects($this->any())->method('getConnection')->willReturn($this->connectionMock);
110 
111  $objectManager = new ObjectManager($this);
112  $this->patchBacwardCompatability = $objectManager->getObject(
113  PatchBackwardCompatability::class,
114  [
115  'moduleResource' => $this->moduleResourceMock
116  ]
117  );
118  $this->patchApllier = $objectManager->getObject(
119  PatchApplier::class,
120  [
121  'patchRegistryFactory' => $this->patchRegistryFactoryMock,
122  'dataPatchReader' => $this->dataPatchReaderMock,
123  'schemaPatchReader' => $this->schemaPatchReaderMock,
124  'resourceConnection' => $this->resourceConnectionMock,
125  'moduleResource' => $this->moduleResourceMock,
126  'patchHistory' => $this->patchHistoryMock,
127  'patchFactory' => $this->patchFactoryMock,
128  'objectManager' => $this->objectManagerMock,
129  'schemaSetup' => $this->schemaSetupMock,
130  'moduleDataSetup' => $this->moduleDataSetupMock,
131  'patchBackwardCompatability' => $this->patchBacwardCompatability
132  ]
133  );
134  require_once __DIR__ . '/../_files/data_patch_classes.php';
135  require_once __DIR__ . '/../_files/schema_patch_classes.php';
136  }
137 
145  public function testApplyDataPatchForNewlyInstalledModule($moduleName, $dataPatches, $moduleVersionInDb)
146  {
147  $this->dataPatchReaderMock->expects($this->once())
148  ->method('read')
149  ->with($moduleName)
150  ->willReturn($dataPatches);
151 
152  $this->moduleResourceMock->expects($this->any())->method('getDataVersion')->willReturnMap(
153  [
154  [$moduleName, $moduleVersionInDb]
155  ]
156  );
157 
158  $patches = [
159  \SomeDataPatch::class,
160  \OtherDataPatch::class
161  ];
162  $patchRegistryMock = $this->createAggregateIteratorMock(PatchRegistry::class, $patches, ['registerPatch']);
163  $patchRegistryMock->expects($this->exactly(2))
164  ->method('registerPatch');
165 
166  $this->patchRegistryFactoryMock->expects($this->any())
167  ->method('create')
168  ->willReturn($patchRegistryMock);
169 
170  $patch1 = $this->createMock(\SomeDataPatch::class);
171  $patch1->expects($this->once())->method('apply');
172  $patch2 = $this->createMock(\OtherDataPatch::class);
173  $patch2->expects($this->once())->method('apply');
174  $this->objectManagerMock->expects($this->any())->method('create')->willReturnMap(
175  [
176  ['\\' . \SomeDataPatch::class, ['moduleDataSetup' => $this->moduleDataSetupMock], $patch1],
177  ['\\' . \OtherDataPatch::class, ['moduleDataSetup' => $this->moduleDataSetupMock], $patch2],
178  ]
179  );
180  $this->connectionMock->expects($this->exactly(2))->method('beginTransaction');
181  $this->connectionMock->expects($this->exactly(2))->method('commit');
182  $this->patchHistoryMock->expects($this->any())->method('fixPatch')->willReturnMap(
183  [
184  [get_class($patch1)],
185  [get_class($patch2)],
186  ]
187  );
188  $this->patchApllier->applyDataPatch($moduleName);
189  }
190 
195  {
196  return [
197  'newly installed module' => [
198  'moduleName' => 'Module1',
199  'dataPatches' => [
200  \SomeDataPatch::class,
201  \OtherDataPatch::class
202  ],
203  'moduleVersionInDb' => null,
204  ],
205  ];
206  }
207 
215  public function testApplyDataPatchForInstalledModule($moduleName, $dataPatches, $moduleVersionInDb)
216  {
217  $this->dataPatchReaderMock->expects($this->once())
218  ->method('read')
219  ->with($moduleName)
220  ->willReturn($dataPatches);
221 
222  $this->moduleResourceMock->expects($this->any())->method('getDataVersion')->willReturnMap(
223  [
224  [$moduleName, $moduleVersionInDb]
225  ]
226  );
227 
228  $patches = [
229  \SomeDataPatch::class,
230  \OtherDataPatch::class
231  ];
232  $patchRegistryMock = $this->createAggregateIteratorMock(
233  PatchRegistry::class,
234  $patches,
235  ['registerPatch']
236  );
237  $patchRegistryMock->expects(self::exactly(2))
238  ->method('registerPatch');
239 
240  $this->patchRegistryFactoryMock->expects(self::any())
241  ->method('create')
242  ->willReturn($patchRegistryMock);
243 
244  $patch1 = $this->createMock(\SomeDataPatch::class);
245  $patch1->expects(self::never())->method('apply');
246  $patch2 = $this->createMock(\OtherDataPatch::class);
247  $patch2->expects(self::once())->method('apply');
248  $this->objectManagerMock->expects(self::any())->method('create')->willReturnMap(
249  [
250  ['\\' . \SomeDataPatch::class, ['moduleDataSetup' => $this->moduleDataSetupMock], $patch1],
251  ['\\' . \OtherDataPatch::class, ['moduleDataSetup' => $this->moduleDataSetupMock], $patch2],
252  ]
253  );
254  $this->connectionMock->expects(self::exactly(1))->method('beginTransaction');
255  $this->connectionMock->expects(self::exactly(1))->method('commit');
256  $this->patchHistoryMock->expects(self::exactly(2))->method('fixPatch');
257  $this->patchApllier->applyDataPatch($moduleName);
258  }
259 
264  {
265  return [
266  'upgrade module iwth only OtherDataPatch' => [
267  'moduleName' => 'Module1',
268  'dataPatches' => [
269  \SomeDataPatch::class,
270  \OtherDataPatch::class
271  ],
272  'moduleVersionInDb' => '2.0.0',
273  ]
274  ];
275  }
276 
287  public function testApplyDataPatchRollback($moduleName, $dataPatches, $moduleVersionInDb)
288  {
289  $this->dataPatchReaderMock->expects($this->once())
290  ->method('read')
291  ->with($moduleName)
292  ->willReturn($dataPatches);
293 
294  $this->moduleResourceMock->expects($this->any())->method('getDataVersion')->willReturnMap(
295  [
296  [$moduleName, $moduleVersionInDb]
297  ]
298  );
299 
300  $patches = [
301  \SomeDataPatch::class,
302  \OtherDataPatch::class
303  ];
304  $patchRegistryMock = $this->createAggregateIteratorMock(PatchRegistry::class, $patches, ['registerPatch']);
305  $patchRegistryMock->expects($this->exactly(2))
306  ->method('registerPatch');
307 
308  $this->patchRegistryFactoryMock->expects($this->any())
309  ->method('create')
310  ->willReturn($patchRegistryMock);
311 
312  $patch1 = $this->createMock(\SomeDataPatch::class);
313  $patch1->expects($this->never())->method('apply');
314  $patch2 = $this->createMock(\OtherDataPatch::class);
315  $exception = new \Exception('Patch Apply Error');
316  $patch2->expects($this->once())->method('apply')->willThrowException($exception);
317  $this->objectManagerMock->expects($this->any())->method('create')->willReturnMap(
318  [
319  ['\\' . \SomeDataPatch::class, ['moduleDataSetup' => $this->moduleDataSetupMock], $patch1],
320  ['\\' . \OtherDataPatch::class, ['moduleDataSetup' => $this->moduleDataSetupMock], $patch2],
321  ]
322  );
323  $this->connectionMock->expects($this->exactly(1))->method('beginTransaction');
324  $this->connectionMock->expects($this->never())->method('commit');
325  $this->connectionMock->expects($this->exactly(1))->method('rollback');
326  $this->patchHistoryMock->expects($this->exactly(1))->method('fixPatch');
327  $this->patchApllier->applyDataPatch($moduleName);
328  }
329 
334  public function testNonDataPatchApply()
335  {
336  $this->dataPatchReaderMock->expects($this->once())
337  ->method('read')
338  ->with('module1')
339  ->willReturn([\stdClass::class]);
340  $patchRegistryMock = $this->createAggregateIteratorMock(
341  PatchRegistry::class,
342  [\stdClass::class],
343  ['registerPatch']
344  );
345  $patchRegistryMock->expects($this->exactly(1))
346  ->method('registerPatch');
347 
348  $this->patchRegistryFactoryMock->expects($this->any())
349  ->method('create')
350  ->willReturn($patchRegistryMock);
351 
352  $this->objectManagerMock->expects($this->any())->method('create')->willReturnMap(
353  [
354  [
355  '\\' . \stdClass::class,
356  ['moduleDataSetup' => $this->moduleDataSetupMock],
357  $this->createMock(\stdClass::class)
358  ],
359  ]
360  );
361 
362  $this->patchApllier->applyDataPatch('module1');
363  }
364 
365  public function testNonTransactionablePatch()
366  {
367  $patches = [\NonTransactionableDataPatch::class];
368  $this->dataPatchReaderMock->expects($this->once())
369  ->method('read')
370  ->with('module1')
371  ->willReturn($patches);
372  $patchRegistryMock = $this->createAggregateIteratorMock(
373  PatchRegistry::class,
374  $patches,
375  ['registerPatch']
376  );
377  $patchRegistryMock->expects($this->exactly(1))
378  ->method('registerPatch');
379 
380  $this->patchRegistryFactoryMock->expects($this->any())
381  ->method('create')
382  ->willReturn($patchRegistryMock);
383 
384  $patch1 = $this->createMock($patches[0]);
385  $patch1->expects($this->exactly(1))->method('apply');
386  $this->connectionMock->expects($this->never())->method('beginTransaction');
387  $this->connectionMock->expects($this->never())->method('commit');
388  $this->connectionMock->expects($this->never())->method('rollback');
389  $this->patchHistoryMock->expects($this->once())->method('fixPatch')->with(get_class($patch1));
390  $this->objectManagerMock->expects($this->any())->method('create')->willReturnMap(
391  [
392  [
393  '\\' . $patches[0],
394  ['moduleDataSetup' => $this->moduleDataSetupMock],
395  $patch1
396  ],
397  ]
398  );
399 
400  $this->patchApllier->applyDataPatch('module1');
401  }
402 
410  public function testSchemaPatchAplly($moduleName, $schemaPatches, $moduleVersionInDb)
411  {
412  $this->schemaPatchReaderMock->expects($this->once())
413  ->method('read')
414  ->with($moduleName)
415  ->willReturn($schemaPatches);
416 
417  $this->moduleResourceMock->expects($this->any())->method('getDbVersion')->willReturnMap(
418  [
419  [$moduleName, $moduleVersionInDb]
420  ]
421  );
422 
423  $patches = [
424  \SomeSchemaPatch::class,
425  \OtherSchemaPatch::class
426  ];
427  $patchRegistryMock = $this->createAggregateIteratorMock(PatchRegistry::class, $patches, ['registerPatch']);
428  $patchRegistryMock->expects($this->exactly(2))
429  ->method('registerPatch');
430 
431  $this->patchRegistryFactoryMock->expects($this->any())
432  ->method('create')
433  ->willReturn($patchRegistryMock);
434 
435  $patch1 = $this->createMock(\SomeSchemaPatch::class);
436  $patch1->expects($this->never())->method('apply');
437  $patch2 = $this->createMock(\OtherSchemaPatch::class);
438  $patch2->expects($this->once())->method('apply');
439  $this->patchFactoryMock->expects($this->any())->method('create')->willReturnMap(
440  [
441  [\SomeSchemaPatch::class, ['schemaSetup' => $this->schemaSetupMock], $patch1],
442  [\OtherSchemaPatch::class, ['schemaSetup' => $this->schemaSetupMock], $patch2],
443  ]
444  );
445  $this->connectionMock->expects($this->never())->method('beginTransaction');
446  $this->connectionMock->expects($this->never())->method('commit');
447  $this->patchHistoryMock->expects($this->exactly(2))->method('fixPatch');
448  $this->patchApllier->applySchemaPatch($moduleName);
449  }
450 
451  public function testRevertDataPatches()
452  {
453  $patches = [\RevertableDataPatch::class];
454  $this->dataPatchReaderMock->expects($this->once())
455  ->method('read')
456  ->with('module1')
457  ->willReturn($patches);
458  $patchRegistryMock = $this->createAggregateIteratorMock(
459  PatchRegistry::class,
460  $patches,
461  ['registerPatch', 'getReverseIterator']
462  );
463  $patchRegistryMock->expects($this->exactly(1))
464  ->method('registerPatch');
465  $patchRegistryMock->expects($this->once())->method('getReverseIterator')
466  ->willReturn(array_reverse($patches));
467 
468  $this->patchRegistryFactoryMock->expects($this->any())
469  ->method('create')
470  ->willReturn($patchRegistryMock);
471 
472  $patch1 = $this->createMock($patches[0]);
473  $patch1->expects($this->exactly(1))->method('revert');
474  $this->connectionMock->expects($this->once())->method('beginTransaction');
475  $this->connectionMock->expects($this->once())->method('commit');
476  $this->connectionMock->expects($this->never())->method('rollback');
477  $this->patchHistoryMock->expects($this->once())->method('revertPatchFromHistory')->with(get_class($patch1));
478  $this->objectManagerMock->expects($this->any())->method('create')->willReturnMap(
479  [
480  [
481  '\\' . $patches[0],
482  ['moduleDataSetup' => $this->moduleDataSetupMock],
483  $patch1
484  ],
485  ]
486  );
487 
488  $this->patchApllier->revertDataPatches('module1');
489  }
490 
494  public function schemaPatchDataProvider()
495  {
496  return [
497  'upgrade module iwth only OtherSchemaPatch' => [
498  'moduleName' => 'Module1',
499  'schemaPatches' => [
500  \SomeSchemaPatch::class,
501  \OtherSchemaPatch::class
502  ],
503  'moduleVersionInDb' => '2.0.0',
504  ]
505  ];
506  }
516  private function createAggregateIteratorMock($className, array $items = [], array $methods = [])
517  {
518  if (!in_array(ltrim(\IteratorAggregate::class, '\\'), class_implements($className))) {
519  throw new \Exception('Mock possible only for classes that implement IteratorAggregate interface.');
520  }
524  $someIterator = $this->createMock(\ArrayIterator::class);
525 
526  $mockIteratorAggregate = $this->getMockBuilder($className)
527  ->disableOriginalConstructor()
528  ->setMethods(array_merge($methods, ['getIterator']))
529  ->getMock();
530 
531  $mockIteratorAggregate->expects($this->any())->method('getIterator')->willReturn($someIterator);
532 
533  $iterator = new \ArrayIterator($items);
534 
535  $someIterator->expects($this->any())
536  ->method('rewind')
537  ->willReturnCallback(function () use ($iterator) {
538  $iterator->rewind();
539  });
540 
541  $someIterator->expects($this->any())
542  ->method('current')
543  ->willReturnCallback(function () use ($iterator) {
544  return $iterator->current();
545  });
546 
547  $someIterator->expects($this->any())
548  ->method('key')
549  ->willReturnCallback(function () use ($iterator) {
550  return $iterator->key();
551  });
552 
553  $someIterator->expects($this->any())
554  ->method('next')
555  ->willReturnCallback(function () use ($iterator) {
556  $iterator->next();
557  });
558 
559  $someIterator->expects($this->any())
560  ->method('valid')
561  ->willReturnCallback(function () use ($iterator) {
562  return $iterator->valid();
563  });
564 
565  return $mockIteratorAggregate;
566  }
567 }
testApplyDataPatchForNewlyInstalledModule($moduleName, $dataPatches, $moduleVersionInDb)
$objectManager
Definition: bootstrap.php:17
defined('TESTS_BP')||define('TESTS_BP' __DIR__
Definition: _bootstrap.php:60
testSchemaPatchAplly($moduleName, $schemaPatches, $moduleVersionInDb)
$methods
Definition: billing.phtml:71
testApplyDataPatchRollback($moduleName, $dataPatches, $moduleVersionInDb)
testApplyDataPatchForInstalledModule($moduleName, $dataPatches, $moduleVersionInDb)
if($currentSelectedMethod==$_code) $className
Definition: form.phtml:31
$items