diff --git a/app/code/Magento/SampleData/Console/Command/SampleDataDeployCommand.php b/app/code/Magento/SampleData/Console/Command/SampleDataDeployCommand.php index 158c588d113582756a03114fee0fbd24737ee0ff..88df47283133a2ceacf371b0d65cf730da1f346e 100644 --- a/app/code/Magento/SampleData/Console/Command/SampleDataDeployCommand.php +++ b/app/code/Magento/SampleData/Console/Command/SampleDataDeployCommand.php @@ -12,6 +12,7 @@ use Magento\Setup\Model\PackagesAuth; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; /** @@ -19,6 +20,8 @@ use Symfony\Component\Console\Output\OutputInterface; */ class SampleDataDeployCommand extends Command { + const OPTION_NO_UPDATE = 'no-update'; + /** * @var \Magento\Framework\Filesystem */ @@ -66,6 +69,12 @@ class SampleDataDeployCommand extends Command { $this->setName('sampledata:deploy') ->setDescription('Deploy sample data modules'); + $this->addOption( + self::OPTION_NO_UPDATE, + null, + InputOption::VALUE_NONE, + 'Update composer.json without executing composer update' + ); parent::configure(); } @@ -80,6 +89,9 @@ class SampleDataDeployCommand extends Command if (!empty($sampleDataPackages)) { $baseDir = $this->filesystem->getDirectoryRead(DirectoryList::ROOT)->getAbsolutePath(); $commonArgs = ['--working-dir' => $baseDir, '--no-progress' => 1]; + if ($input->getOption(self::OPTION_NO_UPDATE)) { + $commonArgs['--no-update'] = 1; + } $packages = []; foreach ($sampleDataPackages as $name => $version) { $packages[] = "$name:$version"; diff --git a/app/code/Magento/SampleData/Console/Command/SampleDataRemoveCommand.php b/app/code/Magento/SampleData/Console/Command/SampleDataRemoveCommand.php index 36f5c591bedc34e80ff895d02b9b869fd3f744f3..5e10b6c6e59302aad9c0994cbe88000d81547692 100644 --- a/app/code/Magento/SampleData/Console/Command/SampleDataRemoveCommand.php +++ b/app/code/Magento/SampleData/Console/Command/SampleDataRemoveCommand.php @@ -8,6 +8,7 @@ namespace Magento\SampleData\Console\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Magento\SampleData\Model\Dependency; use Symfony\Component\Console\Input\ArrayInput; @@ -22,6 +23,8 @@ use Composer\Console\ApplicationFactory; */ class SampleDataRemoveCommand extends Command { + const OPTION_NO_UPDATE = 'no-update'; + /** * @var Filesystem */ @@ -69,6 +72,12 @@ class SampleDataRemoveCommand extends Command { $this->setName('sampledata:remove') ->setDescription('Remove all sample data packages from composer.json'); + $this->addOption( + self::OPTION_NO_UPDATE, + null, + InputOption::VALUE_NONE, + 'Update composer.json without executing composer update' + ); parent::configure(); } @@ -81,6 +90,9 @@ class SampleDataRemoveCommand extends Command if (!empty($sampleDataPackages)) { $baseDir = $this->filesystem->getDirectoryRead(DirectoryList::ROOT)->getAbsolutePath(); $commonArgs = ['--working-dir' => $baseDir, '--no-interaction' => 1, '--no-progress' => 1]; + if ($input->getOption(self::OPTION_NO_UPDATE)) { + $commonArgs['--no-update'] = 1; + } $packages = array_keys($sampleDataPackages); $arguments = array_merge(['command' => 'remove', 'packages' => $packages], $commonArgs); $commandInput = new ArrayInput($arguments); diff --git a/app/code/Magento/SampleData/Test/Unit/Console/Command/AbstractSampleDataCommandTest.php b/app/code/Magento/SampleData/Test/Unit/Console/Command/AbstractSampleDataCommandTest.php new file mode 100644 index 0000000000000000000000000000000000000000..090bb4256f80723cf95a2bf3ffa31f3d76372ec9 --- /dev/null +++ b/app/code/Magento/SampleData/Test/Unit/Console/Command/AbstractSampleDataCommandTest.php @@ -0,0 +1,130 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\SampleData\Test\Unit\Console\Command; + +use Composer\Console\Application; +use Composer\Console\ApplicationFactory; +use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\Filesystem; +use Magento\Framework\Filesystem\Directory\ReadInterface; +use Magento\Framework\Filesystem\Directory\WriteInterface; +use Magento\SampleData\Model\Dependency; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\ArrayInputFactory; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +abstract class AbstractSampleDataCommandTest extends TestCase +{ + /** + * @var ReadInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $directoryReadMock; + + /** + * @var WriteInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $directoryWriteMock; + + /** + * @var Filesystem|\PHPUnit_Framework_MockObject_MockObject + */ + protected $filesystemMock; + + /** + * @var Dependency|\PHPUnit_Framework_MockObject_MockObject + */ + protected $sampleDataDependencyMock; + + /** + * @var ArrayInputFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $arrayInputFactoryMock; + + /** + * @var Application|\PHPUnit_Framework_MockObject_MockObject + */ + protected $applicationMock; + + /** + * @var ApplicationFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $applicationFactoryMock; + + /** + * @return void + */ + protected function setUp() + { + $this->directoryReadMock = $this->createMock(ReadInterface::class); + $this->directoryWriteMock = $this->createMock(WriteInterface::class); + $this->filesystemMock = $this->createMock(Filesystem::class); + $this->sampleDataDependencyMock = $this->createMock(Dependency::class); + $this->arrayInputFactoryMock = $this->createMock(ArrayInputFactory::class); + $this->applicationMock = $this->createMock(Application::class); + $this->applicationFactoryMock = $this->createPartialMock(ApplicationFactory::class, ['create']); + } + + /** + * @param array $sampleDataPackages Array in form [package_name => version_constraint] + * @param string $pathToComposerJson Fake path to composer.json + * @param int $appRunResult Composer exit code + * @param array $additionalComposerArgs Additional arguments that composer expects + */ + protected function setupMocks( + $sampleDataPackages, + $pathToComposerJson, + $appRunResult, + $additionalComposerArgs = [] + ) { + $this->directoryReadMock->expects($this->any())->method('getAbsolutePath')->willReturn($pathToComposerJson); + $this->filesystemMock->expects($this->any())->method('getDirectoryRead')->with(DirectoryList::ROOT)->willReturn( + $this->directoryReadMock + ); + $this->sampleDataDependencyMock->expects($this->any())->method('getSampleDataPackages')->willReturn( + $sampleDataPackages + ); + $this->arrayInputFactoryMock->expects($this->never())->method('create'); + + $this->applicationMock->expects($this->any()) + ->method('run') + ->with( + new ArrayInput( + array_merge( + $this->expectedComposerArguments( + $sampleDataPackages, + $pathToComposerJson + ), + $additionalComposerArgs + ) + ), + $this->anything() + ) + ->willReturn($appRunResult); + + if (($appRunResult !== 0) && !empty($sampleDataPackages)) { + $this->applicationMock->expects($this->once())->method('resetComposer')->willReturnSelf(); + } + + $this->applicationFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($this->applicationMock); + } + + /** + * Expected arguments for composer based on sample data packages and composer.json path + * + * @param array $sampleDataPackages + * @param string $pathToComposerJson + * @return array + */ + abstract protected function expectedComposerArguments( + array $sampleDataPackages, + string $pathToComposerJson + ) : array; +} diff --git a/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataDeployCommandTest.php b/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataDeployCommandTest.php index 464a6c9ccd832921c8e781225c306efa55ab6d5a..450b2d8798f52491bfd8976f609c343fda18037d 100644 --- a/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataDeployCommandTest.php +++ b/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataDeployCommandTest.php @@ -9,66 +9,26 @@ use Magento\Framework\App\Filesystem\DirectoryList; use Magento\SampleData\Console\Command\SampleDataDeployCommand; use Magento\Setup\Model\PackagesAuth; use Symfony\Component\Console\Tester\CommandTester; -use Magento\Framework\Filesystem; -use Magento\Framework\Filesystem\Directory\ReadInterface; -use Magento\Framework\Filesystem\Directory\WriteInterface; -use Magento\SampleData\Model\Dependency; -use Symfony\Component\Console\Input\ArrayInputFactory; -use Composer\Console\ApplicationFactory; -use Composer\Console\Application; -/** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class SampleDataDeployCommandTest extends \PHPUnit\Framework\TestCase +class SampleDataDeployCommandTest extends AbstractSampleDataCommandTest { /** - * @var ReadInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $directoryReadMock; - - /** - * @var WriteInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $directoryWriteMock; - - /** - * @var Filesystem|\PHPUnit_Framework_MockObject_MockObject - */ - private $filesystemMock; - - /** - * @var Dependency|\PHPUnit_Framework_MockObject_MockObject - */ - private $sampleDataDependencyMock; - - /** - * @var ArrayInputFactory|\PHPUnit_Framework_MockObject_MockObject - */ - private $arrayInputFactoryMock; - - /** - * @var Application|\PHPUnit_Framework_MockObject_MockObject - */ - private $applicationMock; - - /** - * @var ApplicationFactory|\PHPUnit_Framework_MockObject_MockObject + * @param bool $authExist True to test with existing auth.json, false without */ - private $applicationFactoryMock; - - /** - * @return void - */ - protected function setUp() + protected function setupMocksForAuthFile($authExist) { - $this->directoryReadMock = $this->createMock(ReadInterface::class); - $this->directoryWriteMock = $this->createMock(WriteInterface::class); - $this->filesystemMock = $this->createMock(Filesystem::class); - $this->sampleDataDependencyMock = $this->createMock(Dependency::class); - $this->arrayInputFactoryMock = $this->createMock(ArrayInputFactory::class); - $this->applicationMock = $this->createMock(Application::class); - $this->applicationFactoryMock = $this->createPartialMock(ApplicationFactory::class, ['create']); + $this->directoryWriteMock->expects($this->once()) + ->method('isExist') + ->with(PackagesAuth::PATH_TO_AUTH_FILE) + ->willReturn($authExist); + $this->directoryWriteMock->expects($authExist ? $this->never() : $this->once())->method('writeFile')->with( + PackagesAuth::PATH_TO_AUTH_FILE, + '{}' + ); + $this->filesystemMock->expects($this->once()) + ->method('getDirectoryWrite') + ->with(DirectoryList::COMPOSER_HOME) + ->willReturn($this->directoryWriteMock); } /** @@ -82,68 +42,36 @@ class SampleDataDeployCommandTest extends \PHPUnit\Framework\TestCase */ public function testExecute(array $sampleDataPackages, $appRunResult, $expectedMsg, $authExist) { - $pathToComposerJson = '/path/to/composer.json'; - - $this->directoryReadMock->expects($this->any()) - ->method('getAbsolutePath') - ->willReturn($pathToComposerJson); - $this->directoryWriteMock->expects($this->once()) - ->method('isExist') - ->with(PackagesAuth::PATH_TO_AUTH_FILE) - ->willReturn($authExist); - $this->directoryWriteMock->expects($authExist ? $this->never() : $this->once()) - ->method('writeFile') - ->with(PackagesAuth::PATH_TO_AUTH_FILE, '{}'); - $this->filesystemMock->expects($this->any()) - ->method('getDirectoryRead') - ->with(DirectoryList::ROOT) - ->willReturn($this->directoryReadMock); - $this->filesystemMock->expects($this->once()) - ->method('getDirectoryWrite') - ->with(DirectoryList::COMPOSER_HOME) - ->willReturn($this->directoryWriteMock); - $this->sampleDataDependencyMock->expects($this->any()) - ->method('getSampleDataPackages') - ->willReturn($sampleDataPackages); - $this->arrayInputFactoryMock->expects($this->never()) - ->method('create'); - - array_walk($sampleDataPackages, function (&$v, $k) { - $v = "$k:$v"; - }); - - $packages = array_values($sampleDataPackages); - - $requireArgs = [ - 'command' => 'require', - '--working-dir' => $pathToComposerJson, - '--no-progress' => 1, - 'packages' => $packages, - ]; - $commandInput = new \Symfony\Component\Console\Input\ArrayInput($requireArgs); - - $this->applicationMock->expects($this->any()) - ->method('run') - ->with($commandInput, $this->anything()) - ->willReturn($appRunResult); - - if (($appRunResult !== 0) && !empty($sampleDataPackages)) { - $this->applicationMock->expects($this->once())->method('resetComposer')->willReturnSelf(); - } + $this->setupMocks($sampleDataPackages, '/path/to/composer.json', $appRunResult); + $this->setupMocksForAuthFile($authExist); + $commandTester = $this->createCommandTester(); + $commandTester->execute([]); - $this->applicationFactoryMock->expects($this->any()) - ->method('create') - ->willReturn($this->applicationMock); + $this->assertEquals($expectedMsg, $commandTester->getDisplay()); + } - $commandTester = new CommandTester( - new SampleDataDeployCommand( - $this->filesystemMock, - $this->sampleDataDependencyMock, - $this->arrayInputFactoryMock, - $this->applicationFactoryMock - ) + /** + * @param array $sampleDataPackages + * @param int $appRunResult - int 0 if everything went fine, or an error code + * @param string $expectedMsg + * @param bool $authExist + * @return void + * + * @dataProvider processDataProvider + */ + public function testExecuteWithNoUpdate(array $sampleDataPackages, $appRunResult, $expectedMsg, $authExist) + { + $this->setupMocks( + $sampleDataPackages, + '/path/to/composer.json', + $appRunResult, + ['--no-update' => 1] ); - $commandTester->execute([]); + $this->setupMocksForAuthFile($authExist); + $commandInput = ['--no-update' => 1]; + + $commandTester = $this->createCommandTester(); + $commandTester->execute($commandInput); $this->assertEquals($expectedMsg, $commandTester->getDisplay()); } @@ -154,13 +82,13 @@ class SampleDataDeployCommandTest extends \PHPUnit\Framework\TestCase public function processDataProvider() { return [ - [ + 'No sample data found' => [ 'sampleDataPackages' => [], 'appRunResult' => 1, 'expectedMsg' => 'There is no sample data for current set of modules.' . PHP_EOL, 'authExist' => true, ], - [ + 'No auth.json found' => [ 'sampleDataPackages' => [ 'magento/module-cms-sample-data' => '1.0.0-beta', ], @@ -169,7 +97,7 @@ class SampleDataDeployCommandTest extends \PHPUnit\Framework\TestCase . PHP_EOL, 'authExist' => false, ], - [ + 'Successful sample data installation' => [ 'sampleDataPackages' => [ 'magento/module-cms-sample-data' => '1.0.0-beta', ], @@ -204,6 +132,14 @@ class SampleDataDeployCommandTest extends \PHPUnit\Framework\TestCase ->with(DirectoryList::COMPOSER_HOME) ->willReturn($this->directoryWriteMock); + $this->createCommandTester()->execute([]); + } + + /** + * @return CommandTester + */ + private function createCommandTester(): CommandTester + { $commandTester = new CommandTester( new SampleDataDeployCommand( $this->filesystemMock, @@ -212,6 +148,36 @@ class SampleDataDeployCommandTest extends \PHPUnit\Framework\TestCase $this->applicationFactoryMock ) ); - $commandTester->execute([]); + return $commandTester; + } + + /** + * @param $sampleDataPackages + * @param $pathToComposerJson + * @return array + */ + protected function expectedComposerArguments( + array $sampleDataPackages, + string $pathToComposerJson + ) : array { + return [ + 'command' => 'require', + '--working-dir' => $pathToComposerJson, + '--no-progress' => 1, + 'packages' => $this->packageVersionStrings($sampleDataPackages), + ]; + } + + /** + * @param array $sampleDataPackages + * @return array + */ + private function packageVersionStrings(array $sampleDataPackages): array + { + array_walk($sampleDataPackages, function (&$v, $k) { + $v = "$k:$v"; + }); + + return array_values($sampleDataPackages); } } diff --git a/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataRemoveCommandTest.php b/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataRemoveCommandTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7fce70fd9c3764acaf37c6106519d2e10add7832 --- /dev/null +++ b/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataRemoveCommandTest.php @@ -0,0 +1,109 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\SampleData\Test\Unit\Console\Command; + +use Magento\SampleData\Console\Command\SampleDataRemoveCommand; +use Symfony\Component\Console\Tester\CommandTester; + +class SampleDataRemoveCommandTest extends AbstractSampleDataCommandTest +{ + + /** + * @param array $sampleDataPackages + * @param int $appRunResult - int 0 if everything went fine, or an error code + * @param string $expectedMsg + * @return void + * + * @dataProvider processDataProvider + */ + public function testExecute(array $sampleDataPackages, $appRunResult, $expectedMsg) + { + $this->setupMocks($sampleDataPackages, '/path/to/composer.json', $appRunResult); + $commandTester = $this->createCommandTester(); + $commandTester->execute([]); + + $this->assertEquals($expectedMsg, $commandTester->getDisplay()); + } + + /** + * @param array $sampleDataPackages + * @param int $appRunResult - int 0 if everything went fine, or an error code + * @param string $expectedMsg + * @return void + * + * @dataProvider processDataProvider + */ + public function testExecuteWithNoUpdate(array $sampleDataPackages, $appRunResult, $expectedMsg) + { + $this->setupMocks( + $sampleDataPackages, + '/path/to/composer.json', + $appRunResult, + ['--no-update' => 1] + ); + $commandInput = ['--no-update' => 1]; + + $commandTester = $this->createCommandTester(); + $commandTester->execute($commandInput); + + $this->assertEquals($expectedMsg, $commandTester->getDisplay()); + } + + /** + * @return array + */ + public function processDataProvider() + { + return [ + 'No sample data found' => [ + 'sampleDataPackages' => [], + 'appRunResult' => 1, + 'expectedMsg' => 'There is no sample data for current set of modules.' . PHP_EOL, + ], + 'Successful sample data installation' => [ + 'sampleDataPackages' => [ + 'magento/module-cms-sample-data' => '1.0.0-beta', + ], + 'appRunResult' => 0, + 'expectedMsg' => '', + ], + ]; + } + + /** + * @return CommandTester + */ + private function createCommandTester(): CommandTester + { + $commandTester = new CommandTester( + new SampleDataRemoveCommand( + $this->filesystemMock, + $this->sampleDataDependencyMock, + $this->arrayInputFactoryMock, + $this->applicationFactoryMock + ) + ); + return $commandTester; + } + + /** + * @param $sampleDataPackages + * @param $pathToComposerJson + * @return array + */ + protected function expectedComposerArguments( + array $sampleDataPackages, + string $pathToComposerJson + ) : array { + return [ + 'command' => 'remove', + '--working-dir' => $pathToComposerJson, + '--no-interaction' => 1, + '--no-progress' => 1, + 'packages' => array_keys($sampleDataPackages), + ]; + } +}