Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
ModuleUninstallCommandTest.php
Go to the documentation of this file.
1 <?php
7 
12 use Symfony\Component\Console\Tester\CommandTester;
13 
18 class ModuleUninstallCommandTest extends \PHPUnit\Framework\TestCase
19 {
23  private $deploymentConfig;
24 
28  private $fullModuleList;
29 
33  private $maintenanceMode;
34 
38  private $uninstallCollector;
39 
43  private $packageInfo;
44 
48  private $dependencyChecker;
49 
53  private $moduleUninstaller;
54 
58  private $moduleRegistryUninstaller;
59 
63  private $cache;
64 
68  private $cleanupFiles;
69 
73  private $backupRollback;
74 
78  private $backupRollbackFactory;
79 
83  private $question;
84 
88  private $helperSet;
89 
93  private $command;
94 
98  private $tester;
99 
103  private $patchApplierMock;
104 
108  public function setUp()
109  {
110  $this->deploymentConfig = $this->createMock(\Magento\Framework\App\DeploymentConfig::class);
111  $this->fullModuleList = $this->createMock(\Magento\Framework\Module\FullModuleList::class);
112  $this->maintenanceMode = $this->createMock(\Magento\Framework\App\MaintenanceMode::class);
113  $objectManagerProvider = $this->createMock(\Magento\Setup\Model\ObjectManagerProvider::class);
114  $objectManager = $this->getMockForAbstractClass(
115  \Magento\Framework\ObjectManagerInterface::class,
116  [],
117  '',
118  false
119  );
120  $this->uninstallCollector = $this->createMock(\Magento\Setup\Model\UninstallCollector::class);
121  $this->packageInfo = $this->createMock(\Magento\Framework\Module\PackageInfo::class);
122  $packageInfoFactory = $this->createMock(\Magento\Framework\Module\PackageInfoFactory::class);
123  $packageInfoFactory->expects($this->once())->method('create')->willReturn($this->packageInfo);
124  $this->dependencyChecker = $this->createMock(\Magento\Framework\Module\DependencyChecker::class);
125  $this->backupRollback = $this->createMock(\Magento\Framework\Setup\BackupRollback::class);
126  $this->backupRollbackFactory = $this->createMock(\Magento\Framework\Setup\BackupRollbackFactory::class);
127  $this->backupRollbackFactory->expects($this->any())
128  ->method('create')
129  ->willReturn($this->backupRollback);
130  $this->cache = $this->createMock(\Magento\Framework\App\Cache::class);
131  $this->cleanupFiles = $this->createMock(\Magento\Framework\App\State\CleanupFiles::class);
132  $objectManagerProvider->expects($this->any())->method('get')->willReturn($objectManager);
133  $configLoader = $this->getMockForAbstractClass(
134  \Magento\Framework\ObjectManager\ConfigLoaderInterface::class,
135  [],
136  '',
137  false
138  );
139  $this->patchApplierMock = $this->getMockBuilder(PatchApplier::class)
140  ->disableOriginalConstructor()
141  ->getMock();
142  $configLoader->expects($this->any())->method('load')->willReturn([]);
143  $objectManager->expects($this->any())
144  ->method('get')
145  ->will($this->returnValueMap([
146  [\Magento\Framework\Module\PackageInfoFactory::class, $packageInfoFactory],
147  [\Magento\Framework\Module\DependencyChecker::class, $this->dependencyChecker],
148  [\Magento\Framework\App\Cache::class, $this->cache],
149  [\Magento\Framework\App\State\CleanupFiles::class, $this->cleanupFiles],
150  [
151  \Magento\Framework\App\State::class,
152  $this->createMock(\Magento\Framework\App\State::class)
153  ],
154  [\Magento\Framework\Setup\BackupRollbackFactory::class, $this->backupRollbackFactory],
155  [PatchApplier::class, $this->patchApplierMock],
156  [\Magento\Framework\ObjectManager\ConfigLoaderInterface::class, $configLoader],
157  ]));
158  $composer = $this->createMock(\Magento\Framework\Composer\ComposerInformation::class);
159  $composer->expects($this->any())
160  ->method('getRootRequiredPackages')
161  ->willReturn(['magento/package-a', 'magento/package-b']);
162  $this->moduleUninstaller = $this->createMock(\Magento\Setup\Model\ModuleUninstaller::class);
163  $this->moduleRegistryUninstaller = $this->createMock(\Magento\Setup\Model\ModuleRegistryUninstaller::class);
164  $this->command = new ModuleUninstallCommand(
165  $composer,
166  $this->deploymentConfig,
167  $this->fullModuleList,
168  $this->maintenanceMode,
169  $objectManagerProvider,
170  $this->uninstallCollector,
171  $this->moduleUninstaller,
172  $this->moduleRegistryUninstaller,
173  new MaintenanceModeEnabler($this->maintenanceMode)
174  );
175  $this->question = $this->createMock(\Symfony\Component\Console\Helper\QuestionHelper::class);
176  $this->question
177  ->expects($this->any())
178  ->method('ask')
179  ->will($this->returnValue(true));
180  $this->helperSet = $this->createMock(\Symfony\Component\Console\Helper\HelperSet::class);
181  $this->helperSet
182  ->expects($this->any())
183  ->method('get')
184  ->with('question')
185  ->will($this->returnValue($this->question));
186  $this->command->setHelperSet($this->helperSet);
187  $this->tester = new CommandTester($this->command);
188  }
189 
191  {
192  $this->deploymentConfig->expects($this->once())->method('isAvailable')->willReturn(false);
193  $this->tester->execute(['module' => ['Magento_A']]);
194  $this->assertEquals(
195  'You cannot run this command because the Magento application is not installed.' . PHP_EOL,
196  $this->tester->getDisplay()
197  );
198  }
199 
208  array $packageInfoMap,
209  array $fullModuleListMap,
210  array $input,
211  array $expect
212  ) {
213  $this->deploymentConfig->expects($this->once())->method('isAvailable')->willReturn(true);
214  $this->packageInfo->expects($this->exactly(count($input['module'])))
215  ->method('getPackageName')
216  ->will($this->returnValueMap($packageInfoMap));
217  $this->fullModuleList->expects($this->exactly(count($input['module'])))
218  ->method('has')
219  ->will($this->returnValueMap($fullModuleListMap));
220  $this->tester->execute($input);
221  foreach ($expect as $message) {
222  $this->assertContains($message, $this->tester->getDisplay());
223  }
224  }
225 
230  {
231  return [
232  'one non-composer package' => [
233  [['Magento_C', 'magento/package-c']],
234  [['Magento_C', true]],
235  ['module' => ['Magento_C']],
236  ['Magento_C is not an installed composer package']
237  ],
238  'one non-composer package, one valid' => [
239  [['Magento_A', 'magento/package-a'], ['Magento_C', 'magento/package-c']],
240  [['Magento_A', true], ['Magento_C', true]],
241  ['module' => ['Magento_A', 'Magento_C']],
242  ['Magento_C is not an installed composer package']
243  ],
244  'two non-composer packages' => [
245  [['Magento_C', 'magento/package-c'], ['Magento_D', 'magento/package-d']],
246  [['Magento_C', true], ['Magento_D', true]],
247  ['module' => ['Magento_C', 'Magento_D']],
248  ['Magento_C, Magento_D are not installed composer packages']
249  ],
250  'one unknown module' => [
251  [['Magento_C', '']],
252  [['Magento_C', false]],
253  ['module' => ['Magento_C']],
254  ['Unknown module(s): Magento_C']
255  ],
256  'two unknown modules' => [
257  [['Magento_C', ''], ['Magento_D', '']],
258  [['Magento_C', false], ['Magento_D', false]],
259  ['module' => ['Magento_C', 'Magento_D']],
260  ['Unknown module(s): Magento_C, Magento_D']
261  ],
262  'one unknown module, one valid' => [
263  [['Magento_C', ''], ['Magento_B', 'magento/package-b']],
264  [['Magento_C', false], ['Magento_B', true]],
265  ['module' => ['Magento_C', 'Magento_B']],
266  ['Unknown module(s): Magento_C']
267  ],
268  'one non-composer package, one unknown module' => [
269  [['Magento_C', 'magento/package-c'], ['Magento_D', '']],
270  [['Magento_C', true], ['Magento_D', false]],
271  ['module' => ['Magento_C', 'Magento_D']],
272  ['Magento_C is not an installed composer package', 'Unknown module(s): Magento_D']
273  ],
274  'two non-composer package, one unknown module' => [
275  [['Magento_C', 'magento/package-c'], ['Magento_D', ''], ['Magento_E', 'magento/package-e']],
276  [['Magento_C', true], ['Magento_D', false], ['Magento_E', true]],
277  ['module' => ['Magento_C', 'Magento_D', 'Magento_E']],
278  ['Magento_C, Magento_E are not installed composer packages', 'Unknown module(s): Magento_D']
279  ],
280  'two non-composer package, two unknown module' => [
281  [
282  ['Magento_C', 'magento/package-c'],
283  ['Magento_D', ''],
284  ['Magento_E', 'magento/package-e'],
285  ['Magento_F', '']
286  ],
287  [['Magento_C', true], ['Magento_D', false], ['Magento_E', true], ['Magento_F', false]],
288  ['module' => ['Magento_C', 'Magento_D', 'Magento_E', 'Magento_F']],
289  ['Magento_C, Magento_E are not installed composer packages', 'Unknown module(s): Magento_D, Magento_F']
290  ],
291  'two non-composer package, two unknown module, two valid' => [
292  [
293  ['Magento_C', 'magento/package-c'],
294  ['Magento_D', ''],
295  ['Magento_E', 'magento/package-e'],
296  ['Magento_F', ''],
297  ['Magento_A', 'magento/package-a'],
298  ['Magento_B', 'magento/package-b'],
299  ],
300  [
301  ['Magento_A', true],
302  ['Magento_B', true],
303  ['Magento_C', true],
304  ['Magento_D', false],
305  ['Magento_E', true],
306  ['Magento_F', false]
307  ],
308  ['module' => ['Magento_A', 'Magento_B', 'Magento_C', 'Magento_D', 'Magento_E', 'Magento_F']],
309  ['Magento_C, Magento_E are not installed composer packages', 'Unknown module(s): Magento_D, Magento_F']
310  ]
311  ];
312  }
313 
314  private function setUpPassValidation()
315  {
316  $this->deploymentConfig->expects($this->once())->method('isAvailable')->willReturn(true);
317  $packageMap = [
318  ['Magento_A', 'magento/package-a'],
319  ['Magento_B', 'magento/package-b'],
320  ];
321  $this->packageInfo->expects($this->any())
322  ->method('getPackageName')
323  ->will($this->returnValueMap($packageMap));
324  $this->fullModuleList->expects($this->any())
325  ->method('has')
326  ->willReturn(true);
327  }
328 
336  array $dependencies,
337  array $input,
338  array $expect
339  ) {
340  $this->setUpPassValidation();
341  $this->dependencyChecker->expects($this->once())
342  ->method('checkDependenciesWhenDisableModules')
343  ->willReturn($dependencies);
344  $this->tester->execute($input);
345  foreach ($expect as $message) {
346  $this->assertContains($message, $this->tester->getDisplay());
347  }
348  }
349 
354  {
355  return [
356  [
357  ['Magento_A' => ['Magento_D' => ['Magento_D', 'Magento_A']]],
358  ['module' => ['Magento_A']],
359  [
360  "Cannot uninstall module 'Magento_A' because the following module(s) depend on it:" .
361  PHP_EOL . "\tMagento_D"
362  ]
363  ],
364  [
365  ['Magento_A' => ['Magento_D' => ['Magento_D', 'Magento_A']]],
366  ['module' => ['Magento_A', 'Magento_B']],
367  [
368  "Cannot uninstall module 'Magento_A' because the following module(s) depend on it:" .
369  PHP_EOL . "\tMagento_D"
370  ]
371  ],
372  [
373  [
374  'Magento_A' => ['Magento_D' => ['Magento_D', 'Magento_A']],
375  'Magento_B' => ['Magento_E' => ['Magento_E', 'Magento_A']]
376  ],
377  ['module' => ['Magento_A', 'Magento_B']],
378  [
379  "Cannot uninstall module 'Magento_A' because the following module(s) depend on it:" .
380  PHP_EOL . "\tMagento_D",
381  "Cannot uninstall module 'Magento_B' because the following module(s) depend on it:" .
382  PHP_EOL . "\tMagento_E"
383  ]
384  ],
385  ];
386  }
387 
388  private function setUpExecute()
389  {
390  $this->setUpPassValidation();
391  $this->dependencyChecker->expects($this->once())
392  ->method('checkDependenciesWhenDisableModules')
393  ->willReturn(['Magento_A' => [], 'Magento_B' => []]);
394  $this->cache->expects($this->once())->method('clean');
395  $this->cleanupFiles->expects($this->once())->method('clearCodeGeneratedClasses');
396  }
397 
398  public function testExecute()
399  {
400  $input = ['module' => ['Magento_A', 'Magento_B']];
401  $this->setUpExecute();
402  $this->moduleUninstaller->expects($this->once())
403  ->method('uninstallCode')
404  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
405  $this->moduleRegistryUninstaller->expects($this->once())
406  ->method('removeModulesFromDb')
407  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
408  $this->moduleRegistryUninstaller->expects($this->once())
409  ->method('removeModulesFromDeploymentConfig')
410  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
411  $this->tester->execute($input);
412  }
413 
415  {
416  $input = ['module' => ['Magento_A', 'Magento_B'], '-c' => true];
417  $this->setUpExecute();
418  $this->moduleUninstaller->expects($this->once())
419  ->method('uninstallCode')
420  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
421  $this->moduleRegistryUninstaller->expects($this->once())
422  ->method('removeModulesFromDb')
423  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
424  $this->moduleRegistryUninstaller->expects($this->once())
425  ->method('removeModulesFromDeploymentConfig')
426  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
427  $this->cleanupFiles->expects($this->once())->method('clearMaterializedViewFiles');
428  $this->tester->execute($input);
429  }
430 
431  public function testExecuteRemoveData()
432  {
433  $input = ['module' => ['Magento_A', 'Magento_B'], '-r' => true];
434  $this->setUpExecute();
435  $this->moduleUninstaller->expects($this->once())
436  ->method('uninstallData')
437  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
438  $this->moduleUninstaller->expects($this->once())
439  ->method('uninstallCode')
440  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
441  $this->moduleRegistryUninstaller->expects($this->once())
442  ->method('removeModulesFromDb')
443  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
444  $this->moduleRegistryUninstaller->expects($this->once())
445  ->method('removeModulesFromDeploymentConfig')
446  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
447  $this->tester->execute($input);
448  }
449 
451  {
452  $this->deploymentConfig->expects(self::once())
453  ->method('isAvailable')
454  ->willReturn(true);
455  $input = ['module' => ['Magento_A'], '-c' => true, '-r' => true, '--non-composer' => true];
456  $this->patchApplierMock->expects(self::once())
457  ->method('revertDataPatches')
458  ->with('Magento_A');
459  self::assertEquals(0, $this->tester->execute($input));
460  }
461 
462  public function testExecuteAll()
463  {
464  $input = ['module' => ['Magento_A', 'Magento_B'], '-c' => true, '-r' => true];
465  $this->setUpExecute();
466  $this->moduleUninstaller->expects($this->once())
467  ->method('uninstallData')
468  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
469  $this->moduleUninstaller->expects($this->once())
470  ->method('uninstallCode')
471  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
472  $this->moduleRegistryUninstaller->expects($this->once())
473  ->method('removeModulesFromDb')
474  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
475  $this->moduleRegistryUninstaller->expects($this->once())
476  ->method('removeModulesFromDeploymentConfig')
477  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
478  $this->cleanupFiles->expects($this->once())->method('clearMaterializedViewFiles');
479  $this->tester->execute($input);
480  }
481 
482  public function testExecuteCodeBackup()
483  {
484  $input = ['module' => ['Magento_A', 'Magento_B'], '--backup-code' => true];
485  $this->setUpExecute();
486  $this->moduleUninstaller->expects($this->once())
487  ->method('uninstallCode')
488  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
489  $this->moduleRegistryUninstaller->expects($this->once())
490  ->method('removeModulesFromDb')
491  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
492  $this->moduleRegistryUninstaller->expects($this->once())
493  ->method('removeModulesFromDeploymentConfig')
494  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
495  $this->backupRollback->expects($this->once())
496  ->method('codeBackup')
497  ->willReturn($this->backupRollback);
498  $this->tester->execute($input);
499  }
500 
501  public function testExecuteMediaBackup()
502  {
503  $input = ['module' => ['Magento_A', 'Magento_B'], '--backup-media' => true];
504  $this->setUpExecute();
505  $this->moduleUninstaller->expects($this->once())
506  ->method('uninstallCode')
507  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
508  $this->moduleRegistryUninstaller->expects($this->once())
509  ->method('removeModulesFromDb')
510  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
511  $this->moduleRegistryUninstaller->expects($this->once())
512  ->method('removeModulesFromDeploymentConfig')
513  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
514  $this->backupRollback->expects($this->once())
515  ->method('codeBackup')
516  ->willReturn($this->backupRollback);
517  $this->tester->execute($input);
518  }
519 
520  public function testExecuteDBBackup()
521  {
522  $input = ['module' => ['Magento_A', 'Magento_B'], '--backup-db' => true];
523  $this->setUpExecute();
524  $this->moduleUninstaller->expects($this->once())
525  ->method('uninstallCode')
526  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
527  $this->moduleRegistryUninstaller->expects($this->once())
528  ->method('removeModulesFromDb')
529  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
530  $this->moduleRegistryUninstaller->expects($this->once())
531  ->method('removeModulesFromDeploymentConfig')
532  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
533  $this->backupRollback->expects($this->once())
534  ->method('dbBackup')
535  ->willReturn($this->backupRollback);
536  $this->tester->execute($input);
537  }
538 
539  public function testInteraction()
540  {
541  $input = ['module' => ['Magento_A', 'Magento_B']];
542  $this->setUpExecute();
543  $this->moduleUninstaller->expects($this->once())
544  ->method('uninstallCode')
545  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
546  $this->moduleRegistryUninstaller->expects($this->once())
547  ->method('removeModulesFromDb')
548  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
549  $this->moduleRegistryUninstaller->expects($this->once())
550  ->method('removeModulesFromDeploymentConfig')
551  ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $input['module']);
552  $this->question
553  ->expects($this->once())
554  ->method('ask')
555  ->will($this->returnValue(false));
556  $this->helperSet
557  ->expects($this->once())
558  ->method('get')
559  ->with('question')
560  ->will($this->returnValue($this->question));
561  $this->command->setHelperSet($this->helperSet);
562  $this->tester = new CommandTester($this->command);
563  $this->tester->execute($input);
564  }
565 }
$objectManager
Definition: bootstrap.php:17
$message
testExecuteFailedDependencies(array $dependencies, array $input, array $expect)
testExecuteFailedValidation(array $packageInfoMap, array $fullModuleListMap, array $input, array $expect)