ThemeUninstallCommandTest.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Theme\Test\Unit\Console\Command;
  7. use Magento\Framework\App\Console\MaintenanceModeEnabler;
  8. use Magento\Theme\Console\Command\ThemeUninstallCommand;
  9. use Magento\Theme\Model\Theme\ThemePackageInfo;
  10. use Magento\Theme\Model\Theme\ThemeUninstaller;
  11. use Magento\Theme\Model\Theme\ThemeDependencyChecker;
  12. use Symfony\Component\Console\Tester\CommandTester;
  13. use Magento\Framework\Setup\BackupRollbackFactory;
  14. /**
  15. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  16. */
  17. class ThemeUninstallCommandTest extends \PHPUnit\Framework\TestCase
  18. {
  19. /**
  20. * @var \Magento\Framework\App\MaintenanceMode|\PHPUnit_Framework_MockObject_MockObject
  21. */
  22. private $maintenanceMode;
  23. /**
  24. * @var \Magento\Framework\Composer\DependencyChecker|\PHPUnit_Framework_MockObject_MockObject
  25. */
  26. private $dependencyChecker;
  27. /**
  28. * @var \Magento\Theme\Model\Theme\Data\Collection|\PHPUnit_Framework_MockObject_MockObject
  29. */
  30. private $collection;
  31. /**
  32. * @var \Magento\Framework\App\Cache|\PHPUnit_Framework_MockObject_MockObject
  33. */
  34. private $cache;
  35. /**
  36. * @var \Magento\Framework\App\State\CleanupFiles|\PHPUnit_Framework_MockObject_MockObject
  37. */
  38. private $cleanupFiles;
  39. /**
  40. * @var ThemeUninstallCommand
  41. */
  42. private $command;
  43. /**
  44. * @var BackupRollbackFactory|\PHPUnit_Framework_MockObject_MockObject
  45. */
  46. private $backupRollbackFactory;
  47. /**
  48. * Theme Validator
  49. *
  50. * @var \Magento\Theme\Model\ThemeValidator|\PHPUnit_Framework_MockObject_MockObject
  51. */
  52. private $themeValidator;
  53. /**
  54. * @var ThemeUninstaller|\PHPUnit_Framework_MockObject_MockObject
  55. */
  56. private $themeUninstaller;
  57. /**
  58. * @var ThemeDependencyChecker|\PHPUnit_Framework_MockObject_MockObject
  59. */
  60. private $themeDependencyChecker;
  61. /**
  62. * @var ThemePackageInfo|\PHPUnit_Framework_MockObject_MockObject
  63. */
  64. private $themePackageInfo;
  65. /**
  66. * @var CommandTester
  67. */
  68. private $tester;
  69. protected function setUp()
  70. {
  71. $this->maintenanceMode = $this->createMock(\Magento\Framework\App\MaintenanceMode::class);
  72. $composerInformation = $this->createMock(\Magento\Framework\Composer\ComposerInformation::class);
  73. $composerInformation->expects($this->any())
  74. ->method('getRootRequiredPackages')
  75. ->willReturn(['magento/theme-a', 'magento/theme-b', 'magento/theme-c']);
  76. $this->dependencyChecker = $this->createMock(\Magento\Framework\Composer\DependencyChecker::class);
  77. $this->collection = $this->createMock(\Magento\Theme\Model\Theme\Data\Collection::class);
  78. $this->cache = $this->createMock(\Magento\Framework\App\Cache::class);
  79. $this->cleanupFiles = $this->createMock(\Magento\Framework\App\State\CleanupFiles::class);
  80. $this->backupRollbackFactory = $this->createMock(\Magento\Framework\Setup\BackupRollbackFactory::class);
  81. $this->themeValidator = $this->createMock(\Magento\Theme\Model\ThemeValidator::class);
  82. $this->themeUninstaller = $this->createMock(\Magento\Theme\Model\Theme\ThemeUninstaller::class);
  83. $this->themeDependencyChecker = $this->createMock(\Magento\Theme\Model\Theme\ThemeDependencyChecker::class);
  84. $this->themePackageInfo = $this->createMock(\Magento\Theme\Model\Theme\ThemePackageInfo::class);
  85. $this->command = new ThemeUninstallCommand(
  86. $this->cache,
  87. $this->cleanupFiles,
  88. $composerInformation,
  89. $this->maintenanceMode,
  90. $this->dependencyChecker,
  91. $this->collection,
  92. $this->backupRollbackFactory,
  93. $this->themeValidator,
  94. $this->themePackageInfo,
  95. $this->themeUninstaller,
  96. $this->themeDependencyChecker,
  97. new MaintenanceModeEnabler($this->maintenanceMode)
  98. );
  99. $this->tester = new CommandTester($this->command);
  100. }
  101. public function testExecuteFailedValidationNotPackage()
  102. {
  103. $this->themePackageInfo->expects($this->at(0))->method('getPackageName')->willReturn('dummy');
  104. $this->themePackageInfo->expects($this->at(1))->method('getPackageName')->willReturn('magento/theme-a');
  105. $this->collection->expects($this->any())
  106. ->method('getThemeByFullPath')
  107. ->willReturn(
  108. $this->getMockForAbstractClass(
  109. \Magento\Framework\View\Design\ThemeInterface::class,
  110. [],
  111. '',
  112. false
  113. )
  114. );
  115. $this->collection->expects($this->any())->method('hasTheme')->willReturn(true);
  116. $this->tester->execute(['theme' => ['area/vendor/test1', 'area/vendor/test2']]);
  117. $this->assertContains(
  118. 'test1 is not an installed Composer package',
  119. $this->tester->getDisplay()
  120. );
  121. $this->assertNotContains(
  122. 'test2 is not an installed Composer package',
  123. $this->tester->getDisplay()
  124. );
  125. }
  126. public function testExecuteFailedValidationNotTheme()
  127. {
  128. $this->themePackageInfo->expects($this->exactly(2))->method('getPackageName')->willReturn('');
  129. $this->collection->expects($this->any())
  130. ->method('getThemeByFullPath')
  131. ->willReturn(
  132. $this->getMockForAbstractClass(
  133. \Magento\Framework\View\Design\ThemeInterface::class,
  134. [],
  135. '',
  136. false
  137. )
  138. );
  139. $this->collection->expects($this->any())->method('hasTheme')->willReturn(false);
  140. $this->tester->execute(['theme' => ['area/vendor/test1', 'area/vendor/test2']]);
  141. $this->assertContains(
  142. 'Unknown theme(s): area/vendor/test1, area/vendor/test2' . PHP_EOL,
  143. $this->tester->getDisplay()
  144. );
  145. }
  146. public function testExecuteFailedValidationMixed()
  147. {
  148. $this->themePackageInfo->expects($this->exactly(4))
  149. ->method('getPackageName')
  150. ->will($this->returnValueMap([
  151. ['area/vendor/test1', 'dummy1'],
  152. ['area/vendor/test2', 'magento/theme-b'],
  153. ['area/vendor/test3', ''],
  154. ['area/vendor/test4', 'dummy2'],
  155. ]));
  156. $this->collection->expects($this->any())
  157. ->method('getThemeByFullPath')
  158. ->willReturn(
  159. $this->getMockForAbstractClass(
  160. \Magento\Framework\View\Design\ThemeInterface::class,
  161. [],
  162. '',
  163. false
  164. )
  165. );
  166. $this->collection->expects($this->at(1))->method('hasTheme')->willReturn(true);
  167. $this->collection->expects($this->at(3))->method('hasTheme')->willReturn(true);
  168. $this->collection->expects($this->at(5))->method('hasTheme')->willReturn(false);
  169. $this->collection->expects($this->at(7))->method('hasTheme')->willReturn(true);
  170. $this->tester->execute([
  171. 'theme' => [
  172. 'area/vendor/test1',
  173. 'area/vendor/test2',
  174. 'area/vendor/test3',
  175. 'area/vendor/test4',
  176. ],
  177. ]);
  178. $this->assertContains(
  179. 'area/vendor/test1, area/vendor/test4 are not installed Composer packages',
  180. $this->tester->getDisplay()
  181. );
  182. $this->assertNotContains(
  183. 'area/vendor/test2 is not an installed Composer package',
  184. $this->tester->getDisplay()
  185. );
  186. $this->assertContains(
  187. 'Unknown theme(s): area/vendor/test3' . PHP_EOL,
  188. $this->tester->getDisplay()
  189. );
  190. }
  191. public function setUpPassValidation()
  192. {
  193. $this->themePackageInfo->expects($this->any())->method('getPackageName')->willReturn('magento/theme-a');
  194. $this->collection->expects($this->any())
  195. ->method('getThemeByFullPath')
  196. ->willReturn(
  197. $this->getMockForAbstractClass(
  198. \Magento\Framework\View\Design\ThemeInterface::class,
  199. [],
  200. '',
  201. false
  202. )
  203. );
  204. $this->themeDependencyChecker->expects($this->any())->method('checkChildTheme')->willReturn([]);
  205. $this->collection->expects($this->any())->method('hasTheme')->willReturn(true);
  206. }
  207. public function setupPassChildThemeCheck()
  208. {
  209. $theme = $this->createMock(\Magento\Theme\Model\Theme::class);
  210. $theme->expects($this->any())->method('hasChildThemes')->willReturn(false);
  211. $this->collection->expects($this->any())->method('getIterator')->willReturn(new \ArrayIterator([]));
  212. }
  213. public function setupPassThemeInUseCheck()
  214. {
  215. $this->themeValidator->expects($this->once())->method('validateIsThemeInUse')->willReturn([]);
  216. }
  217. public function setupPassDependencyCheck()
  218. {
  219. $this->dependencyChecker->expects($this->once())->method('checkDependencies')->willReturn([]);
  220. }
  221. public function testExecuteFailedThemeInUseCheck()
  222. {
  223. $this->setUpPassValidation();
  224. $this->setupPassChildThemeCheck();
  225. $this->setupPassDependencyCheck();
  226. $this->themeValidator
  227. ->expects($this->once())
  228. ->method('validateIsThemeInUse')
  229. ->willReturn(['frontend/Magento/a is in use in default config']);
  230. $this->tester->execute(['theme' => ['frontend/Magento/a']]);
  231. $this->assertEquals(
  232. 'Unable to uninstall. Please resolve the following issues:' . PHP_EOL
  233. . 'frontend/Magento/a is in use in default config' . PHP_EOL,
  234. $this->tester->getDisplay()
  235. );
  236. }
  237. public function testExecuteFailedDependencyCheck()
  238. {
  239. $this->setUpPassValidation();
  240. $this->setupPassThemeInUseCheck();
  241. $this->setupPassChildThemeCheck();
  242. $this->dependencyChecker->expects($this->once())
  243. ->method('checkDependencies')
  244. ->willReturn(['magento/theme-a' => ['magento/theme-b', 'magento/theme-c']]);
  245. $this->tester->execute(['theme' => ['frontend/Magento/a']]);
  246. $this->assertContains(
  247. 'Unable to uninstall. Please resolve the following issues:' . PHP_EOL .
  248. 'frontend/Magento/a has the following dependent package(s):'
  249. . PHP_EOL . "\tmagento/theme-b" . PHP_EOL . "\tmagento/theme-c",
  250. $this->tester->getDisplay()
  251. );
  252. }
  253. public function setUpExecute()
  254. {
  255. $this->setUpPassValidation();
  256. $this->setupPassThemeInUseCheck();
  257. $this->setupPassChildThemeCheck();
  258. $this->setupPassDependencyCheck();
  259. $this->cache->expects($this->once())->method('clean');
  260. $this->themeUninstaller->expects($this->once())
  261. ->method('uninstallRegistry')
  262. ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $this->anything());
  263. $this->themeUninstaller->expects($this->once())
  264. ->method('uninstallCode')
  265. ->with($this->isInstanceOf(\Symfony\Component\Console\Output\OutputInterface::class), $this->anything());
  266. }
  267. public function testExecuteWithBackupCode()
  268. {
  269. $this->setUpExecute();
  270. $backupRollback = $this->createMock(\Magento\Framework\Setup\BackupRollback::class);
  271. $this->backupRollbackFactory->expects($this->once())
  272. ->method('create')
  273. ->willReturn($backupRollback);
  274. $this->tester->execute(['theme' => ['area/vendor/test'], '--backup-code' => true]);
  275. $this->tester->getDisplay();
  276. }
  277. public function testExecute()
  278. {
  279. $this->setUpExecute();
  280. $this->cleanupFiles->expects($this->never())->method('clearMaterializedViewFiles');
  281. $this->tester->execute(['theme' => ['area/vendor/test']]);
  282. $this->assertContains('Enabling maintenance mode', $this->tester->getDisplay());
  283. $this->assertContains('Disabling maintenance mode', $this->tester->getDisplay());
  284. $this->assertContains('Alert: Generated static view files were not cleared.', $this->tester->getDisplay());
  285. $this->assertNotContains('Generated static view files cleared successfully', $this->tester->getDisplay());
  286. }
  287. public function testExecuteCleanStaticFiles()
  288. {
  289. $this->setUpExecute();
  290. $this->cleanupFiles->expects($this->once())->method('clearMaterializedViewFiles');
  291. $this->tester->execute(['theme' => ['area/vendor/test'], '-c' => true]);
  292. $this->assertContains('Enabling maintenance mode', $this->tester->getDisplay());
  293. $this->assertContains('Disabling maintenance mode', $this->tester->getDisplay());
  294. $this->assertNotContains('Alert: Generated static view files were not cleared.', $this->tester->getDisplay());
  295. $this->assertContains('Generated static view files cleared successfully', $this->tester->getDisplay());
  296. }
  297. /**
  298. * @param $themePath
  299. * @dataProvider dataProviderThemeFormat
  300. */
  301. public function testExecuteWrongThemeFormat($themePath)
  302. {
  303. $this->tester->execute(['theme' => [$themePath]]);
  304. $this->assertContains(
  305. 'Theme path should be specified as full path which is area/vendor/name.',
  306. $this->tester->getDisplay()
  307. );
  308. }
  309. /**
  310. * @return array
  311. */
  312. public function dataProviderThemeFormat()
  313. {
  314. return [
  315. ['test1'],
  316. ['/test1'],
  317. ['test1/'],
  318. ['/test1/'],
  319. ['vendor/test1'],
  320. ['/vendor/test1'],
  321. ['vendor/test1/'],
  322. ['/vendor/test1/'],
  323. ['area/vendor/test1/'],
  324. ['/area/vendor/test1'],
  325. ];
  326. }
  327. }