diff --git a/composer.json b/composer.json index 168ae6d75d..f91b784606 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/ece-tools", "description": "Provides tools to build and deploy Magento 2 Enterprise Edition", "type": "magento2-component", - "version": "2002.1.10", + "version": "2002.1.11", "license": "OSL-3.0", "repositories": { "repo.magento.com": { diff --git a/src/Command/Dev/GenerateSchemaError.php b/src/Command/Dev/GenerateSchemaError.php index ca0c439b8c..f33ba04376 100644 --- a/src/Command/Dev/GenerateSchemaError.php +++ b/src/Command/Dev/GenerateSchemaError.php @@ -7,6 +7,7 @@ namespace Magento\MagentoCloud\Command\Dev; +use Magento\MagentoCloud\Cli; use Magento\MagentoCloud\Filesystem\Driver\File; use Magento\MagentoCloud\Filesystem\FileList; use Symfony\Component\Console\Command\Command; @@ -79,14 +80,11 @@ protected function configure(): void } /** - * @param InputInterface $input - * @param OutputInterface $output - * @return int|void - * @throws \Magento\MagentoCloud\Filesystem\FileSystemException + * @inheritdoc * * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $errors = Yaml::parse( $this->file->fileGetContents($this->fileList->getErrorSchema()), @@ -100,6 +98,8 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->file->filePutContents($this->fileList->getErrorDistConfig(), $docs); $output->writeln(sprintf('File %s was generated', $this->fileList->getErrorDistConfig())); + + return Cli::SUCCESS; } /** diff --git a/src/Command/Dev/UpdateComposer.php b/src/Command/Dev/UpdateComposer.php index ddbc2f036b..d12d3054a4 100644 --- a/src/Command/Dev/UpdateComposer.php +++ b/src/Command/Dev/UpdateComposer.php @@ -108,12 +108,23 @@ protected function execute(InputInterface $input, OutputInterface $output): int { $gitOptions = $this->globalSection->get(GlobalSection::VAR_DEPLOY_FROM_GIT_OPTIONS); - $scripts = $this->composerGenerator->getInstallFromGitScripts($gitOptions['repositories']); - foreach (array_slice($scripts, 1) as $script) { + $InstallFromGitScripts = $this->composerGenerator->getInstallFromGitScripts($gitOptions['repositories']); + foreach (array_slice($InstallFromGitScripts, 1) as $script) { $this->shell->execute($script); } - $composer = $this->composerGenerator->generate($gitOptions['repositories']); + // Preparing framework modules for installation + $frameworkPreparationScript = $this->composerGenerator->getFrameworkPreparationScript( + array_keys($gitOptions['repositories']) + ); + foreach ($frameworkPreparationScript as $script) { + $this->shell->execute($script); + } + + $composer = $this->composerGenerator->generate( + $gitOptions['repositories'], + array_merge($InstallFromGitScripts, $frameworkPreparationScript) + ); if (!empty($gitOptions['clear_magento_module_requirements'])) { $clearRequirementsScript = $this->clearModuleRequirements->generate(); diff --git a/src/Command/Dev/UpdateComposer/ComposerGenerator.php b/src/Command/Dev/UpdateComposer/ComposerGenerator.php index 2800fd0627..ed8af3b054 100644 --- a/src/Command/Dev/UpdateComposer/ComposerGenerator.php +++ b/src/Command/Dev/UpdateComposer/ComposerGenerator.php @@ -69,13 +69,14 @@ public function __construct( * Generates composer.json data for installation from git. * * @param array $repoOptions + * @param array $installFromGitScripts * @return array * @throws FileSystemException * @codeCoverageIgnore */ - public function generate(array $repoOptions): array + public function generate(array $repoOptions, array $installFromGitScripts): array { - $composer = $this->getBaseComposer($repoOptions); + $composer = $this->getBaseComposer($installFromGitScripts); $rootComposerJsonPath = $this->directoryList->getMagentoRoot() . '/composer.json'; if ($this->file->isExists($rootComposerJsonPath)) { @@ -162,15 +163,39 @@ public function getInstallFromGitScripts(array $repoOptions): array return $installFromGitScripts; } + /** + * @param array $repoNames + * @return array + * @throws FileSystemException + */ + public function getFrameworkPreparationScript(array $repoNames): array + { + $script = []; + + foreach ($repoNames as $repoName) { + $path = $repoName . '/lib/internal/Magento/Framework'; + $absolutePath = $this->directoryList->getMagentoRoot() . '/' .$path; + + if ($this->file->isExists($absolutePath)) { + foreach ($this->findPackages($absolutePath) as $package) { + if ($package) { + $script[] = 'mv ' . $path . '/' . $package . ' ' . $path . '-' . $package; + } + } + } + } + + return $script; + } + /** * Returns base skeleton for composer.json. * - * @param array $repoOptions + * @param array $installFromGitScripts * @return array */ - private function getBaseComposer(array $repoOptions): array + private function getBaseComposer(array $installFromGitScripts): array { - $installFromGitScripts = $this->getInstallFromGitScripts($repoOptions); $composer = [ 'name' => 'magento/cloud-dev', 'description' => 'eCommerce Platform for Growth', @@ -188,6 +213,11 @@ private function getBaseComposer(array $repoOptions): array ], 'config' => [ 'use-include-path' => true, + 'allow-plugins' => [ + 'dealerdirect/phpcodesniffer-composer-installer' => true, + 'laminas/laminas-dependency-plugin' => true, + 'magento/*' => true + ] ], 'autoload' => [ 'psr-4' => [ @@ -200,6 +230,11 @@ private function getBaseComposer(array $repoOptions): array 'extra' => [ 'magento-force' => 'override', 'magento-deploystrategy' => 'copy', + 'magento-deploy-ignore' => [ + '*' => [ + '/.gitignore' + ] + ] ], 'scripts' => [ 'install-from-git' => $installFromGitScripts, diff --git a/src/Step/Deploy/InstallUpdate/ConfigUpdate/Amqp/Config.php b/src/Config/Amqp.php similarity index 91% rename from src/Step/Deploy/InstallUpdate/ConfigUpdate/Amqp/Config.php rename to src/Config/Amqp.php index a86540dcb7..01946b7ade 100644 --- a/src/Step/Deploy/InstallUpdate/ConfigUpdate/Amqp/Config.php +++ b/src/Config/Amqp.php @@ -5,9 +5,8 @@ */ declare(strict_types=1); -namespace Magento\MagentoCloud\Step\Deploy\InstallUpdate\ConfigUpdate\Amqp; +namespace Magento\MagentoCloud\Config; -use Magento\MagentoCloud\Config\ConfigMerger; use Magento\MagentoCloud\Config\Stage\DeployInterface; use Magento\MagentoCloud\Service\RabbitMq; use Magento\MagentoCloud\Package\MagentoVersion; @@ -15,7 +14,7 @@ /** * Returns queue configuration. */ -class Config +class Amqp { /** * @var RabbitMq @@ -61,9 +60,9 @@ public function __construct( * @return array * @throws \Magento\MagentoCloud\Package\UndefinedPackageException */ - public function get(): array + public function getConfig(): array { - $config = $this->getConfig(); + $config = $this->getMergedConfig(); if ($this->magentoVersion->isGreaterOrEqual('2.2')) { $config['consumers_wait_for_messages'] = $this->stageConfig->get( @@ -79,7 +78,7 @@ public function get(): array * * @return array */ - private function getConfig(): array + private function getMergedConfig(): array { $envQueueConfig = $this->stageConfig->get(DeployInterface::VAR_QUEUE_CONFIGURATION); $mqConfig = $this->getAmqpConfig(); diff --git a/src/Config/Validator/Deploy/ElasticSuiteIntegrity.php b/src/Config/Validator/Deploy/ElasticSuiteIntegrity.php index bc045e2949..f66d508b84 100644 --- a/src/Config/Validator/Deploy/ElasticSuiteIntegrity.php +++ b/src/Config/Validator/Deploy/ElasticSuiteIntegrity.php @@ -15,6 +15,7 @@ use Magento\MagentoCloud\Config\ValidatorException; use Magento\MagentoCloud\Config\ValidatorInterface; use Magento\MagentoCloud\Service\ElasticSearch; +use Magento\MagentoCloud\Service\OpenSearch; /** * Validates different aspects of ElasticSuite's configuration. @@ -31,6 +32,11 @@ class ElasticSuiteIntegrity implements ValidatorInterface */ private $elasticSearch; + /** + * @var OpenSearch + */ + private $openSearch; + /** * @var Validator\ResultFactory */ @@ -44,24 +50,27 @@ class ElasticSuiteIntegrity implements ValidatorInterface /** * @param ElasticSuite $elasticSuite * @param ElasticSearch $elasticSearch + * @param OpenSearch $openSearch * @param Validator\ResultFactory $resultFactory * @param DeployInterface $config */ public function __construct( ElasticSuite $elasticSuite, ElasticSearch $elasticSearch, + OpenSearch $openSearch, Validator\ResultFactory $resultFactory, DeployInterface $config ) { $this->elasticSuite = $elasticSuite; $this->elasticSearch = $elasticSearch; + $this->openSearch = $openSearch; $this->resultFactory = $resultFactory; $this->config = $config; } /** * If ElasticSuite is absent - skip validation. - * If ElasticSuite is present and no ElasticSearch connection - fail validation. + * If ElasticSuite is present and no ElasticSearch or OpenSearch connection - fail validation. * If search engine is manually set to non-ElasticSuite it will fail after deploy - fail validation. * * Otherwise - validation is successful. @@ -76,9 +85,9 @@ public function validate(): Validator\ResultInterface return $this->resultFactory->success(); } - if (!$this->elasticSearch->isInstalled()) { + if (!$this->elasticSearch->isInstalled() && !$this->openSearch->isInstalled()) { return $this->resultFactory->error( - 'ElasticSuite is installed without available ElasticSearch service.', + 'ElasticSuite is installed without available ElasticSearch or OpenSearch service.', '', Error::DEPLOY_ELASTIC_SUITE_WITHOUT_ES ); diff --git a/src/Step/Deploy/InstallUpdate/ConfigUpdate/Amqp.php b/src/Step/Deploy/InstallUpdate/ConfigUpdate/Amqp.php index e6e6f90cbe..30352f92ef 100644 --- a/src/Step/Deploy/InstallUpdate/ConfigUpdate/Amqp.php +++ b/src/Step/Deploy/InstallUpdate/ConfigUpdate/Amqp.php @@ -15,7 +15,7 @@ use Magento\MagentoCloud\Config\Magento\Env\ReaderInterface as ConfigReader; use Magento\MagentoCloud\Config\Magento\Env\WriterInterface as ConfigWriter; use Psr\Log\LoggerInterface; -use Magento\MagentoCloud\Step\Deploy\InstallUpdate\ConfigUpdate\Amqp\Config as AmqpConfig; +use Magento\MagentoCloud\Config\Amqp as AmqpConfig; /** * @inheritdoc @@ -75,7 +75,7 @@ public function execute() { try { $config = $this->configReader->read(); - $amqpConfig = $this->amqpConfig->get(); + $amqpConfig = $this->amqpConfig->getConfig(); } catch (GenericException $e) { throw new StepException($e->getMessage(), $e->getCode(), $e); } diff --git a/src/Step/Deploy/InstallUpdate/Install/Setup/InstallCommandFactory.php b/src/Step/Deploy/InstallUpdate/Install/Setup/InstallCommandFactory.php index 26b20262ed..2f35f6f7ca 100644 --- a/src/Step/Deploy/InstallUpdate/Install/Setup/InstallCommandFactory.php +++ b/src/Step/Deploy/InstallUpdate/Install/Setup/InstallCommandFactory.php @@ -23,6 +23,7 @@ use Magento\MagentoCloud\Util\UrlManager; use Magento\MagentoCloud\Util\PasswordGenerator; use Magento\MagentoCloud\Config\RemoteStorage; +use Magento\MagentoCloud\Config\Amqp as AmqpConfig; /** * Generates command for magento installation @@ -90,6 +91,11 @@ class InstallCommandFactory */ private $remoteStorage; + /** + * @var AmqpConfig + */ + private $amqpConfig; + /** * @param UrlManager $urlManager * @param AdminDataInterface $adminData @@ -102,6 +108,7 @@ class InstallCommandFactory * @param ElasticSearch $elasticSearch * @param OpenSearch $openSearch * @param RemoteStorage $remoteStorage + * @param AmqpConfig $amqpConfig * * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ @@ -116,7 +123,8 @@ public function __construct( MagentoVersion $magentoVersion, ElasticSearch $elasticSearch, OpenSearch $openSearch, - RemoteStorage $remoteStorage + RemoteStorage $remoteStorage, + AmqpConfig $amqpConfig ) { $this->urlManager = $urlManager; $this->adminData = $adminData; @@ -129,6 +137,7 @@ public function __construct( $this->elasticSearch = $elasticSearch; $this->openSearch = $openSearch; $this->remoteStorage = $remoteStorage; + $this->amqpConfig = $amqpConfig; } /** @@ -148,7 +157,8 @@ public function create(): string $this->getBaseOptions(), $this->getAdminOptions(), $this->getEsOptions(), - $this->getRemoteStorageOptions() + $this->getRemoteStorageOptions(), + $this->getAmqpOptions() ); } catch (GenericException $exception) { throw new ConfigException($exception->getMessage(), $exception->getCode(), $exception); @@ -334,4 +344,27 @@ private function getConnectionData(): ConnectionInterface return $this->connectionData; } + + /** + * Returns AMQP optional config options. + * + * @return array + * @throws UndefinedPackageException + */ + private function getAmqpOptions(): array + { + $options = []; + $config = $this->amqpConfig->getConfig(); + $map = ['host', 'port', 'user', 'password', 'virtualhost']; + + if (!empty($config['amqp']['host'])) { + foreach ($map as $option) { + if (!empty($config['amqp'][$option])) { + $options['--amqp-' . $option] = (string)$config['amqp'][$option]; + } + } + } + + return $options; + } } diff --git a/src/Test/Unit/Command/Dev/UpdateComposer/ComposerGeneratorTest.php b/src/Test/Unit/Command/Dev/UpdateComposer/ComposerGeneratorTest.php index 8feeba8775..cceceead29 100644 --- a/src/Test/Unit/Command/Dev/UpdateComposer/ComposerGeneratorTest.php +++ b/src/Test/Unit/Command/Dev/UpdateComposer/ComposerGeneratorTest.php @@ -49,6 +49,20 @@ class ComposerGeneratorTest extends TestCase ], ]; + /** + * @var array + */ + private $installFromGitScript = [ + 'php -r"@mkdir(__DIR__ . \'/app/etc\', 0777, true);"', + 'rm -rf repo1 repo2 repo3 repo4 repo5', + 'git clone -b 1.0.0 --single-branch --depth 1 path_to_repo1 repo1', + 'git clone -b 2.0.0 --single-branch --depth 1 path_to_repo2 repo2', + 'git clone path_to_repo3 "repo3" && git --git-dir="repo3/.git" --work-tree="repo3" checkout ref3', + 'git clone path_to_repo4 "repo4" && git --git-dir="repo4/.git" --work-tree="repo4" checkout ref4', + 'git clone path_to_repo5 "repo5" && git --git-dir="repo5/.git" --work-tree="repo5" checkout ref5', + 'mv repo1/lib/internal/Magento/Framework/Lib1 repo1/lib/internal/Magento/Framework-Lib1', + ]; + /** * @var DirectoryList|MockObject */ @@ -86,16 +100,23 @@ protected function setUp(): void ); } - public function testGetInstallFromGitScripts() + public function testScripts(): void { $expected = include(__DIR__ . '/_files/expected_composer.php'); - $actual = $this->composerGenerator->getInstallFromGitScripts($this->repoOptions); - $this->assertEquals($expected['scripts']['install-from-git'], $actual); + $installFromGitScripts = $this->composerGenerator->getInstallFromGitScripts($this->repoOptions); + $frameworkPreparationScript = $this->composerGenerator->getFrameworkPreparationScript( + array_keys($this->repoOptions) + ); + + $this->assertEquals( + $expected['scripts']['install-from-git'], + array_merge($installFromGitScripts, $frameworkPreparationScript) + ); } public function testGenerate(): void { - $composer = $this->composerGenerator->generate($this->repoOptions); + $composer = $this->composerGenerator->generate($this->repoOptions, $this->installFromGitScript); $expected = include(__DIR__ . '/_files/expected_composer.php'); foreach ($expected as $key => $value) { diff --git a/src/Test/Unit/Command/Dev/UpdateComposer/_files/app/repo1/lib/internal/Magento/Framework/Lib1/composer.json b/src/Test/Unit/Command/Dev/UpdateComposer/_files/app/repo1/lib/internal/Magento/Framework/Lib1/composer.json new file mode 100644 index 0000000000..931af2c241 --- /dev/null +++ b/src/Test/Unit/Command/Dev/UpdateComposer/_files/app/repo1/lib/internal/Magento/Framework/Lib1/composer.json @@ -0,0 +1,4 @@ +{ + "name": "magento/lib1", + "type": "magento2-library" +} diff --git a/src/Test/Unit/Command/Dev/UpdateComposer/_files/expected_composer.php b/src/Test/Unit/Command/Dev/UpdateComposer/_files/expected_composer.php index 2f9399afd1..775165e844 100644 --- a/src/Test/Unit/Command/Dev/UpdateComposer/_files/expected_composer.php +++ b/src/Test/Unit/Command/Dev/UpdateComposer/_files/expected_composer.php @@ -40,6 +40,13 @@ 'symlink' => false, ], ], + 'magento/lib1' => [ + 'type' => 'path', + 'url' => 'repo1/lib/internal/Magento/Framework/Lib1', + 'options' => [ + 'symlink' => false, + ], + ], ], 'require' => [ 'package' => '*', @@ -47,6 +54,7 @@ 'vendor/theme1' => '*@dev', 'vendor/module-module1' => '*@dev', 'vendor/module-module5' => '*@dev', + 'magento/lib1' => '*@dev', ], 'scripts' =>[ 'install-from-git' => [ @@ -57,6 +65,7 @@ 'git clone path_to_repo3 "repo3" && git --git-dir="repo3/.git" --work-tree="repo3" checkout ref3', 'git clone path_to_repo4 "repo4" && git --git-dir="repo4/.git" --work-tree="repo4" checkout ref4', 'git clone path_to_repo5 "repo5" && git --git-dir="repo5/.git" --work-tree="repo5" checkout ref5', + 'mv repo1/lib/internal/Magento/Framework/Lib1 repo1/lib/internal/Magento/Framework-Lib1', ], 'pre-install-cmd' => [ '@install-from-git', @@ -65,7 +74,7 @@ '@install-from-git', ], 'prepare-packages' => [ - 'rsync -azhm --stats --exclude=\'lib/internal/Vendor/Library1\' --exclude=\'dev/tests\' --exclude=\'.git\' --exclude=\'composer.json\' --exclude=\'composer.lock\' ./repo1/ ./', + 'rsync -azhm --stats --exclude=\'lib/internal/Magento/Framework/Lib1\' --exclude=\'lib/internal/Vendor/Library1\' --exclude=\'dev/tests\' --exclude=\'.git\' --exclude=\'composer.json\' --exclude=\'composer.lock\' ./repo1/ ./', 'rsync -azhm --stats --exclude=\'app/code/Vendor/Module1\' --exclude=\'dev/tests\' --exclude=\'.git\' --exclude=\'composer.json\' --exclude=\'composer.lock\' ./repo2/ ./', 'rsync -azhm --stats --exclude=\'app/design/Vendor/Theme1\' --exclude=\'dev/tests\' --exclude=\'.git\' --exclude=\'composer.json\' --exclude=\'composer.lock\' ./repo3/ ./', 'rsync -azhm --stats --exclude=\'dev/tests\' --exclude=\'.git\' --exclude=\'composer.json\' --exclude=\'composer.lock\' ./repo4/ ./', diff --git a/src/Test/Unit/Command/Dev/UpdateComposerTest.php b/src/Test/Unit/Command/Dev/UpdateComposerTest.php index 35c668d434..80c17976f3 100644 --- a/src/Test/Unit/Command/Dev/UpdateComposerTest.php +++ b/src/Test/Unit/Command/Dev/UpdateComposerTest.php @@ -105,6 +105,13 @@ public function testExecute(): void 'script2', 'script3', ]); + $this->composerGeneratorMock->expects($this->once()) + ->method('getFrameworkPreparationScript') + ->with(array_keys($gitOptions['repositories'])) + ->willReturn([ + 'script4', + 'script5', + ]); $this->composerGeneratorMock->expects($this->once()) ->method('generate') ->with($gitOptions['repositories']) @@ -121,11 +128,13 @@ public function testExecute(): void ], ], ]); - $this->shellMock->expects($this->exactly(3)) + $this->shellMock->expects($this->exactly(5)) ->method('execute') ->withConsecutive( ['script2'], ['script3'], + ['script4'], + ['script5'], ['composer update --ansi --no-interaction'] ); $this->fileListMock->expects($this->once()) diff --git a/src/Test/Unit/Step/Deploy/InstallUpdate/ConfigUpdate/Amqp/ConfigTest.php b/src/Test/Unit/Config/AmqpTest.php similarity index 97% rename from src/Test/Unit/Step/Deploy/InstallUpdate/ConfigUpdate/Amqp/ConfigTest.php rename to src/Test/Unit/Config/AmqpTest.php index e2391c38b3..6be64dcda9 100644 --- a/src/Test/Unit/Step/Deploy/InstallUpdate/ConfigUpdate/Amqp/ConfigTest.php +++ b/src/Test/Unit/Config/AmqpTest.php @@ -5,13 +5,13 @@ */ declare(strict_types=1); -namespace Magento\MagentoCloud\Test\Unit\Step\Deploy\InstallUpdate\ConfigUpdate\Amqp; +namespace Magento\MagentoCloud\Test\Unit\Config; use Magento\MagentoCloud\Config\ConfigMerger; use Magento\MagentoCloud\Package\MagentoVersion; use Magento\MagentoCloud\Config\Stage\DeployInterface; use Magento\MagentoCloud\Package\UndefinedPackageException; -use Magento\MagentoCloud\Step\Deploy\InstallUpdate\ConfigUpdate\Amqp\Config; +use Magento\MagentoCloud\Config\Amqp; use Magento\MagentoCloud\Service\RabbitMq; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -19,10 +19,10 @@ /** * @inheritdoc */ -class ConfigTest extends TestCase +class AmqpTest extends TestCase { /** - * @var Config + * @var Amqp */ protected $config; @@ -50,7 +50,7 @@ protected function setUp(): void $this->stageConfigMock = $this->getMockForAbstractClass(DeployInterface::class); $this->magentoVersionMock = $this->createMock(MagentoVersion::class); - $this->config = new Config( + $this->config = new Amqp( $this->rabbitMq, $this->stageConfigMock, new ConfigMerger(), @@ -67,9 +67,9 @@ protected function setUp(): void * @param array $expectedQueueConfig * @throws UndefinedPackageException * - * @dataProvider getDataProvider + * @dataProvider getConfigDataProvider */ - public function testGet( + public function testGetConfig( array $customQueueConfig, array $amqpServiceConfig, bool $isGreaterOrEqualReturns, @@ -92,7 +92,7 @@ public function testGet( ->with('2.2') ->willReturn($isGreaterOrEqualReturns); - $this->assertEquals($expectedQueueConfig, $this->config->get()); + $this->assertEquals($expectedQueueConfig, $this->config->getConfig()); } /** @@ -100,7 +100,7 @@ public function testGet( * * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - public function getDataProvider(): array + public function getConfigDataProvider(): array { return [ 'queue configuration does not exist' => [ diff --git a/src/Test/Unit/Config/Validator/Deploy/ElasticSuiteIntegrityTest.php b/src/Test/Unit/Config/Validator/Deploy/ElasticSuiteIntegrityTest.php index 1048928fc5..61b24d653f 100644 --- a/src/Test/Unit/Config/Validator/Deploy/ElasticSuiteIntegrityTest.php +++ b/src/Test/Unit/Config/Validator/Deploy/ElasticSuiteIntegrityTest.php @@ -15,6 +15,7 @@ use Magento\MagentoCloud\Config\Validator\Result\Success; use Magento\MagentoCloud\Config\Validator\ResultFactory; use Magento\MagentoCloud\Service\ElasticSearch; +use Magento\MagentoCloud\Service\OpenSearch; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -38,6 +39,11 @@ class ElasticSuiteIntegrityTest extends TestCase */ private $elasticSearchMock; + /** + * @var OpenSearch|MockObject + */ + private $openSearchMock; + /** * @var ResultFactory|MockObject */ @@ -55,12 +61,14 @@ protected function setUp(): void { $this->elasticSuiteMock = $this->createMock(ElasticSuite::class); $this->elasticSearchMock = $this->createMock(ElasticSearch::class); + $this->openSearchMock = $this->createMock(OpenSearch::class); $this->resultFactoryMock = $this->createMock(ResultFactory::class); $this->stageConfigMock = $this->createMock(DeployInterface::class); $this->validator = new ElasticSuiteIntegrity( $this->elasticSuiteMock, $this->elasticSearchMock, + $this->openSearchMock, $this->resultFactoryMock, $this->stageConfigMock ); @@ -71,6 +79,60 @@ public function testValidate() $this->elasticSuiteMock->expects($this->once()) ->method('isInstalled') ->willReturn(false); + $this->elasticSearchMock->expects($this->never()) + ->method('isInstalled'); + $this->openSearchMock->expects($this->never()) + ->method('isInstalled'); + $this->resultFactoryMock->expects($this->once()) + ->method('success') + ->willReturn(new Success()); + + $this->assertInstanceOf(Success::class, $this->validator->validate()); + } + + public function testValidateEsOs() + { + $this->elasticSuiteMock->expects($this->once()) + ->method('isInstalled') + ->willReturn(true); + $this->openSearchMock->expects($this->once()) + ->method('isInstalled') + ->willReturn(true); + $this->resultFactoryMock->expects($this->once()) + ->method('success') + ->willReturn(new Success()); + + $this->assertInstanceOf(Success::class, $this->validator->validate()); + } + + public function testValidateEs() + { + $this->elasticSuiteMock->expects($this->once()) + ->method('isInstalled') + ->willReturn(true); + $this->elasticSearchMock->expects($this->once()) + ->method('isInstalled') + ->willReturn(true); + $this->openSearchMock->expects($this->never()) + ->method('isInstalled'); + $this->resultFactoryMock->expects($this->once()) + ->method('success') + ->willReturn(new Success()); + + $this->assertInstanceOf(Success::class, $this->validator->validate()); + } + + public function testValidateOs() + { + $this->elasticSuiteMock->expects($this->once()) + ->method('isInstalled') + ->willReturn(true); + $this->elasticSearchMock->expects($this->once()) + ->method('isInstalled') + ->willReturn(false); + $this->openSearchMock->expects($this->once()) + ->method('isInstalled') + ->willReturn(true); $this->resultFactoryMock->expects($this->once()) ->method('success') ->willReturn(new Success()); @@ -78,7 +140,7 @@ public function testValidate() $this->assertInstanceOf(Success::class, $this->validator->validate()); } - public function testValidateNoESInstalled() + public function testValidateNoESandOSInstalled() { $this->elasticSuiteMock->expects($this->once()) ->method('isInstalled') @@ -86,10 +148,13 @@ public function testValidateNoESInstalled() $this->elasticSearchMock->expects($this->once()) ->method('isInstalled') ->willReturn(false); + $this->openSearchMock->expects($this->once()) + ->method('isInstalled') + ->willReturn(false); $this->resultFactoryMock->expects($this->once()) ->method('error') ->with( - 'ElasticSuite is installed without available ElasticSearch service.', + 'ElasticSuite is installed without available ElasticSearch or OpenSearch service.', '', AppError::DEPLOY_ELASTIC_SUITE_WITHOUT_ES ) @@ -106,6 +171,8 @@ public function testValidateSearchEngineIsMysql() $this->elasticSearchMock->expects($this->once()) ->method('isInstalled') ->willReturn(true); + $this->openSearchMock->expects($this->never()) + ->method('isInstalled'); $this->stageConfigMock->expects($this->once()) ->method('get') ->with(DeployInterface::VAR_SEARCH_CONFIGURATION) @@ -130,6 +197,8 @@ public function testValidateNoErrors() $this->elasticSearchMock->expects($this->once()) ->method('isInstalled') ->willReturn(true); + $this->openSearchMock->expects($this->never()) + ->method('isInstalled'); $this->stageConfigMock->expects($this->once()) ->method('get') ->with(DeployInterface::VAR_SEARCH_CONFIGURATION) diff --git a/src/Test/Unit/Step/Deploy/InstallUpdate/ConfigUpdate/AmqpTest.php b/src/Test/Unit/Step/Deploy/InstallUpdate/ConfigUpdate/AmqpTest.php index 1c29ff6f2e..f4a999b5f8 100644 --- a/src/Test/Unit/Step/Deploy/InstallUpdate/ConfigUpdate/AmqpTest.php +++ b/src/Test/Unit/Step/Deploy/InstallUpdate/ConfigUpdate/AmqpTest.php @@ -17,7 +17,7 @@ use Magento\MagentoCloud\Config\Magento\Env\WriterInterface as ConfigWriter; use Psr\Log\LoggerInterface; use Magento\MagentoCloud\Step\Deploy\InstallUpdate\ConfigUpdate\Amqp; -use Magento\MagentoCloud\Step\Deploy\InstallUpdate\ConfigUpdate\Amqp\Config as AmqpConfig; +use Magento\MagentoCloud\Config\Amqp as AmqpConfig; /** * @inheritdoc @@ -78,7 +78,7 @@ public function testExecuteWithoutAmqp(): void ->method('read') ->willReturn($config); $this->amqpConfigMock->expects($this->once()) - ->method('get') + ->method('getConfig') ->willReturn([]); $this->loggerMock->expects($this->never()) ->method('info'); @@ -113,7 +113,7 @@ public function testExecuteAddUpdate(): void ->method('read') ->willReturn($config); $this->amqpConfigMock->expects($this->once()) - ->method('get') + ->method('getConfig') ->willReturn($amqpConfig); $this->loggerMock->expects($this->once()) ->method('info') diff --git a/src/Test/Unit/Step/Deploy/InstallUpdate/Install/Setup/InstallCommandFactoryTest.php b/src/Test/Unit/Step/Deploy/InstallUpdate/Install/Setup/InstallCommandFactoryTest.php index ac4452dbef..b1c4cf9d3e 100644 --- a/src/Test/Unit/Step/Deploy/InstallUpdate/Install/Setup/InstallCommandFactoryTest.php +++ b/src/Test/Unit/Step/Deploy/InstallUpdate/Install/Setup/InstallCommandFactoryTest.php @@ -18,6 +18,7 @@ use Magento\MagentoCloud\Package\MagentoVersion; use Magento\MagentoCloud\Service\ElasticSearch; use Magento\MagentoCloud\Service\OpenSearch; +use Magento\MagentoCloud\Config\Amqp as AmqpConfig; use Magento\MagentoCloud\Step\Deploy\InstallUpdate\Install\Setup\InstallCommandFactory; use Magento\MagentoCloud\Util\PasswordGenerator; use Magento\MagentoCloud\Util\UrlManager; @@ -91,6 +92,11 @@ class InstallCommandFactoryTest extends TestCase */ private $remoteStorageMock; + /** + * @var AmqpConfig|MockObject + */ + private $amqpConfigMock; + /** * @inheritdoc */ @@ -112,6 +118,7 @@ protected function setUp(): void $this->elasticSearchMock = $this->createMock(ElasticSearch::class); $this->openSearchMock = $this->createMock(OpenSearch::class); $this->remoteStorageMock = $this->createMock(RemoteStorage::class); + $this->amqpConfigMock = $this->createMock(AmqpConfig::class); $this->installCommandFactory = new InstallCommandFactory( $this->urlManagerMock, @@ -124,7 +131,8 @@ protected function setUp(): void $this->magentoVersionMock, $this->elasticSearchMock, $this->openSearchMock, - $this->remoteStorageMock + $this->remoteStorageMock, + $this->amqpConfigMock ); } @@ -539,4 +547,124 @@ public function testExecuteWithOSauthOptions(): void self::assertStringContainsString("--elasticsearch-password='secret'", $command); self::assertStringContainsString("--elasticsearch-index-prefix='test'", $command); } + + /** + * @param array $amqpConfig + * @param string $expectedResult + * @return void + * @throws ConfigException + * + * @dataProvider executeWithAmqpConfigOptionsDataProvider + */ + public function testExecuteWithAmqpConfigOptions( + array $amqpConfig, + string $expectedResult + ): void { + $this->mockBaseConfig('', '', '', '', '', ''); + $this->magentoVersionMock->method('isGreaterOrEqual') + ->willReturnMap([ + ['2.4.0', false], + ['2.4.2', true] + ]); + $this->amqpConfigMock->method('getConfig') + ->willReturn($amqpConfig); + + self::assertStringContainsString($expectedResult, $this->installCommandFactory->create()); + } + + /** + * @return array + */ + public function executeWithAmqpConfigOptionsDataProvider(): array + { + return [ + 'with all parameters and other config' => [ + 'amqpConfig' => [ + 'amqp' => [ + 'host' => 'some_host', + 'port' => 'some_port', + 'user' => 'some_user', + 'password' => 'some_password', + 'virtualhost' => 'some_host', + 'some_config' => 'some_config' + ], + 'some_config' => 'some_value', + ], + 'expectedResult' => "--amqp-host='some_host' --amqp-port='some_port' --amqp-user='some_user'" + . " --amqp-password='some_password' --amqp-virtualhost='some_host'", + ], + 'only host' => [ + 'amqpConfig' => [ + 'amqp' => [ + 'host' => 'some_host', + 'user' => 'some_user', + 'password' => 'some_password', + 'virtualhost' => 'some_host', + 'some_config' => 'some_config' + ], + 'some_config' => 'some_value', + ], + 'expectedResult' => "--amqp-host='some_host'", + ], + ]; + } + + /** + * @param array $amqpConfig + * @return void + * @throws ConfigException + * + * @dataProvider executeWithAmqpConfigOptionsWithoutHostDataProvider + */ + public function testExecuteWithAmqpConfigOptionsWithoutHost(array $amqpConfig): void + { + $this->mockBaseConfig('', '', '', '', '', ''); + $this->magentoVersionMock->method('isGreaterOrEqual') + ->willReturnMap([ + ['2.4.0', false], + ['2.4.2', true] + ]); + $this->amqpConfigMock->method('getConfig') + ->willReturn($amqpConfig); + + $command = $this->installCommandFactory->create(); + self::assertStringNotContainsString('--amqp-host', $command); + self::assertStringNotContainsString('--amqp-port', $command); + self::assertStringNotContainsString('--amqp-user', $command); + self::assertStringNotContainsString('--amqp-password', $command); + self::assertStringNotContainsString('--amqp-virtualhost', $command); + } + + /** + * @return array + */ + public function executeWithAmqpConfigOptionsWithoutHostDataProvider(): array + { + return [ + 'host is not set' => [ + 'amqpConfig' => [ + 'amqp' => [ + 'port' => 'some_port', + 'user' => 'some_user', + 'password' => 'some_password', + 'virtualhost' => 'some_host', + 'some_config' => 'some_config' + ], + 'some_config' => 'some_value', + ], + ], + 'host is empty' => [ + 'amqpConfig' => [ + 'amqp' => [ + 'host' => '', + 'user' => 'some_user', + 'password' => 'some_password', + 'virtualhost' => 'some_host', + 'some_config' => 'some_config' + ], + 'some_config' => 'some_value', + ], + ], + ]; + } }